
PoC für CVE-2025-65945 (Unzureichende Überprüfung der kryptografischen Signatur in node-jws)
Dies ist ein Proof of Concept für eine Signaturverifikationsumgehung in der Bibliothek node-jws. Der Fehler ermöglicht es Angreifern, gültige JWTs zu fälschen, wenn der Server HMAC-Geheimnisse aus benutzergesteuerten Daten ableitet.
Die Funktion jws.createVerify() validiert nicht, dass bei Verwendung von HMAC-Algorithmen tatsächlich ein Geheimnis bereitgestellt wurde. Wenn Ihre App Geheimnisse basierend auf etwas im JWT (wie einem kid-Header) nachschlägt und dieser Lookup fehlschlägt, könnte es passieren, dass Sie gegen ein leeres Geheimnis verifizieren.
Ein Angreifer kann dies ausnutzen, indem er:
undefined zurück, das zu einem leeren String umgewandelt wirdDer Angreifer kann sich nun als beliebige Person ausgeben oder sich selbst Administratorrechte gewähren.
Aktualisieren Sie auf 3.2.3+ oder 4.0.1+, um dies zu beheben.
Stellen Sie sicher, dass Bun installiert ist, und führen Sie dann Folgendes aus:
# Installiere die verwundbare Version
bun install [email protected]
# Führe den Exploit aus
bun run exploit.js
Sie sollten eine Ausgabe sehen, die zeigt, dass ein gefälschtes Admin-Token als gültig akzeptiert wird.
Der PoC simuliert einen Server, der:
kid (Schlüssel-ID) Header des JWT nachschlägtcreateVerify() mit der Streaming-API verwendetDer Angreifer erstellt ein JWT mit kid: "non-existent-key" und signiert es mit einem leeren Geheimnis. Wenn der Server versucht, diesen Schlüssel nachzuschlagen, erhält er undefined, schreibt einen leeren String in den Verifikationsstream, und das gefälschte Token besteht die Validierung.
# Upgrade auf die gepatchte Version
bun install [email protected]
# Erneut ausführen – sollte jetzt fehlschlagen
bun run exploit.js
Mit der gepatchten Version wird ein Fehler angezeigt: secret must be a string or buffer or a KeyObject. Der Fix stellt sicher, dass HMAC-Operationen vor der Ausführung ein ordentliches Geheimnis haben.
Wenn Ihr Code so aussieht, könnten Sie betroffen sein:
const decoded = jws.decode(token);
const secret = lookupSecret(decoded.header.kid); // könnte undefined zurückgeben!
const verifier = jws.createVerify({
algorithm: "HS256",
signature: token,
});
verifier.secret.write(secret); // oops
verifier.secret.end();