
PoC for CVE-2025-65945 (Improper Verification of Cryptographic Signature in node-jws)
This is a proof of concept for a signature verification bypass in the node-jws library. The bug lets attackers forge valid JWTs when the server derives HMAC secrets from user-controlled data.
The jws.createVerify() function doesn't validate that a secret was actually provided when using HMAC algorithms. If your app looks up secrets based on something in the JWT (like a kid header) and that lookup fails, you might end up verifying against an empty secret.
An attacker can exploit this by:
undefined, which gets coerced to empty stringThe attacker can now impersonate anyone or grant themselves admin privileges.
Upgrade to 3.2.3+ or 4.0.1+ to fix this.
Make sure you have Bun installed, then:
# Install the vulnerable version
bun install [email protected]
# Run the exploit
bun run exploit.js
You should see output showing a forged admin token being accepted as valid.
The PoC simulates a server that:
kid (key ID) headercreateVerify() with the streaming APIThe attacker creates a JWT with kid: "non-existent-key" and signs it with an empty secret. When the server tries to look up this key, it gets undefined, writes an empty string to the verification stream, and the forged token passes validation.
# Upgrade to patched version
bun install [email protected]
# Run again - should fail now
bun run exploit.js
With the patched version, you'll see an error: secret must be a string or buffer or a KeyObject. The fix validates that HMAC operations have a proper secret before proceeding.
If your code looks anything like this, you might be affected:
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();