OAuth Token Leak via Referer: Still a Real Bug Class
OAuth tokens in query strings are old news. People still ship them. The failure mode that keeps paying is quieter: after the redirect lands, the victim's browser loads a third-party script, image, or analytics beacon and attaches a Referer that still contains access_token, id_token, or code.
You are not attacking the IdP crypto. You are watching how the client app handles the callback URL.
Reproduce with two tabs and a beacon
Complete a normal login with an account you own. On the redirect URI page—often /oauth/callback?code=... or a fragment-based implicit leftover—view the HTML. Note every cross-origin resource: CDNs, payment widgets, support chat, A/B pixels, font hosts.
Open DevTools. Watch the request to that third party. If Referer includes the query string with a code or token, you have leakage. Severity scales with what leaked:
- Authorization code: often needs
client_secretor PKCE verifier; still serious if the app is public + PKCE-broken or the code is usable from your client. - Access token in query: usually direct API access as the victim.
- Refresh token: longer-lived disaster.
Modern browsers may truncate Referer based on referrer policy. Check the page's Referrer-Policy and meta tags. no-referrer or strict-origin-when-cross-origin can save a mediocre app. unsafe-url or a missing policy on older WebViews can sink a good one.
Fragments are not a free pass
Implicit flow put tokens in the hash so they would stay out of Referer. That helps for classic third-party loads, but in-app browsers, intermediate redirects that convert fragments to queries, and server-side logging of full URLs still bite. Also test mobile webviews used by the official app if they are in scope.
Another angle: the app accepts the token on the query string, then redirects to / without stripping sensitive params first. The intermediate 302's Location might be clean while analytics on the callback page already fired.
Post-login marketing tags are frequent offenders. The security team ships a careful callback; growth adds a pixel a year later. Diff the callback HTML across environments if you can. Staging sometimes loads extra debug beacons that production also inherits.
Write the report for a tired reviewer
Include the callback URL pattern, the third-party host that received Referer, a redacted header capture, and whether you could replay the secret from a different IP. Recommend moving to code flow with PKCE, delivering tokens in POST body or header-only storage, setting Referrer-Policy: no-referrer on callback routes, and scrubbing sensitive query params before any outbound resource loads.
If the only leak is to a first-party subdomain that already had the session, downgrade your tone. Cross-origin analytics domains are the story.
One rhetorical question I ask before filing: would this leak still exist if the callback rendered zero third-party tags? If yes, you also have a token-in-URL design issue worth stating separately. If no, focus the report on the beacon and the missing referrer policy—those are the patches that ship fastest.
Mobile deep links deserve a pass too. If the callback opens the native app via a custom scheme and the web fallback still renders tags first, the race can leak the code before the app claims the URL. Capture that sequence with a slow proxy if the flash is easy to miss.