CVE-2026-35039
Description
fast-jwt provides fast JSON Web Token (JWT) implementation. From 0.0.1 to before 6.2.0, setting up a custom cacheKeyBuilder method which does not properly create unique keys for different tokens can lead to cache collisions. This could cause tokens to be mis-identified during the verification process leading to valid tokens returning claims from different valid tokens and users being mis-identified as other users based on the wrong token. Version 6.2.0 contains a patch.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
fast-jwtnpm | >= 0.0.1, < 6.2.0 | 6.2.0 |
Affected products
1Patches
1de121056c641fix: cache confusion risk with composite-key approach (#587)
3 files changed · +64 −3
README.md+8 −2 modified@@ -176,7 +176,7 @@ Create a verifier function by calling `createVerifier` and providing one or more - `clockTolerance`: Timespan in milliseconds is the tolerance to apply to the current timestamp when performing time comparisons. Default is `0`. -- `cacheKeyBuilder`: The function that will be used to create the [cache's key](#caching) for each token. To mitigate the risk of leaking sensitive information and generate collisions, [a hashing function](./src/utils.js) is used by default. +- `cacheKeyBuilder`: The function that will be used to create the [cache's key](#caching) for each token. To mitigate the risk of leaking sensitive information and reduce the risk of collisions, [a hashing function](./src/utils.js) is used by default. When using a custom function, users must be aware of the possible risks. Check the [Caching section](#caching) for more information. The verifier is a function which accepts a token (as Buffer or string) and returns the payload or the sections of the token. @@ -280,7 +280,13 @@ The default `cacheKeyBuilder` is a function that hashes the token. This provides For a detailed discussion about it, take a look at [this issue](https://github.com/nearform/fast-jwt/issues/503). -> **_Note:_** Errors are not cached by default, to change this behaviour use the `errorCacheTTL` option. +> [!NOTE] +> Errors are not cached by default, to change this behaviour use the `errorCacheTTL` option. + +> [!WARNING] +> Setting up a custom `cacheKeyBuilder` method which does not properly create unique keys for different tokens can lead to cache collisions. This could cause tokens to be mis-identified during the verification process. For more information check [this GHSA](https://github.com/advisories/GHSA-rp9m-7r4c-75qg). +> Users willing to set up a custom cache key builder method have to make sure it works properly. + ## Token Error Codes
src/verifier.js+13 −1 modified@@ -516,6 +516,18 @@ module.exports = function createVerifier(options) { const allowedCritHeadersSet = new Set(allowedCritHeaders || []) + const cache = createCache(cacheSize) + + if (cache && options?.cacheKeyBuilder) { + process.emitWarning( + 'A custom cacheKeyBuilder is in use with caching enabled. ' + + 'Cache key collisions can lead to identity/authorization bypass. ' + + 'Make sure your cacheKeyBuilder generates unique keys for different tokens. ' + + 'See https://github.com/nearform/fast-jwt/security/advisories/GHSA-rp9m-7r4c-75qg', + { code: 'FAST_JWT_CACHE_KEY_BUILDER_SECURITY_RISK' } + ) + } + // Add validators const validators = [] @@ -581,7 +593,7 @@ module.exports = function createVerifier(options) { isAsync: keyType === 'function', validators, decode: createDecoder({ complete: true }), - cache: createCache(cacheSize), + cache, requiredClaims, allowedCritHeaders: allowedCritHeadersSet, cacheKeyBuilder
test/verifier.spec.js+43 −0 modified@@ -1196,6 +1196,49 @@ test('caching - sync - custom cacheKeyBuilder', t => { t.assert.ok(verifier.cache.get(invalidToken)[0] instanceof TokenError) }) +test('caching - sync - custom cacheKeyBuilder emits security warning', async t => { + let onWarning + const warningPromise = new Promise(resolve => { + onWarning = w => { + if (w.code === 'FAST_JWT_CACHE_KEY_BUILDER_SECURITY_RISK') { + resolve(w) + } + } + process.on('warning', onWarning) + }) + + t.after(() => process.off('warning', onWarning)) + + createVerifier({ key: 'secret', cache: true, cacheKeyBuilder: id => id }) + + const timeout = new Promise((_, reject) => + setTimeout(() => reject(new Error('Timed out waiting for FAST_JWT_CACHE_KEY_BUILDER_SECURITY_RISK warning')), 1000) + ) + + const warning = await Promise.race([warningPromise, timeout]) + t.assert.equal(warning.code, 'FAST_JWT_CACHE_KEY_BUILDER_SECURITY_RISK') + t.assert.ok(warning.message.includes('cacheKeyBuilder')) +}) + +test('caching - sync - default cacheKeyBuilder does not emit security warning', async t => { + let warningReceived = false + const onWarning = w => { + if (w.code === 'FAST_JWT_CACHE_KEY_BUILDER_SECURITY_RISK') { + warningReceived = true + } + } + process.on('warning', onWarning) + t.after(() => { + process.off('warning', onWarning) + }) + + createVerifier({ key: 'secret', cache: true }) + + // Wait a tick to allow any potential warning to be emitted + await new Promise(resolve => setImmediate(resolve)) + t.assert.equal(warningReceived, false) +}) + test('caching - async', async t => { const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxfQ.57TF7smP9XDhIexBqPC-F1toZReYZLWb_YRU5tv0sxM' const invalidToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxfQ.aaa'
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
4- github.com/nearform/fast-jwt/commit/de121056c6415b58770c60640881eaec67ac4cebnvdPatchWEB
- github.com/advisories/GHSA-rp9m-7r4c-75qgghsaADVISORY
- github.com/nearform/fast-jwt/security/advisories/GHSA-rp9m-7r4c-75qgnvdMitigationVendor AdvisoryWEB
- nvd.nist.gov/vuln/detail/CVE-2026-35039ghsaADVISORY
News mentions
0No linked articles in our index yet.