OAuth Account Takeover in SaaS: 5 Patterns Dominating 2026
5 OAuth account takeover patterns behind real B2B SaaS bugs: state confusion, redirect URI fuzzing, code injection, PKCE bypass and implicit/hybrid flow.
Security researcher and founder of No Vuln

Account takeover (ATO) via OAuth is one of the most lucrative bug classes in international bug bounty programs — and one of the least covered by traditional pentests in the Brazilian market. Scanners don't detect it. The OWASP checklist doesn't cover it well. And the vector is hard because it depends on understanding the protocol, not just firing payloads at input fields.
This article breaks down the 5 OAuth ATO paths that show up most often in real programs in 2025–2026, with real (anonymized) examples and what defensive teams need to do to block them.
OAuth in one sentence
OAuth 2.0 is an authorization protocol that lets one application (the client) access a user's resources in another application (the provider) without the user having to share their credentials with the first one. It's like handing your car key to the hotel valet: you grant limited access without giving away your house keys.
OIDC (OpenID Connect) is a layer on top of OAuth 2.0 that adds authentication (knowing who the user is), not just authorization.
Why OAuth is a frequent ATO vector
The OAuth 2.0 flow diagram has at least 5 actors and 8 message exchanges. The specification runs 80+ pages. In practice:
- Developers skim the docs and get ~70% of the implementation right
- The 30% they get wrong lives in details that look optional
- Those details are where the exploit lives
Let's get to the 5 paths.
1. State confusion — the classic that still works
The state parameter ties the initial authorization request to the response. With no state, or a predictable one, the attacker can forge the response for the victim.
Typical scenario:
- The attacker clicks “Connect with Google” on their own account
- They capture the callback URL generated by the provider (with the
code) - They send that URL to the victim as a phishing link
- The victim clicks while logged in to the app — the callback is processed against the victim's session
- The attacker's account gets linked to the victim's user — or vice versa
Recurring pentest finding: B2B SaaS products where the “connect with Google” flow doesn't validate state properly — any user can be forced to link the attacker's account through a link shared on Slack or by email. This vector shows up frequently in public bug bounty programs, with payouts between US$ 2,000 and US$ 15,000.
How to block it: a cryptographically random state (at least 128 bits), bound to the session and validated in the callback before the code is processed.
2. Redirect URI fuzzing — modern and still underestimated
The OAuth provider validates the redirect_uri against a pre-approved list. If that validation is weak, the attacker can redirect to their own domain with the victim's code.
Common bypasses:
- Prefix validation: you registered
https://app.com, the attacker useshttps://app.com.evil.com - Suffix validation: you registered
app.com/callback, the attacker useshttps://evil.com/callback?x=app.com/callback - Validation that accepts query parameters:
https://app.com/callback?next=https://evil.com(internal open redirect) - Path traversal: you registered
https://app.com/oauth/callback, the attacker useshttps://app.com/oauth/callback/../../external?url=evil.com - Subdomain takeover: you registered a subdomain whose CNAME points to an abandoned SaaS
How to block it: exact-match validation (full string match). No wildcards, no prefixes, no suffixes. A closed, pre-registered list of redirect_uris.
3. Code injection / code leakage
The code returned by the provider should be single-use and short-lived. But there are patterns where it leaks:
- The code appears in the
Refererheader if the callback page loads external images - The code gets logged on the server side (reverse proxy, CDN, APM)
- The code is stored in
localStorage, where XSS can reach it - The code is sent via GET to an endpoint with permissive CORS
Recurring pentest finding: applications that log full OAuth callbacks in observability tools (Datadog, Splunk, Sentry, New Relic) — any engineer with access to those logs can collect users' authorization codes and, without mandatory PKCE, exchange them for valid access tokens. It's a classic finding in assessments of production fintechs and B2B SaaS.
How to block it:
- Mandatory PKCE (even for confidential clients)
- Short code TTL (5 minutes max, 30 seconds ideally)
- Log sanitization (filter out the
codefield) - A
Referrer-Policy: no-referrerheader on the callback page
4. PKCE bypass
PKCE (Proof Key for Code Exchange) was introduced to protect public clients (mobile, SPAs) from code interception. In 2026 it's required for confidential clients too — in theory.
Common bypasses:
- The server accepts requests without a
code_verifier(optional PKCE) - The server accepts
code_challenge_method=plain(useless PKCE) - The server accepts a
code_verifierwhose hash doesn't match (missing validation) - The server allows a
code_challengeto be reused across requests
How to block it: explicitly reject all 4 conditions above. PKCE with S256, mandatory and validated.
5. Implicit and hybrid flows still running in production
OAuth 2.1 (still a draft, on track to become an RFC) deprecates the implicit flow and hybrid flows that put tokens in the URL. They're fragile: the token shows up in the URL, in browser history, in logs, in the Referer. Yet in 2026 they're still in production.
Scenario: a legacy app using the implicit flow. The victim gets redirected to app.com/#access_token=abc123. The attacker can read it:
- Through XSS injected into
app.com - Through a malicious browser extension installed in the victim's profile
- By abusing
navigator.share - Through subframe hijacking if the page can be embedded
How to block it: migrate to the Authorization Code Flow + PKCE. Don't use implicit. Don't use hybrid with tokens in the URL. If a legacy client needs a gradual migration, isolate the implicit flow on a separate domain and monitor it aggressively.
Bonus: confused deputy when you're the OAuth client
If your application consumes third-party OAuth (sign in with Google, Microsoft, Facebook), you're an OAuth client. You need to:
- Verify the
id_token(nonce, audience, issuer) - Never trust an unverified email coming from the provider
- Link the provider account to the internal account by
sub(a stable ID), not by email - Handle “email already exists” carefully: otherwise an attacker can take over an existing account just by changing their email on Google
That last vector — account confusion via an unverified email — is currently one of the most lucrative ATO exploits. An attacker with their own Google Workspace sets up an alias matching the target's email, connects to the app and gets linked to the victim's account.
How a serious pentest attacks all of this
No Vuln uses the OAuth State Fuzzer (a proprietary tool) to automate:
- State guessing and replay
- Redirect URI fuzzing (50+ bypass payloads)
- PKCE downgrade attacks
- Code reuse attempts
- JKU/X5U injection in ID tokens
Then, by hand, a researcher validates each path with a reproducible PoC, aligns severity with business impact (ATO on an enterprise admin account = P0; on a regular user account = P1 or P2 depending on the data) and writes a specific remediation recommendation.
Conclusion
OAuth ATO in 2026 comes down to the details. Scanners won't catch it. Checklist reviews won't catch it. It takes a researcher who understands the protocol and has the tooling to fuzz the 50+ bypass paths.
If your application uses OAuth (and in 2026 almost every one does), a superficial pentest won't protect you. Look for a firm that explicitly covers the 5 vectors in this article before the engagement starts.
Next step
Want to apply this to your system?
No Vuln runs in-depth penetration tests with the same methodology described in this article. Request a proposal: mutual NDA within 24h, scope defined on a technical call.