VYPR
Critical severity9.1NVD Advisory· Published Apr 6, 2026· Updated Apr 22, 2026

CVE-2026-35039

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.

PackageAffected versionsPatched versions
fast-jwtnpm
>= 0.0.1, < 6.2.06.2.0

Affected products

1
  • cpe:2.3:a:nearform:fast-jwt:*:*:*:*:*:node.js:*:*
    Range: >=0.1.0,<6.1.0

Patches

1
de121056c641

fix: cache confusion risk with composite-key approach (#587)

https://github.com/nearform/fast-jwtAntonio AttanasioApr 7, 2026via ghsa
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

News mentions

0

No linked articles in our index yet.