
Abusing OAuth 2.0 PKCE Downgrade in Native Clients
A subtle authorization-code injection path emerging when public clients silently fall back from S256 to plain PKCE.
Background
OAuth 2.0 PKCE (RFC 7636) was designed to neutralize authorization-code interception against public clients. In practice, several SDKs still accept the legacy plain transformation when S256 negotiation fails — and a meaningful subset of identity providers will quietly honor it.
This post documents a chain that turns that fallback into an account takeover on a production native client.
The downgrade
When the client emits two simultaneous authorization requests — one with code_challenge_method=S256 and one omitted — the provider's session binding collapses to the most recent request. The recovered code is then exchangeable with a verifier the attacker controls.
GET /authorize?response_type=code
&client_id=app
&code_challenge=abc
&code_challenge_method=plainImpact
Single-tap account takeover from a malicious app holding the universal link entitlement.
Mitigation
Reject any token exchange where the original code_challenge_method is absent or plain for a client that previously advertised S256. Bind the method to the session, not the request.