Share
## https://sploitus.com/exploit?id=0F27C219-7545-58CE-9AB3-D57541856B70
# CVE-2025-65945: node-jws Signature Bypass

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.

## What's the bug?

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:

1. Sending a JWT with a fake key ID that doesn't exist in your database
2. Signing their malicious payload with an empty string as the secret
3. Your server's lookup returns `undefined`, which gets coerced to empty string
4. Both sides now agree on the "secret" (empty string), so the signature validates

The attacker can now impersonate anyone or grant themselves admin privileges.

## Affected versions

- jws 3.2.2 and earlier
- jws 4.0.0

Upgrade to 3.2.3+ or 4.0.1+ to fix this.

## Running the PoC

Make sure you have [Bun](https://bun.sh) installed, then:

```sh
# Install the vulnerable version
bun install jws@3.2.2

# Run the exploit
bun run exploit.js
```

You should see output showing a forged admin token being accepted as valid.

## What does the exploit do?

The PoC simulates a server that:

- Has a secret store with a couple of API keys
- Looks up secrets based on the JWT's `kid` (key ID) header
- Uses `createVerify()` with the streaming API

The 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.

## Testing the fix

```sh
# Upgrade to patched version
bun install jws@3.2.3

# 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.

## The vulnerable code pattern

If your code looks anything like this, you might be affected:

```javascript
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();
```

## References

- [GitHub Advisory](https://github.com/advisories/GHSA-869p-cjfg-cm3x)
- [Fix commit](https://github.com/auth0/node-jws/commit/34c45b2c04434f925b638de6a061de9339c0ea2e)