The "low severity" finding

The app had a classic open redirect: /go?next= would bounce the browser to any URL with no allow-list. Reported alone, this gets triaged as informational and closed. The interesting part is never the primitive — it's what you can wire it to.

https://app.target.com/go?next=https://attacker.example/

The leaky OAuth flow

The login flow used OAuth with a redirect_uri that the authorization server validated only by prefix. The access token came back in the URL fragment. Two weak checks, individually defensible, catastrophic together.

The chain

  1. Start an OAuth flow with redirect_uri pointing at the trusted /go endpoint — it passes the prefix check.
  2. The provider redirects back to /go?next= with the token in the fragment.
  3. The open redirect forwards the browser — fragment and all — to the attacker's origin.
  4. Attacker's page reads location.hash, lifts the token, and replays it for full session access.
Two "won't fix" findings can multiply into a critical. Bug bounty is about the graph, not the node.

The fix

Kill the open redirect with a strict allow-list of internal paths. Enforce exact redirect_uri matching on the authorization server, and deliver tokens via the authorization-code flow with PKCE instead of returning them in a fragment. Defense in depth means any one of these breaks the chain.

Takeaway

Don't dismiss low-severity primitives. Catalog them, then go looking for the second bug that turns the pair into something that pays.