
PoC pour CVE-2025-65945 (Vérification incorrecte de la signature cryptographique dans node-jws)
Ceci est une preuve de concept pour un contournement de la vérification de signature dans la bibliothèque node-jws. Ce bug permet aux attaquants de forger des JWTs valides lorsque le serveur dérive des secrets HMAC à partir de données contrôlées par l'utilisateur.
La fonction jws.createVerify() ne valide pas qu'un secret a bien été fourni lors de l'utilisation d'algorithmes HMAC. Si votre application recherche des secrets en fonction d'un élément du JWT (comme un en-tête kid) et que cette recherche échoue, vous pourriez finir par vérifier avec un secret vide.
Un attaquant peut exploiter cela en :
undefined, qui est converti en chaîne videL'attaquant peut désormais usurper l'identité de n'importe qui ou s'accorder des privilèges d'administration.
Mettez à niveau vers 3.2.3+ ou 4.0.1+ pour corriger cela.
Assurez-vous d'avoir Bun installé, puis :
# Install the vulnerable version
bun install [email protected]
# Run the exploit
bun run exploit.js
Vous devriez voir une sortie montrant un jeton d'administration falsifié accepté comme valide.
Le PoC simule un serveur qui :
kid (identifiant de clé) du JWTcreateVerify() avec l'API de streamingL'attaquant crée un JWT avec kid: "non-existent-key" et le signe avec un secret vide. Lorsque le serveur tente de rechercher cette clé, il obtient undefined, écrit une chaîne vide dans le flux de vérification, et le jeton falsifié passe la validation.
# Upgrade to patched version
bun install [email protected]
# Run again - should fail now
bun run exploit.js
Avec la version corrigée, vous verrez une erreur : secret must be a string or buffer or a KeyObject. Le correctif valide que les opérations HMAC disposent d'un secret approprié avant de continuer.
Si votre code ressemble à ceci, vous pourriez être affecté :
const decoded = jws.decode(token);
const secret = lookupSecret(decoded.header.kid); // might return undefined!
const verifier = jws.createVerify({
algorithm: "HS256",
signature: token,
});
verifier.secret.write(secret); // oops
verifier.secret.end();