VYPR
Medium severity6.5NVD Advisory· Published Mar 19, 2025· Updated Apr 15, 2026

CVE-2025-30144

CVE-2025-30144

Description

fast-jwt provides fast JSON Web Token (JWT) implementation. Prior to 5.0.6, the fast-jwt library does not properly validate the iss claim based on the RFC 7519. The iss (issuer) claim validation within the fast-jwt library permits an array of strings as a valid iss value. This design flaw enables a potential attack where a malicious actor crafts a JWT with an iss claim structured as ['https://attacker-domain/', 'https://valid-iss']. Due to the permissive validation, the JWT will be deemed valid. Furthermore, if the application relies on external libraries like get-jwks that do not independently validate the iss claim, the attacker can leverage this vulnerability to forge a JWT that will be accepted by the victim application. Essentially, the attacker can insert their own domain into the iss array, alongside the legitimate issuer, and bypass the intended security checks. This issue is fixed in 5.0.6.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
fast-jwtnpm
< 5.0.65.0.6

Patches

2
cc26b1d473f9

Merge commit from fork

https://github.com/nearform/fast-jwtAnthony GublerMar 19, 2025via ghsa
2 files changed · +152 0
  • src/verifier.js+12 0 modified
    @@ -152,6 +152,16 @@ function validateClaimType(values, claim, array, type) {
     }
     
     function validateClaimValues(values, claim, allowed, arrayValue) {
    +  const failureMessage = arrayValue
    +    ? `Not all of the ${claim} claim values are allowed.`
    +    : `The ${claim} claim value is not allowed.`
    +
    +  if (!values.every(v => allowed.some(a => a.test(v)))) {
    +    throw new TokenError(TokenError.codes.invalidClaimValue, failureMessage)
    +  }
    +}
    +
    +function validateClaimArrayValues(values, claim, allowed, arrayValue) {
       const failureMessage = arrayValue
         ? `None of ${claim} claim values are allowed.`
         : `The ${claim} claim value is not allowed.`
    @@ -222,6 +232,8 @@ function verifyToken(
     
         if (type === 'date') {
           validateClaimDateValue(value, modifier, now, greater, errorCode, errorVerb)
    +    } else if (array) {
    +      validateClaimArrayValues(values, claim, allowed, arrayValue)
         } else {
           validateClaimValues(values, claim, allowed, arrayValue)
         }
    
  • test/verifier.spec.js+140 0 modified
    @@ -500,6 +500,41 @@ test('it validates the jti claim only if explicitily enabled', t => {
         { message: 'The jti claim value is not allowed.' }
       )
     
    +  t.assert.throws(
    +    () => {
    +      return verify(
    +        'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJqdGkiOlsiSlRJIiwiSlRJMSJdLCJhdWQiOlsiQVVEMSJdLCJpc3MiOiJJU1MiLCJzdWIiOiJTVUIiLCJub25jZSI6Ik5PTkNFIn0.H2GACKIYvauUswRaK3SVsSwUOTjEcQDb1Qj_iCuLWoM',
    +        { allowedJti: ['JTI'], key: 'secret-secret-secret-secret-secret' }
    +      )
    +    },
    +    { message: 'Not all of the jti claim values are allowed.' }
    +  )
    +
    +  t.assert.throws(
    +    () => {
    +      return verify(
    +        'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJqdGkiOlsiSlRJIiwiSlRJMSJdLCJhdWQiOlsiQVVEMSJdLCJpc3MiOiJJU1MiLCJzdWIiOiJTVUIiLCJub25jZSI6Ik5PTkNFIn0.H2GACKIYvauUswRaK3SVsSwUOTjEcQDb1Qj_iCuLWoM',
    +        { allowedJti: ['JTI', 'JTI2'], key: 'secret-secret-secret-secret-secret' }
    +      )
    +    },
    +    { message: 'Not all of the jti claim values are allowed.' }
    +  )
    +
    +  t.assert.deepStrictEqual(
    +    verify(
    +      'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJqdGkiOlsiSlRJIiwiSlRJMSJdLCJhdWQiOlsiQVVEMSJdLCJpc3MiOiJJU1MiLCJzdWIiOiJTVUIiLCJub25jZSI6Ik5PTkNFIn0.H2GACKIYvauUswRaK3SVsSwUOTjEcQDb1Qj_iCuLWoM',
    +      { allowedJti: ['JTI', 'JTI1'], key: 'secret-secret-secret-secret-secret' }
    +    ),
    +    {
    +      a: 1,
    +      jti: ['JTI', 'JTI1'],
    +      aud: ['AUD1'],
    +      iss: 'ISS',
    +      sub: 'SUB',
    +      nonce: 'NONCE'
    +    }
    +  )
    +
       t.assert.deepStrictEqual(
         verify(
           'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJqdGkiOiJKVEkiLCJhdWQiOlsiQVVEMSIsIkRVQTIiXSwiaXNzIjoiSVNTIiwic3ViIjoiU1VCIiwibm9uY2UiOiJOT05DRSJ9.8fqzi23J-GjaD7rW3OYJv8UtBYkx8MOkViJjS4sXmVw',
    @@ -664,6 +699,41 @@ test('it validates the iss claim only if explicitily enabled', t => {
         { message: 'The iss claim value is not allowed.' }
       )
     
    +  t.assert.throws(
    +    () => {
    +      return verify(
    +        'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJqdGkiOiJKVEkiLCJhdWQiOlsiQVVEMSJdLCJpc3MiOlsiSVNTIiwiSVNTMSJdLCJzdWIiOiJTVUIiLCJub25jZSI6Ik5PTkNFIn0.IS9XILuqYEAKycN8j2MT0121j19T02CbW_h0erVh5IE',
    +        { allowedIss: ['ISS'], key: 'secret-secret-secret-secret-secret' }
    +      )
    +    },
    +    { message: 'Not all of the iss claim values are allowed.' }
    +  )
    +
    +  t.assert.throws(
    +    () => {
    +      return verify(
    +        'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJqdGkiOiJKVEkiLCJhdWQiOlsiQVVEMSJdLCJpc3MiOlsiSVNTIiwiSVNTMSJdLCJzdWIiOiJTVUIiLCJub25jZSI6Ik5PTkNFIn0.IS9XILuqYEAKycN8j2MT0121j19T02CbW_h0erVh5IE',
    +        { allowedIss: ['ISS', 'ISS2'], key: 'secret-secret-secret-secret-secret' }
    +      )
    +    },
    +    { message: 'Not all of the iss claim values are allowed.' }
    +  )
    +
    +  t.assert.deepStrictEqual(
    +    verify(
    +      'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJqdGkiOiJKVEkiLCJhdWQiOlsiQVVEMSJdLCJpc3MiOlsiSVNTIiwiSVNTMSJdLCJzdWIiOiJTVUIiLCJub25jZSI6Ik5PTkNFIn0.IS9XILuqYEAKycN8j2MT0121j19T02CbW_h0erVh5IE',
    +      { allowedIss: ['ISS', 'ISS1'], key: 'secret-secret-secret-secret-secret' }
    +    ),
    +    {
    +      a: 1,
    +      jti: 'JTI',
    +      aud: ['AUD1'],
    +      iss: ['ISS', 'ISS1'],
    +      sub: 'SUB',
    +      nonce: 'NONCE'
    +    }
    +  )
    +
       t.assert.deepStrictEqual(
         verify(
           'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJqdGkiOiJKVEkiLCJhdWQiOlsiQVVEMSIsIkRVQTIiXSwiaXNzIjoiSVNTIiwic3ViIjoiU1VCIiwibm9uY2UiOiJOT05DRSJ9.8fqzi23J-GjaD7rW3OYJv8UtBYkx8MOkViJjS4sXmVw',
    @@ -741,6 +811,41 @@ test('it validates the sub claim only if explicitily enabled', t => {
         { message: 'The sub claim value is not allowed.' }
       )
     
    +  t.assert.throws(
    +    () => {
    +      return verify(
    +        'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJqdGkiOiJKVEkiLCJhdWQiOlsiQVVEMSJdLCJpc3MiOiJJU1MiLCJzdWIiOlsiU1VCMSIsIlNVQjIiXSwibm9uY2UiOiJOT05DRSJ9.RwBpdTCEFCxO0jIFPnJpxjRd0JVIhP2Eettmsh0uwzY',
    +        { allowedSub: ['SUB1'], key: 'secret-secret-secret-secret-secret' }
    +      )
    +    },
    +    { message: 'Not all of the sub claim values are allowed.' }
    +  )
    +
    +  t.assert.throws(
    +    () => {
    +      return verify(
    +        'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJqdGkiOiJKVEkiLCJhdWQiOlsiQVVEMSJdLCJpc3MiOiJJU1MiLCJzdWIiOlsiU1VCMSIsIlNVQjIiXSwibm9uY2UiOiJOT05DRSJ9.RwBpdTCEFCxO0jIFPnJpxjRd0JVIhP2Eettmsh0uwzY',
    +        { allowedSub: ['SUB1', 'SUB3'], key: 'secret-secret-secret-secret-secret' }
    +      )
    +    },
    +    { message: 'Not all of the sub claim values are allowed.' }
    +  )
    +
    +  t.assert.deepStrictEqual(
    +    verify(
    +      'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJqdGkiOiJKVEkiLCJhdWQiOlsiQVVEMSJdLCJpc3MiOiJJU1MiLCJzdWIiOlsiU1VCMSIsIlNVQjIiXSwibm9uY2UiOiJOT05DRSJ9.RwBpdTCEFCxO0jIFPnJpxjRd0JVIhP2Eettmsh0uwzY',
    +      { allowedSub: ['SUB1', 'SUB2'], key: 'secret-secret-secret-secret-secret' }
    +    ),
    +    {
    +      a: 1,
    +      jti: 'JTI',
    +      aud: ['AUD1'],
    +      iss: 'ISS',
    +      sub: ['SUB1', 'SUB2'],
    +      nonce: 'NONCE'
    +    }
    +  )
    +
       t.assert.deepStrictEqual(
         verify(
           'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJqdGkiOiJKVEkiLCJhdWQiOlsiQVVEMSIsIkRVQTIiXSwiaXNzIjoiSVNTIiwic3ViIjoiU1VCIiwibm9uY2UiOiJOT05DRSJ9.8fqzi23J-GjaD7rW3OYJv8UtBYkx8MOkViJjS4sXmVw',
    @@ -818,6 +923,41 @@ test('it validates the nonce claim only if explicitily enabled', t => {
         { message: 'The nonce claim value is not allowed.' }
       )
     
    +  t.assert.throws(
    +    () => {
    +      return verify(
    +        'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJqdGkiOiJKVEkiLCJhdWQiOlsiQVVEMSJdLCJpc3MiOiJJU1MiLCJzdWIiOiJTVUIiLCJub25jZSI6WyJOT05DRSIsIk5PTkNFMSJdfQ.a8ZSzXebJvaw32jyWgbBo9aeLNTgs_sqxD2llV4f8KQ',
    +        { allowedNonce: ['NONCE'], key: 'secret-secret-secret-secret-secret' }
    +      )
    +    },
    +    { message: 'Not all of the nonce claim values are allowed.' }
    +  )
    +
    +  t.assert.throws(
    +    () => {
    +      return verify(
    +        'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJqdGkiOiJKVEkiLCJhdWQiOlsiQVVEMSJdLCJpc3MiOiJJU1MiLCJzdWIiOiJTVUIiLCJub25jZSI6WyJOT05DRSIsIk5PTkNFMSJdfQ.a8ZSzXebJvaw32jyWgbBo9aeLNTgs_sqxD2llV4f8KQ',
    +        { allowedNonce: ['NONCE', 'NONCE2'], key: 'secret-secret-secret-secret-secret' }
    +      )
    +    },
    +    { message: 'Not all of the nonce claim values are allowed.' }
    +  )
    +
    +  t.assert.deepStrictEqual(
    +    verify(
    +      'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJqdGkiOiJKVEkiLCJhdWQiOlsiQVVEMSJdLCJpc3MiOiJJU1MiLCJzdWIiOiJTVUIiLCJub25jZSI6WyJOT05DRSIsIk5PTkNFMSJdfQ.a8ZSzXebJvaw32jyWgbBo9aeLNTgs_sqxD2llV4f8KQ',
    +      { allowedNonce: ['NONCE', 'NONCE1'], key: 'secret-secret-secret-secret-secret' }
    +    ),
    +    {
    +      a: 1,
    +      jti: 'JTI',
    +      aud: ['AUD1'],
    +      iss: 'ISS',
    +      sub: 'SUB',
    +      nonce: ['NONCE', 'NONCE1']
    +    }
    +  )
    +
       t.assert.deepStrictEqual(
         verify(
           'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJqdGkiOiJKVEkiLCJhdWQiOlsiQVVEMSIsIkRVQTIiXSwiaXNzIjoiSVNTIiwic3ViIjoiU1VCIiwibm9uY2UiOiJOT05DRSJ9.8fqzi23J-GjaD7rW3OYJv8UtBYkx8MOkViJjS4sXmVw',
    

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

5

News mentions

0

No linked articles in our index yet.