@node-oauth/oauth2-server: PKCE code_verifier ABNF not enforced in token exchange allows brute-force redemption of intercepted authorization codes
Collected exploitation and prediction evidence
Risk source coverageCISA KEV is observed exploitation evidence. FIRST EPSS is a dated prediction of exploitation in the next 30 days. Missing scores are unknown. This collector requests predictions only for explicit CVE aliases in the public NuGet archive; Microsoft release views retain their existing prediction scope.
No collected risk observation for these identifiers. This does not establish absence of exploitation or a zero probability.
cve-program · CVE-2026-41213
Published@node-oauth/oauth2-server is a module for implementing an OAuth2 server in Node.js. 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.
- Source published
- 23 Apr 2026 18:33:42 UTC
- Source modified
- 25 Apr 2026 01:23:58 UTC
- Observed here
- 23 Oct 2026 15:48:27 UTC
- Source terms
- CVE Program Terms of Use
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: cve-program · CVE Program Terms of Use. Source text is retained; field grouping and change labels are provided by ChangeIntel.
CVSS 3.1 · 5.9 CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
euvd · EUVD-2026-25272
Published@node-oauth/oauth2-server is a module for implementing an OAuth2 server in Node.js. 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.
EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON.
Original publisher date fields
datePublished: Apr 23, 2026, 6:33:42 PM
dateUpdated: Apr 25, 2026, 1:23:58 AM
- Source published
- Apr 23, 2026, 6:33:42 PM (timezone not stated)
- Source modified
- Apr 25, 2026, 1:23:58 AM (timezone not stated)
- Observed here
- 28 Oct 2026 05:07:15 UTC
- Source terms
- ENISA EUVD · source terms and attribution apply
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: euvd · ENISA EUVD · source terms and attribution apply. Source text is retained; field grouping and change labels are provided by ChangeIntel.
EUVD CVSS 3.1 · 5.9 CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
nvd · CVE-2026-41213
Published@node-oauth/oauth2-server is a module for implementing an OAuth2 server in Node.js. 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.
NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON.
Source analysis status: Analyzed
Weakness classifications: CWE-307 · CWE-1289
Original publisher date fields
published: 2026-04-23T19:17:29.400
lastModified: 2026-10-26T21:10:00.170
1 source CPE criteria · context only
- cpe:2.3:a:node-oauth:node-oauth\/oauth2-server:*:*:*:*:*:node.js:*:*
The original JSON retains the logical configuration operators, exclusions and version bounds.
- Source published
- 23 Apr 2026 19:17:29 UTC
- Source modified
- 26 Oct 2026 21:10:00 UTC
- Observed here
- 27 Oct 2026 10:10:07 UTC
- Source terms
- NIST NVD usage terms; underlying source attribution retained
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: nvd · NIST NVD usage terms; underlying source attribution retained. Source text is retained; field grouping and change labels are provided by ChangeIntel.
CVSS 3.1 · [email protected] · Secondary · 5.9 CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
osv · GHSA-jhm7-29pj-4xvf
Published## 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: ```http 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> ``` 2. Observe invalid guesses return `invalid_grant`. 3. Continue guessing (`a`..`z`). 4. When `code_verifier=z`, token issuance succeeds and returns bearer tokens. ### Confirmed PoC output ```text 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.
- Source published
- 16 Apr 2026 21:09:50 UTC
- Source modified
- 5 May 2026 16:11:45 UTC
- Observed here
- 24 Oct 2026 13:17:17 UTC
- Source terms
- GitHub Advisory Database · CC-BY-4.0
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: osv · GitHub Advisory Database · CC-BY-4.0. Source text is retained; field grouping and change labels are provided by ChangeIntel.
CVSS_V3 · CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
Publisher rating · MODERATE