Skip to content

PKCE code_verifier ABNF not enforced in token exchange allows brute-force redemption of intercepted authorization codes

Moderate
jankapunkt published GHSA-jhm7-29pj-4xvf Apr 15, 2026

Package

npm @node-oauth/oauth2-server (npm)

Affected versions

<=5.2.1

Patched versions

5.3.0

Description

Summary

The token exchange path accepts RFC7636-invalid code_verifier values (including one-character strings) for S256 PKCE flows.
Because short/weak verifiers are accepted and failed verifier attempts do not consume the authorization code, an attacker who intercepts an authorization code can brute-force code_verifier guesses online until token issuance succeeds.

Root cause

  1. lib/pkce/pkce.js (getHashForCodeChallenge) only checks that verifier is a non-empty string before hashing for S256; it does not enforce RFC7636 ABNF (43..128 unreserved chars).
  2. lib/grant-types/authorization-code-grant-type.js compares hash(code_verifier) to stored codeChallenge without validating verifier format/length.
  3. In AuthorizationCodeGrantType.handle, authorization code revocation happens after verifier validation. Invalid guesses fail before revoke, so the same code can be retried repeatedly.

Steps to Reproduce

Setup

  • PKCE authorization code exists with:
    • codeChallengeMethod = "S256"
    • codeChallenge = BASE64URL(SHA256("z")) (verifier is one character, RFC-invalid)
  • Attacker has intercepted the authorization code value.

Reproduction

  1. Send repeated token requests with guessed code_verifier values:
POST /token HTTP/1.1
Host: oauth.example
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
client_id=client1&
client_secret=s3cret&
code=stolen-auth-code&
redirect_uri=https://client.example/callback&
code_verifier=<guess>
  1. Observe invalid guesses return invalid_grant.
  2. Continue guessing (a..z).
  3. When code_verifier=z, token issuance succeeds and returns bearer tokens.

Confirmed PoC output

BRUTE_FORCE_SUCCESS { tries: 26, guess: 'z', status: 200, tokenIssued: true }

Impact

An intercepted authorization code can be redeemed by brute-forcing low-entropy verifiers that the server should have rejected under RFC7636.
This weakens PKCE’s protection goal and allows token theft when clients generate short/predictable verifiers.

Recommended Fix

  1. Enforce pkce.codeChallengeMatchesABNF(request.body.code_verifier) in authorization code token exchange before hashing/comparison.
  2. Reject verifier values outside RFC7636 charset/length (43..128 unreserved).
  3. Invalidate authorization codes on failed verifier attempts (or add strict retry limits) to prevent online guessing.

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
High
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
None
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N

CVE ID

CVE-2026-41213

Weaknesses

Improper Restriction of Excessive Authentication Attempts

The product does not implement sufficient measures to prevent multiple failed authentication attempts within a short time frame. Learn more on MITRE.

Improper Validation of Unsafe Equivalence in Input

The product receives an input value that is used as a resource identifier or other type of reference, but it does not validate or incorrectly validates that the input is equivalent to a potentially-unsafe value. Learn more on MITRE.

Credits