CVE-2025-64767: @hpke/core @hpke/core Reuses AEAD Nonces Vulnerability
CRITICALCVE-2025-64767 is a CRITICAL (CVSS 9.1) @hpke/core reuses aead nonces vulnerability (CWE-323: Reusing a Nonce, Key Pair in Encryption) affecting @hpke/core libraries in the npm ecosystem. The issue involves @hpke/core reuses aead nonces. Remediation is available by upgrading affected packages to version 1.7.5.
CVE-2025-64767 at a Glance
Security Impact
CVSS: 9.1
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N).
How to Fix CVE-2025-64767
To remediate this vulnerability, upgrade all affected @hpke/core dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
npm install @hpke/core@1.7.5
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
npm ls @hpke/core
How to Check if You Are Affected
To determine whether your Node.js application is affected by CVE-2025-64767, inspect your project dependencies using npm:
npm ls @hpke/core
Analyze the terminal output to locate any version of @hpke/core in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.7.5), your application is affected.
Note: The npm ls @hpke/core command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-323: Reusing a Nonce, Key Pair in Encryption, where nonces should be used for the present occasion and only once. In @hpke/core, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2025-64767 Affected @hpke/core Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
@hpke/core
|
npm |
< 1.7.5
|
1.7.5
|
References
Frequently Asked Questions
What is CVE-2025-64767?
Which @hpke/core versions are affected?
What version fixes CVE-2025-64767?
Is @hpke/core affected?
What is the CVSS score of CVE-2025-64767?
What CWE is associated with CVE-2025-64767?
How can I check npm dependencies for CVE-2025-64767?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-73g8-5h73-26h4",
"modified" : "2025-11-21T22:18:25Z",
"published" : "2025-11-20T17:36:13Z",
"aliases" : [ "CVE-2025-64767" ],
"summary" : "@hpke/core reuses AEAD nonces",
"details" : "### Summary\n\nThe public SenderContext Seal() API has a race condition which allows for the same AEAD nonce to be re-used for multiple Seal() calls. This can lead to complete loss of Confidentiality and Integrity of the produced messages.\n\n### Details\n\nThe SenderContext Seal() [implementation](https://github.com/dajiaji/hpke-js/blob/b7fd3592c7c08660c98289d67c6bb7f891af75c4/packages/core/src/senderContext.ts#L22-L34) allows for concurrent executions to trigger `computeNonce()` with the same sequence number. This results in the same nonce being used in the suite's AEAD.\n\n### PoC\n\nThis code reproduces the issue (and also checks for more things that could be wrong with the implementation).\n\n```js\nimport { CipherSuite, KdfId, AeadId, KemId } from \"hpke-js\";\n\nconst suite = new CipherSuite({\n kem: KemId.DhkemP256HkdfSha256,\n kdf: KdfId.HkdfSha256,\n aead: AeadId.Aes128Gcm,\n});\n\nconst keypair = await suite.kem.generateKeyPair();\nconst skR = keypair.privateKey;\nconst pkR = keypair.publicKey;\n\nconst sender = await suite.createSenderContext({\n recipientPublicKey: pkR,\n});\n\nconst [message0, message1] = await Promise.all([\n sender.seal(\n new TextEncoder().encode(\"Secret message 1: Attack at dawn\").buffer\n ),\n sender.seal(\n new TextEncoder().encode(\"Secret message 2: Withdraw troops\").buffer\n ),\n]);\n\nconst recipient = await suite.createRecipientContext({\n recipientKey: skR,\n enc: sender.enc,\n});\n\nconst plaintext0 = await recipient.open(message0);\nconsole.log(\"✓ Decrypted message seq=0\", new TextDecoder().decode(plaintext0));\n\ntry {\n console.log(\n \"✓ Decrypted message seq=1\",\n new TextDecoder().decode(await recipient.open(message1))\n );\n console.log(\"\\n✓ nonce-reuse reproduction completed, code is NOT vulnerable\");\n} catch (error) {\n // re-sequence the recipient to verify same nonce was used for two messages\n recipient._ctx.seq = 0;\n console.log(\n \"❌ Decrypted a different message with seq=0\",\n new TextDecoder().decode(await recipient.open(message1))\n );\n\n console.log(\n \"\\n✓ nonce-reuse reproduction completed, code is vulnerable, nonces are reused when concurrent calls to .seal() are used\"\n );\n}\n\n// Test that failed Open() doesn't increment sequence\nconst recipient2 = await suite.createRecipientContext({\n recipientKey: skR,\n enc: sender.enc,\n});\n\nconst invalidMessage = new Uint8Array(message0.byteLength);\ninvalidMessage.set(new Uint8Array(message0));\ninvalidMessage[0] ^= 0xff; // Corrupt the first byte\n\ntry {\n await recipient2.open(invalidMessage.buffer);\n} catch {}\n\n// Now try to open the first valid message - should still work with seq=0\ntry {\n await recipient2.open(message0);\n console.log(\"✓ Successfully decrypted message with seq=0 after failed open()\");\n console.log(\"✓ Failed open() did NOT increment sequence\");\n} catch (error) {\n console.log(\"❌ Failed to decrypt message - sequence was incorrectly incremented\");\n}\n\n// Test that same message produces same ciphertext due to nonce reuse\nconst sender2 = await suite.createSenderContext({\n recipientPublicKey: pkR,\n});\n\nconst sameMessage = new TextEncoder().encode(\"Identical message\").buffer;\nconst [cipher0, cipher1] = await Promise.all([\n sender2.seal(sameMessage),\n sender2.seal(sameMessage),\n]);\n\nconst cipher0Array = new Uint8Array(cipher0);\nconst cipher1Array = new Uint8Array(cipher1);\n\nlet identical = true;\nif (cipher0Array.length !== cipher1Array.length) {\n identical = false;\n} else {\n for (let i = 0; i < cipher0Array.length; i++) {\n if (cipher0Array[i] !== cipher1Array[i]) {\n identical = false;\n break;\n }\n }\n}\n\nif (identical) {\n console.log(\"\\n❌ Same message produced IDENTICAL ciphertext (nonce reuse confirmed)\");\n} else {\n console.log(\"\\n✓ Same message produced different ciphertext (nonces are unique)\");\n}\n```\n\n### Recommendation\n\nImplement a synchronization mechanism such that only one seal()/open() per context can be executed at a time.\n\n### Notes\n\nRefs: https://github.com/hpkewg/hpke/issues/38\n\n> https://www.rfc-editor.org/rfc/rfc9180.html#section-9.7.5\n> The AEADs specified in this document are not secure in case of nonce reuse.\n\n> https://www.rfc-editor.org/rfc/rfc9180.html#section-5-6\n> A context is an implementation-specific structure that encodes the AEAD algorithm and key in use, and manages the nonces used so that the same nonce is not used with multiple plaintexts.\n\nThe context implementation in @hpke/core is not correct given its AEAD Seal() is awaited/asynchronous.",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "npm",
"name" : "@hpke/core"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "1.7.5"
} ]
} ],
"database_specific" : {
"last_known_affected_version_range" : "<= 1.7.4"
}
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/dajiaji/hpke-js/security/advisories/GHSA-73g8-5h73-26h4"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2025-64767"
}, {
"type" : "WEB",
"url" : "https://github.com/dajiaji/hpke-js/commit/94a767c9b9f37ce48d5cd86f7017d8cacd294aaf"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/dajiaji/hpke-js"
}, {
"type" : "WEB",
"url" : "https://github.com/dajiaji/hpke-js/blob/b7fd3592c7c08660c98289d67c6bb7f891af75c4/packages/core/src/senderContext.ts#L22-L34"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-323" ],
"severity" : "CRITICAL",
"github_reviewed" : true,
"github_reviewed_at" : "2025-11-20T17:36:13Z",
"nvd_published_at" : "2025-11-21T19:16:03Z"
}
}