Case Study 1: OAuth Redirect Vulnerabilities and JWT "none" Algorithm Attacks in Bug Bounty Reports
Overview
This case study examines two classes of authentication vulnerabilities that have generated some of the highest payouts in bug bounty history: OAuth redirect URI manipulation and JWT algorithm confusion attacks. Both vulnerability classes exploit fundamental trust assumptions in authentication protocols — and both continue to appear in production applications despite being well-documented for over a decade.
Part I: OAuth Redirect URI Exploitation
Background
OAuth 2.0's security model depends critically on the integrity of the redirect URI. After a user authenticates with an identity provider, the authorization code (or access token, in the deprecated implicit flow) is delivered to the URI specified in the redirect_uri parameter. If an attacker can manipulate this URI, they can redirect the authorization code to an endpoint they control, effectively stealing the user's authentication.
Between 2019 and 2024, OAuth redirect URI vulnerabilities accounted for over $2 million in disclosed bug bounty payouts across programs at Facebook, Google, Microsoft, Slack, and dozens of other major platforms.
The Vulnerability Pattern
In a properly configured OAuth implementation, the authorization server maintains a strict allowlist of registered redirect URIs for each client. When the client initiates an authorization request, the server verifies that the provided redirect_uri exactly matches one of the registered values.
However, implementation weaknesses frequently undermine this verification:
Partial Path Matching. Some authorization servers validate only the domain portion of the redirect URI, allowing arbitrary path components:
Registered: https://app.example.com/callback
Accepted: https://app.example.com/callback/../../../attacker-controlled-path
Accepted: https://app.example.com/redirect?url=https://attacker.com
Subdomain Matching. Wildcard subdomain registrations can be exploited if any subdomain is vulnerable to XSS or has an open redirect:
Registered: https://*.example.com/callback
Exploited: https://xss-vulnerable.example.com/callback
The attacker finds an XSS vulnerability on any subdomain, then uses it to exfiltrate the authorization code delivered to that subdomain's callback URL.
Notable Bug Bounty Reports
Facebook OAuth Account Takeover (2020). Security researcher Amol Baikar discovered that Facebook's OAuth implementation for "Login with Facebook" allowed redirect URI manipulation through a chain of vulnerabilities. The attack involved:
- A registered redirect URI allowed paths under a specific domain
- That domain had an open redirect vulnerability
- By chaining the open redirect, the authorization code could be redirected to an attacker-controlled domain
- With the authorization code, the attacker could obtain an access token and take over the victim's account on the third-party application
The payout was $55,000, reflecting the critical impact — complete account takeover of any user who clicked a crafted link.
Microsoft OAuth Redirect Chain (2021). A researcher discovered that Microsoft's Azure AD OAuth implementation accepted redirect URIs that included certain URL-encoded characters that were decoded differently by the authorization server and the application server. This parsing differential allowed the authorization code to be redirected:
Registered: https://app.contoso.com/auth/callback
Exploited: https://app.contoso.com/auth/callback%23@attacker.com
The authorization server treated the %23 (#) as part of the path (validating against the registered URI), while the browser interpreted it as a fragment delimiter, sending the request to attacker.com.
Slack Workspace Takeover (2019). A critical OAuth redirect vulnerability in Slack allowed an attacker to steal OAuth authorization codes by exploiting a lenient redirect URI validation. The authorization server accepted URIs with additional path segments beyond the registered callback:
Registered: https://slack.com/oauth/callback
Exploited: https://slack.com/oauth/callback/../../redirect?url=https://attacker.com
This path traversal bypassed the validation check, and the subsequent redirect sent the authorization code to the attacker. With the code, the attacker could obtain tokens granting full access to the victim's Slack workspace.
Defense Analysis
Organizations that avoided these vulnerabilities implemented several key controls:
- Exact String Matching: The redirect URI must exactly match the registered value — no wildcards, no pattern matching, no path flexibility
- No Open Redirects: The redirect domain must not contain any open redirect endpoints that could chain into token theft
- PKCE Enforcement: Proof Key for Code Exchange binds the authorization code to the client that initiated the flow, preventing stolen codes from being exchanged by attackers
- State Parameter Validation: Cryptographically random state values tied to the user's session prevent CSRF attacks on the OAuth flow
Part II: JWT "none" Algorithm Attacks
Background
The JWT specification (RFC 7519) defines an "Unsecured JWT" where the alg header is set to "none" and the signature section is empty. This was intended for scenarios where token integrity is guaranteed by other means (such as transport security). In practice, many JWT libraries defaulted to accepting unsigned tokens if the header indicated "none", creating a trivially exploitable vulnerability.
The Vulnerability Mechanism
When a JWT library processes a token, it typically reads the alg header to determine the verification algorithm. Vulnerable implementations follow this logic:
# Vulnerable JWT verification pseudocode
def verify_jwt(token, public_key):
header = decode_header(token)
if header['alg'] == 'none':
return True # No verification needed!
elif header['alg'] == 'HS256':
return verify_hmac(token, secret_key)
elif header['alg'] == 'RS256':
return verify_rsa(token, public_key)
The attacker simply modifies the JWT:
- Changes "alg": "RS256" to "alg": "none"
- Modifies payload claims (e.g., elevating "role": "user" to "role": "admin")
- Removes the signature (but keeps the trailing dot separator)
Real-World Impact
Auth0 Critical Advisory (2015). Auth0, one of the largest identity-as-a-service providers, disclosed that several of their JWT libraries were vulnerable to the none algorithm attack. Any application using these libraries could be completely compromised by an attacker sending unsigned JWTs with escalated privileges. The disclosure affected libraries in multiple languages: node-jsonwebtoken, pyjwt, namshi/jose, php-jwt, and jsjws.
The impact was severe: every application using these libraries for authentication was vulnerable to complete authentication bypass. Auth0 issued emergency patches and coordinated disclosure across the affected ecosystem.
HackerOne Bug Bounties (2019-2023). Multiple high-severity bug bounty reports across various programs revealed JWT none algorithm vulnerabilities in production APIs:
- A financial services API accepted unsigned JWTs, allowing an attacker to forge tokens with any user identity. The payout was $25,000.
- A healthcare platform's patient portal accepted
"alg": "none"tokens, potentially exposing Protected Health Information. The finding was rated critical. - An e-commerce platform's merchant API accepted unsigned tokens, allowing privilege escalation to administrator access. The attacker demonstrated the ability to modify product prices, access customer data, and process fraudulent refunds.
Algorithm Confusion Variant
Related to the none algorithm attack is the algorithm confusion (key confusion) attack, which was also widely reported in bounty programs. If an application uses RS256 (asymmetric) but the JWT library accepts HS256 (symmetric) when instructed by the token header, the attacker can:
- Obtain the server's RSA public key (intentionally public)
- Forge a token signed with HS256 using the public key as the HMAC secret
- The server, seeing HS256 in the header, uses its "key" (the public key) for HMAC verification
- The signature validates because the attacker used the same key
A 2023 bounty report against a major SaaS platform demonstrated this attack against their API gateway, earning $30,000. The API gateway's JWT validation library accepted the algorithm specified in the token header without cross-referencing the expected algorithm configured for the application.
The Fix
Secure JWT verification requires:
# Secure JWT verification pseudocode
def verify_jwt(token, public_key, expected_algorithm='RS256'):
header = decode_header(token)
# CRITICAL: Verify against expected algorithm, not header claim
if header['alg'] != expected_algorithm:
raise SecurityError("Unexpected algorithm")
if expected_algorithm == 'none':
raise SecurityError("Unsigned tokens not accepted")
return verify_signature(token, public_key, expected_algorithm)
Lessons for Ethical Hackers
Testing Methodology
-
OAuth Testing Checklist: - Map all redirect URIs registered for the application - Test path manipulation, subdomain variations, and URL encoding tricks - Look for open redirect vulnerabilities on the redirect domain - Verify PKCE implementation for public clients - Test state parameter presence and validation
-
JWT Testing Checklist: - Decode all JWTs and examine the
algheader - Test"alg": "none"with an empty signature - If RS256, test algorithm confusion to HS256 - Testjkuandx5uheader injection - Testkidparameter for injection - Verify claim validation (exp, nbf, iss, aud)
Impact Documentation
When reporting these vulnerabilities, clearly articulate the impact: - OAuth redirect: "An attacker can steal authorization codes by redirecting them to an attacker-controlled domain, resulting in complete account takeover for any user who clicks a crafted link." - JWT none algorithm: "An attacker can forge authentication tokens with arbitrary claims, including administrative privileges, without knowledge of any cryptographic keys."
Both vulnerability classes consistently receive Critical or High severity ratings in bug bounty programs because they result in authentication bypass — the most impactful category of web application vulnerability.
Discussion Questions
-
Why do OAuth redirect URI vulnerabilities persist despite being well-documented? What organizational and technical factors contribute to their continued appearance?
-
The JWT
nonealgorithm was included in the specification for legitimate use cases. Evaluate the trade-off between specification flexibility and security. Should thenonealgorithm have been included in the RFC? -
How does the PKCE extension mitigate OAuth redirect URI attacks? In what scenarios does PKCE fail to prevent exploitation?
-
Compare the impact of an OAuth redirect vulnerability versus a JWT
nonealgorithm vulnerability. Which is more severe in practice, and why? -
As a penetration tester, how would you prioritize testing for these vulnerability classes within a time-constrained engagement? What indicators would suggest higher likelihood of finding them?