OAuth PKCE Bypass on Public Clients: When code_verifier Is Optional
PKCE exists because public clients cannot keep a client secret. The authorization code is useless without the matching code_verifier. Until an AS quietly accepts the token request without PKCE — or accepts a verifier that never matched the challenge.
That bug turns a stolen or leaked auth code (open redirect, referrer leak, custom URL scheme hijack) into tokens. Public SPAs and native apps are the usual victims; confidential server apps sometimes fail the same way when engineers copy-paste the public-client template.
What correct looks like
Authorization request includes code_challenge + code_challenge_method (usually S256). Token request must send code_verifier. Server stores the challenge and verifies BASE64URL(SHA256(verifier)).
If token endpoint returns tokens when:
code_verifieris omitted- verifier is empty /
null - verifier is a constant like
challenge plainmethod is accepted despiteS256being advertised- a different client_id redeems a code issued with PKCE
…you have a bypass worth chasing.
Hunting steps
- Map the OAuth dance in Burp: authorize → redirect with
code→ token. - Note whether the authorize call sent a challenge.
- Replay token exchange without verifier; with wrong verifier; with
plainmethod ifS256was required. - Try exchanging a code obtained from the official mobile/SPA client using a second “test” client registration if the program provides one.
- Check whether refresh-token rotation or reuse policies change when PKCE was skipped.
Watch for mixed modes: confidential clients enforce PKCE while the public mobile client does not — attackers prefer the weak client_id. Also compare authorize responses when challenge is missing entirely; some ASs still issue codes, which is already wrong for public clients.
Impact framing
PKCE bypass alone is often Medium until you show code theft. Common partners:
- Open redirect on
redirect_uri(within allowlist tricks) - Mobile intent / claim-scheme takeover
- XSS on the redirect landing origin that reads
?code= - Log or Referer leakage of the redirect URL
- Intermediate “login success” pages that bounce through a third-party analytics host
Chain: obtain code → redeem without verifier → access token for the victim. Use only your accounts. If you cannot steal a code in-scope, still report the broken enforcement with clear residual risk language — some programs pay for AS misconfig on its own when public clients are involved.
Report and fix notes
Include authorize + token requests (secrets redacted), proof that tokens issue without a valid verifier, and which client_id is affected. Recommend mandatory PKCE for public clients, reject missing verifiers, bind codes to code_challenge, exact-match redirect_uri, and short code lifetimes.
Spec primer: PKCE. PortSwigger’s OAuth lab track is useful for redirect_uri games that feed this class. Do not confuse “we use PKCE in the mobile app” marketing copy with server-side enforcement — always break the verifier on the wire.