fast-jwt JWT Algorithm Confusion
Description
fast-jwt provides fast JSON Web Token (JWT) implementation. Prior to version 3.3.2, the fast-jwt library does not properly prevent JWT algorithm confusion for all public key types. The 'publicKeyPemMatcher' in 'fast-jwt/src/crypto.js' does not properly match all common PEM formats for public keys. To exploit this vulnerability, an attacker needs to craft a malicious JWT token containing the HS256 algorithm, signed with the public RSA key of the victim application. This attack will only work if the victim application utilizes a public key containing the BEGIN RSA PUBLIC KEY header. Applications using the RS256 algorithm, a public key with a BEGIN RSA PUBLIC KEY header, and calling the verify function without explicitly providing an algorithm, are vulnerable to this algorithm confusion attack which allows attackers to sign arbitrary payloads which will be accepted by the verifier. Version 3.3.2 contains a patch for this issue. As a workaround, change line 29 of blob/master/src/crypto.js to include a regular expression.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
fast-jwtnpm | < 3.3.2 | 3.3.2 |
Affected products
1Patches
115a6e92c9adbMerge pull request from GHSA-c2ff-88x2-x9pg
2 files changed · +11 −17
src/crypto.js+7 −9 modified@@ -26,7 +26,7 @@ const base64UrlMatcher = /[=+/]/g const encoderMap = { '=': '', '+': '-', '/': '_' } const privateKeyPemMatcher = /^-----BEGIN(?: (RSA|EC|ENCRYPTED))? PRIVATE KEY-----/ -const publicKeyPemMatcher = '-----BEGIN PUBLIC KEY-----' +const publicKeyPemMatcher = /^-----BEGIN( RSA)? PUBLIC KEY-----/ const publicKeyX509CertMatcher = '-----BEGIN CERTIFICATE-----' const privateKeysCache = new Cache(1000) const publicKeysCache = new Cache(1000) @@ -44,7 +44,7 @@ const ecCurves = { /* istanbul ignore next */ if (!useNewCrypto) { - directSign = function(alg, data, options) { + directSign = function (alg, data, options) { if (typeof alg === 'undefined') { throw new TokenError(TokenError.codes.signError, 'EdDSA algorithms are not supported by your Node.js version.') } @@ -55,7 +55,7 @@ if (!useNewCrypto) { } } -const PrivateKey = asn.define('PrivateKey', function() { +const PrivateKey = asn.define('PrivateKey', function () { this.seq().obj( this.key('version').int(), this.key('algorithm') @@ -69,7 +69,7 @@ const PrivateKey = asn.define('PrivateKey', function() { ) }) -const PublicKey = asn.define('PublicKey', function() { +const PublicKey = asn.define('PublicKey', function () { this.seq().obj( this.key('algorithm') .seq() @@ -82,7 +82,7 @@ const PublicKey = asn.define('PublicKey', function() { ) }) -const ECPrivateKey = asn.define('ECPrivateKey', function() { +const ECPrivateKey = asn.define('ECPrivateKey', function () { this.seq().obj( this.key('version').int(), this.key('privateKey').octstr(), @@ -103,7 +103,7 @@ function cacheSet(cache, key, value, error) { } function performDetectPrivateKeyAlgorithm(key) { - if (key.includes(publicKeyPemMatcher) || key.includes(publicKeyX509CertMatcher)) { + if (key.match(publicKeyPemMatcher) || key.includes(publicKeyX509CertMatcher)) { throw new TokenError(TokenError.codes.invalidKey, 'Public keys are not supported for signing.') } @@ -157,7 +157,7 @@ function performDetectPrivateKeyAlgorithm(key) { function performDetectPublicKeyAlgorithms(key) { if (key.match(privateKeyPemMatcher)) { throw new TokenError(TokenError.codes.invalidKey, 'Private keys are not supported for verifying.') - } else if (!key.includes(publicKeyPemMatcher) && !key.includes(publicKeyX509CertMatcher)) { + } else if (!key.match(publicKeyPemMatcher) && !key.includes(publicKeyX509CertMatcher)) { // Not a PEM, assume a plain secret return hsAlgorithms } @@ -226,7 +226,6 @@ function detectPublicKeyAlgorithms(key) { if (!key) { return 'none' } - // Check cache first const [cached, error] = publicKeysCache.get(key) || [] @@ -243,7 +242,6 @@ function detectPublicKeyAlgorithms(key) { } else if (typeof key !== 'string') { throw new TokenError(TokenError.codes.invalidKey, 'The public key must be a string or a buffer.') } - return cacheSet(publicKeysCache, key, performDetectPublicKeyAlgorithms(key)) } catch (e) { throw cacheSet(
test/crypto.spec.js+4 −8 modified@@ -43,8 +43,7 @@ const detectedAlgorithms = { PS: rsaAlgorithms } -const invalidPrivatePKCS8 = ` ------BEGIN PRIVATE KEY----- +const invalidPrivatePKCS8 = `-----BEGIN PRIVATE KEY----- MIIBSwIBADCCASsGByqGSM44BAEwggEeAoGBAMGxOb7Tft3j9ibDnbRQmSzNFVWI zXgZuKcImr0hfaTHiCezcafkUCydrdlE+UddkS7i8I2USopaAC8qXm9MakL7aTLa PdCJIPBjmcMSXfxqngeIko1mGySNRVCc2QxGHvMSkjTrY7TEzvgI4cJDg9ykZGU1 @@ -55,16 +54,14 @@ sZjIEvC33/YIQaP8Gvw0zKIQFS9vMwQXAhUAxRK28V19J5W4jfBY+3L3Zy/XbIo= -----END PRIVATE KEY----- ` -const invalidPrivateCurve = ` ------BEGIN EC PRIVATE KEY----- +const invalidPrivateCurve = `-----BEGIN EC PRIVATE KEY----- MHECAQEEHgMIJ+JtbK1h1Hr+VuYfQD/lWlBSRo2Fx4+10MljjKAKBggqhkjOPQMA DaFAAz4ABH2YBzIol9aAQrQERTRHF31ztVeZ6dr8T8qJiitVoAFKep39qV9n/7sV NspwxJ55TbI7tJiW6tcF2/MdOw== -----END EC PRIVATE KEY----- ` -const invalidPublicPKCS8 = ` ------BEGIN PUBLIC KEY----- +const invalidPublicPKCS8 = `-----BEGIN PUBLIC KEY----- MIIBtzCCASwGByqGSM44BAEwggEfAoGBALqI31HbMCIw1QPaf2nGT6z7DaYu/NRV sdQ8cBkQSvegBXOTbAS+hxNq3rMcwm240ukBKnpvdEB3gyegsmNK2UVjrBgdl6Xs 0H9TK5Utnv5HspziTKgCy6Zf5IrAsiitrwnb+fBYLJrVGRAJErNmVVTXo6wiDHhW @@ -78,8 +75,7 @@ dceK/5cqXl02B+Q= -----END PUBLIC KEY----- ` -const invalidPublicCurve = ` ------BEGIN PUBLIC KEY----- +const invalidPublicCurve = `-----BEGIN PUBLIC KEY----- MFUwEwYHKoZIzj0CAQYIKoZIzj0DAA0DPgAEBaKDc/7IW3cMDxat8ivVjqDq1TZ+ T7r5sAUIWaF0Q5uk5NYmLOnCFxoP8Ua16sraCbAozdvg0wfvT7Cq -----END PUBLIC KEY-----
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-c2ff-88x2-x9pgghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-48223ghsaADVISORY
- github.com/nearform/fast-jwt/blob/master/src/crypto.jsghsax_refsource_MISCWEB
- github.com/nearform/fast-jwt/commit/15a6e92c9adb39acde41a9b11cec0cbde8ad763bghsaWEB
- github.com/nearform/fast-jwt/releases/tag/v3.3.2ghsax_refsource_MISCWEB
- github.com/nearform/fast-jwt/security/advisories/GHSA-c2ff-88x2-x9pgghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.