Headline
CVE-2023-48228: OAuth2: Insufficient PKCE check
authentik is an open-source identity provider. When initialising a oauth2 flow with a code_challenge
and code_method
(thus requesting PKCE), the single sign-on provider (authentik) must check if there is a matching and existing code_verifier
during the token step. Prior to versions 2023.10.4 and 2023.8.5, authentik checks if the contents of code_verifier
is matching only when it is provided. When it is left out completely, authentik simply accepts the token request with out it; even when the flow was started with a code_challenge
. authentik 2023.8.5 and 2023.10.4 fix this issue.
Summary
When initialising a OAuth2 flow with a code_challenge and code_method (thus requesting PKCE), the SSO provider (authentik) must check if there is a matching and existing code_verifier during the token step.
authentik checks if the contents of code_verifier is matching ONLY when it is provided. When it is left out completely, authentik simply accepts the token request with out it; even when the flow was started with a code_challenge.
Patches
authentik 2023.8.5 and 2023.10.4 fix this issue.
Details
The code_verifier is only checked when the user provides it. Note that in line 209 there is a check if the code_parameter is left out. But there is no check if the PKCE parameter simply was omitted WHEN the request was started with a code_challenge_method.
This oversight likely did not stem from a coding error but from a misinterpretation of the RFC, where the backward compatibility section may be somewhat confusing.
https://datatracker.ietf.org/doc/html/rfc7636#section-4.5
RFC7636 explicitly says in Section 4.5:
The “code_challenge_method” is bound to the Authorization Code when
the Authorization Code is issued. That is the method that the token
endpoint MUST use to verify the "code_verifier".
Section 5, Compatibility
Server implementations of this specification MAY accept OAuth2.0
clients that do not implement this extension. If the “code_verifier”
is not received from the client in the Authorization Request, servers
supporting backwards compatibility revert to the OAuth 2.0 [RFC6749]
protocol without this extension.
Section 5, Compatibility, allows server implementations of this specification to accept OAuth 2.0 clients that do not implement this extension. However, if a code_verifier is not received from the client in the Authorization Request, servers that support backward compatibility should revert to the standard OAuth 2.0 protocol sans this extension (including all steps).
It should be noted that this does not mean that the code_verifier check can be disregarded at any point if the initial request included code_challenge or code_challenge_method. Since Authentik supports PKCE, it MUST verify the code_verifier as described in Section 4.5 AND fail if it was not provided.
Ofc verification can be skipped if the original authorization request did not invoke PKCE (no code_challenge_method and no code_challenge).
Failure to check the code_verifier renders the PKCE flow ineffective. This vulnerability particularly endangers public or hybrid clients, as their code is deemed non-confidential.
While not explicitly stated in the standard, it is generally recommended that OAuth2 flows accepting public clients should enforce PKCE - at least when redirecting to a non HTTPS URL (like http or an app link).
Impact
The vulnerability poses a high risk to both public and hybrid clients.
When for example a mobile app implements oauth2, a malicious app can simply also register the same in-app-link (e.g. mycoolapp://oauth2) for the redirect callback URL, possibly receiving code during callback. With PKCE working, a malicious app would still receive a code but the code would not work without the correct unhashed code-challenge.
This is especially problematic, because authentik claims to support PKCE, and a developer can expect that the proper checks are in place. Note that app-links cannot be protected by HTTPS or similar mechanisms.
Note also that this vulnerability poses a threat to confidential clients. Many confidential clients act as a proxy for OAuth2 API requests, typically from mobile apps or single-page applications. These proxies relay code_challenge, code_challenge_method (in auth request, which most libraries force and provide on default settings) and code_verifier in the token request unchanged and supplement the CLIENT_SECRET which only the relay knows. The relay can but does not have to check for an existing code_verifier as the standard does not define that PKCE can be ignored on confidential clients during the token request when the client requested PKCE during the authorization request.
An attacker could potentially gain full access to the application. If the code grants access to an admin account, the confidentiality, integrity, and availability of that application are compromised.
For more information
If you have any questions or comments about this advisory:
- Email us at [email protected]