fast-jwt: Incomplete fix for CVE-2023-48223: JWT Algorithm Confusion via Whitespace-Prefixed RSA Public Key
Date: 2026-04
Affected: npm/fast-jwt
Attack vector: other
Category: vulnerability-disclosure
Severity: Critical
CVE: CVE-2023-48223
CVE-2026-34950
CWE: CWE-20
CWE-327
CVSS: 9.1 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N)

### Summary The fix for GHSA-c2ff-88x2-x9pg (CVE-2023-48223) is incomplete. The publicKeyPemMatcher regex in fast-jwt/src/crypto.js uses a ^ anchor that is defeated by any leading whitespace in the key string, re-enabling the exact same JWT algorithm confusion attack that the CVE patched. ### Details The fix for CVE-2023-48223 (https://github.com/nearform/fast-jwt/commit/15a6e92, v3.3.2) changed the public key matcher from a plain string used with .includes() to a regex used with .match(): ``` // Before fix (vulnerable to original CVE) const publicKeyPemMatcher = '-----BEGIN PUBLIC KEY-----' // .includes() matched anywhere in the string — not vulnerable to whitespace // After fix (current code, line 28) const publicKeyPemMatcher = /^-----BEGIN(?: (RSA))? PUBLIC KEY-----/ // ^ anchor requires match at position 0 — defeated by leading whitespace In performDetectPublicKeyAlgorithms() (https://github.com/nearform/fast-jwt/blob/0ff14a687b9af786bd3ffa870d6febe6e1f13aaa/src/crypto.js#L126-L137): function performDetectPublicKeyAlgorithms(key) { const publicKeyPemMatch = key.match(publicKeyPemMatcher) // no .trim()! if (key.match(privateKeyPemMatcher)) { throw ... } else if (publicKeyPemMatch && publicKeyPemMatch[1] === 'RSA') { return rsaAlgorithms // ← correct path: restricts to RS/PS algorithms } else if (!publicKeyPemMatch && !key.includes(publicKeyX509CertMatcher)) { return hsAlgorithms // ← VULNERABLE: RS


Mitigations:

Architectural layers (MAESTRO):