CVE-2025-65945
Executive Summary
CVE-2025-65945 is a critical improper signature verification vulnerability in the auth0/node-jws library, a JSON Web Signature (JWS) implementation for Node.js. The flaw specifically affects the HS256 (HMAC with SHA-256) algorithm when the jws.createVerify() function is used. An attacker can bypass signature verification by crafting a JWS token where the protected header or payload contains data that influences the HMAC secret lookup process. This allows the attacker to forge valid signatures without knowing the actual secret key.
The vulnerability impacts all versions up to and including 3.2.2, as well as version 4.0.0. The CVSS score is 7.5 (High), with a vector of AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N, indicating network-based exploitation with low complexity and no privileges required, leading to a high impact on integrity.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability is in the auth0/node-jws npm package. Organizations using this library in their Node.js applications are at risk. The package is a direct dependency for many authentication and authorization systems. An attacker could exploit this to forge JWT tokens, gaining unauthorized access to protected resources. The supply chain risk is significant because the library is widely used and the vulnerability is in a core security function (signature verification). Organizations should immediately audit their dependencies for affected versions and update to patched versions (3.2.3 or 4.0.1).
CVSS Breakdown & Threat Level
- CVSS Score: 7.5 (High)
- Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
- Attack Vector (AV): Network (N) - Exploitable remotely.
- Attack Complexity (AC): Low (L) - No special conditions required.
- Privileges Required (PR): None (N) - No authentication needed.
- User Interaction (UI): None (N) - No user action required.
- Scope (S): Unchanged (U) - Impact is confined to the vulnerable component.
- Confidentiality (C): None (N) - No data exposure.
- Integrity (I): High (H) - Complete compromise of data integrity.
- Availability (A): None (N) - No impact on availability.
Threat Level: High. The vulnerability allows an attacker to bypass signature verification, effectively forging any JWS token. This can lead to privilege escalation, unauthorized access, and data manipulation.
Deep Dive & Mechanics
The vulnerability lies in the jws.createVerify() function when used with HMAC algorithms (specifically HS256). The function is designed to verify the signature of a JWS token. The verification process typically involves:
- Parsing the JWS token into its three parts: header, payload, and signature.
- Extracting the algorithm from the header.
- Looking up the secret key based on some identifier (e.g.,
kidin the header). - Recomputing the HMAC signature using the secret and the header+payload.
- Comparing the computed signature with the provided signature.
The flaw occurs in step 3. The secret lookup routine is supposed to use a trusted source (e.g., a configuration file or environment variable) to find the secret. However, in the vulnerable versions, the lookup routine can be influenced by user-controlled data from the JWS header or payload. For example, if the application uses the kid (key ID) from the header to fetch the secret from a database, an attacker can provide a kid that points to a secret they know (or can predict), or even a kid that causes the lookup to return a predictable value.
The attacker can then:
- Create a JWS token with a crafted header (e.g.,
{"alg":"HS256","kid":"attacker-controlled"}). - Set the payload to any desired content.
- Compute the HMAC signature using a secret they control (or can derive).
- Send the token to the vulnerable application.
- The application's
jws.createVerify()function will use the attacker-controlledkidto look up the secret, find the attacker's secret, and verify the signature as valid.
This bypasses the entire signature verification mechanism, allowing the attacker to forge arbitrary tokens.
Vulnerable vs. Patched Code
Vulnerable Code (versions < 3.2.3, = 4.0.0):
The vulnerable code likely looks something like this (simplified):
// Vulnerable: secret lookup uses user-controlled data
const jws = require('jws');
function verifyToken(token) {
const decoded = jws.decode(token);
const header = decoded.header;
const payload = decoded.payload;
const signature = decoded.signature;
// Vulnerable: using 'kid' from header to look up secret
const secret = getSecretFromDatabase(header.kid); // User-controlled input!
const isValid = jws.createVerify({
algorithm: header.alg,
key: secret,
header: header,
payload: payload,
signature: signature
});
return isValid;
}
Patched Code (versions 3.2.3 and 4.0.1):
The patched code ensures that the secret lookup is not influenced by user-controlled data. The fix likely involves:
- Validating the
kidagainst a whitelist of allowed key IDs. - Using a separate, trusted mechanism for secret lookup that does not rely on the JWS header.
- Or, simply ignoring the
kidfrom the header and using a fixed secret.
// Patched: secret lookup is isolated from user-controlled data
const jws = require('jws');
function verifyToken(token) {
const decoded = jws.decode(token);
const header = decoded.header;
const payload = decoded.payload;
const signature = decoded.signature;
// Patched: Use a fixed secret or a trusted lookup mechanism
const secret = process.env.JWS_SECRET; // Not from header
const isValid = jws.createVerify({
algorithm: header.alg,
key: secret,
header: header,
payload: payload,
signature: signature
});
return isValid;
}
Exploitation & Lab Setup
Red Team (Attacker)
Objective: Forge a valid JWS token to gain unauthorized access.
Prerequisites:
- A target application using
auth0/node-jwsversion < 3.2.3 or = 4.0.0. - The application must use the
jws.createVerify()function with HMAC algorithms and use user-provided data (e.g.,kid) for secret lookup.
Exploitation Steps:
Identify the Vulnerability: Send a test JWS token with a crafted
kidto see if the application responds differently. For example, send a token withkid: "test"and observe the error message.Craft a Malicious Token:
- Create a JWS header:
{"alg":"HS256","kid":"attacker-controlled"} - Create a payload:
{"sub":"admin","iat":1516239022} - Compute the HMAC signature using a secret that corresponds to the
kidyou provided. If you can control the secret lookup, you can use any secret you know.
import hmac import hashlib import base64 import json header = {"alg":"HS256","kid":"attacker-controlled"} payload = {"sub":"admin","iat":1516239022} # Encode header and payload header_b64 = base64.urlsafe_b64encode(json.dumps(header).encode()).rstrip(b'=').decode() payload_b64 = base64.urlsafe_b64encode(json.dumps(payload).encode()).rstrip(b'=').decode() # Use a known secret (e.g., "mysecret") secret = "mysecret" message = f"{header_b64}.{payload_b64}".encode() signature = hmac.new(secret.encode(), message, hashlib.sha256).digest() signature_b64 = base64.urlsafe_b64encode(signature).rstrip(b'=').decode() token = f"{header_b64}.{payload_b64}.{signature_b64}" print(token)- Create a JWS header:
Send the Token: Send the crafted token to the target application's authentication endpoint.
Gain Access: If successful, the application will accept the forged token, granting you access with the privileges defined in the payload (e.g., admin).
Blue Team (Defender)
Detection and Response:
Monitor for Anomalous JWT Tokens:
- Look for tokens with unusual
kidvalues that do not match known key IDs. - Monitor for tokens where the
kidis not present in the application's key store.
- Look for tokens with unusual
Audit Secret Lookup Logic:
- Review the code that uses
jws.createVerify()to ensure that the secret lookup is not influenced by user-controlled data. - Ensure that the
kidis validated against a whitelist.
- Review the code that uses
Implement Input Validation:
- Validate the
kidfield in the JWS header against a list of allowed values. - Reject tokens with unexpected or missing
kidvalues.
- Validate the
Update to Patched Version:
- Immediately update
auth0/node-jwsto version 3.2.3 or 4.0.1.
- Immediately update
Log and Alert:
- Log all JWT verification failures.
- Set up alerts for repeated verification failures from the same source IP.
Indicators of Compromise (IOCs)
Network Indicators:
- HTTP requests containing JWT tokens with unusual
kidvalues (e.g.,kid: "test",kid: "attacker-controlled"). - Repeated 401 Unauthorized responses followed by a 200 OK (indicating a successful bypass attempt).
- HTTP requests containing JWT tokens with unusual
File/System Indicators:
- Presence of
node-jwspackage version < 3.2.3 or = 4.0.0 inpackage.jsonornode_modules. - Log entries showing JWT verification failures with specific
kidvalues.
- Presence of
Behavioral Indicators:
- Unauthorized access to administrative endpoints.
- Privilege escalation attempts using forged tokens.
Detection Engineering
YARA Rule
rule CVE_2025_65945_node_jws {
meta:
description = "Detects vulnerable versions of auth0/node-jws in package.json"
author = "Valters IT"
date = "2025-04-10"
cve = "CVE-2025-65945"
severity = "high"
strings:
$package_name = "node-jws"
$version_3_2_2 = /"version":\s*"3\.2\.2"/
$version_4_0_0 = /"version":\s*"4\.0\.0"/
$version_less_than_3_2_3 = /"version":\s*"3\.\d+\.\d+"/ and not /"version":\s*"3\.2\.\d+"/ and not /"version":\s*"3\.\d+\.\d+"/ and not /"version":\s*"3\.2\.3"/
$version_less_than_4_0_1 = /"version":\s*"4\.0\.0"/
condition:
$package_name and ($version_3_2_2 or $version_4_0_0 or $version_less_than_3_2_3 or $version_less_than_4_0_1)
}
Sigma Rule
title: CVE-2025-65945 - JWT Signature Bypass via node-jws
id: 8a4b3c2d-1e5f-6a7b-8c9d-0e1f2a3b4c5d
status: experimental
description: Detects attempts to exploit CVE-2025-65945 by sending JWT tokens with suspicious kid values.
author: Valters IT
date: 2025-04-10
tags:
- attack.t1190
- cve.2025.65945
logsource:
category: application
product: nodejs
detection:
selection:
- event: "JWT verification failed"
- event: "JWT verification succeeded"
condition: selection
falsepositives:
- Legitimate use of multiple key IDs
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-65945 - JWT Signature Bypass Attempt"; flow:to_server; content:"Authorization"; nocase; content:"Bearer"; distance:0; pcre:"/kid\":\s*\"[^\"]+\"/"; classtype:attempted-admin; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Action:
- Update
auth0/node-jwsto version 3.2.3 or 4.0.1. - Run
npm update node-jwsor update the version inpackage.jsonand runnpm install.
- Update
Code Review:
- Review all code that uses
jws.createVerify()to ensure that the secret lookup is not influenced by user-controlled data. - Implement a whitelist for allowed
kidvalues.
- Review all code that uses
Network Segmentation:
- Restrict access to the application to trusted networks only.
Monitoring:
- Enable detailed logging for JWT verification.
- Set up alerts for suspicious JWT tokens.
Long-Term:
- Consider using a more robust JWT library that is not vulnerable to this type of attack.
- Implement additional security measures such as token revocation lists and short token expiration times.
Valters IT
DevSecOps & Cyber Threat Intelligence