GHSA-6WVW-VRW4-363W
Vulnerability from github – Published: 2026-08-20 18:35 – Updated: 2026-08-27 19:04Summary A process-global nonce cache with no eviction policy allows an unauthenticated remote attacker to exhaust server heap memory by repeatedly opening sessions, causing the node-opcua server process to crash.
Affected versions: <= 2.165.0 Tested version: 2.165.0 CVSS Score: 7.5 (High) CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H CWE: CWE-770 Allocation of Resources Without Limits or Throttling
Root Cause
In packages/node-opcua-secure-channel/source/server/server_secure_channel_layer.ts at line 156, g_alreadyUsedNonce is a process-global object used to track previously seen nonces for replay detection. Entries are added on every OpenSecureChannelRequest and every CreateSession request but are never removed or expired.
An unauthenticated attacker can exploit the CreateSession path (which requires no certificate) to accumulate nonce entries indefinitely. Even with maxSessions=10 limiting concurrent sessions, nonces persist after session expiry, allowing slow but reliable heap exhaustion across repeated connection cycles.
Measured Impact
Dynamically confirmed heap growth: - 5,000 unique nonces → +1.23 MB resident heap, no eviction after explicit GC - Projected: 10^6 nonces → ~246 MB resident heap - Achievable OOM on default Node.js heap limits
Suggested Fix
Add a TTL-based eviction policy to g_alreadyUsedNonce. Nonces should be expired after the maximum session timeout (or a reasonable fixed window, e.g. 1 hour). A Map with timestamp entries and periodic cleanup is sufficient.
I am following a 90-day responsible disclosure policy. I am happy to provide additional technical details under embargo. Please confirm receipt at your earliest convenience.
Reporter: Stanley Tobias Discovery date: 2026-03-23
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "node-opcua"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.166.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-54156"
],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2026-08-20T18:35:41Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "**Summary**\nA process-global nonce cache with no eviction policy allows an unauthenticated remote attacker to exhaust server heap memory by repeatedly opening sessions, causing the node-opcua server process to crash.\n\n**Affected versions:** \u003c= 2.165.0\n**Tested version:** 2.165.0\n**CVSS Score:** 7.5 (High)\n**CVSS Vector:** CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H\n**CWE:** CWE-770 Allocation of Resources Without Limits or Throttling\n\n---\n\n**Root Cause**\n\nIn `packages/node-opcua-secure-channel/source/server/server_secure_channel_layer.ts` at line 156, `g_alreadyUsedNonce` is a process-global object used to track previously seen nonces for replay detection. Entries are added on every `OpenSecureChannelRequest` and every `CreateSession` request but are never removed or expired.\n\nAn unauthenticated attacker can exploit the `CreateSession` path (which requires no certificate) to accumulate nonce entries indefinitely. Even with `maxSessions=10` limiting concurrent sessions, nonces persist after session expiry, allowing slow but reliable heap exhaustion across repeated connection cycles.\n\n---\n\n**Measured Impact**\n\nDynamically confirmed heap growth:\n- 5,000 unique nonces \u2192 +1.23 MB resident heap, no eviction after explicit GC\n- Projected: 10^6 nonces \u2192 ~246 MB resident heap\n- Achievable OOM on default Node.js heap limits\n\n---\n\n**Suggested Fix**\n\nAdd a TTL-based eviction policy to `g_alreadyUsedNonce`. Nonces should be expired after the maximum session timeout (or a reasonable fixed window, e.g. 1 hour). A Map with timestamp entries and periodic cleanup is sufficient.\n\n---\n\nI am following a 90-day responsible disclosure policy. I am happy to provide additional technical details under embargo. Please confirm receipt at your earliest convenience.\n\nReporter: Stanley Tobias\nDiscovery date: 2026-03-23",
"id": "GHSA-6wvw-vrw4-363w",
"modified": "2026-08-27T19:04:40Z",
"published": "2026-08-20T18:35:41Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/node-opcua/node-opcua/security/advisories/GHSA-6wvw-vrw4-363w"
},
{
"type": "WEB",
"url": "https://github.com/node-opcua/node-opcua/commit/b82c2939fe9c658de58da993f2798ec5481d7313"
},
{
"type": "PACKAGE",
"url": "https://github.com/node-opcua/node-opcua"
},
{
"type": "WEB",
"url": "https://github.com/node-opcua/node-opcua/releases/tag/v2.166.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "node-opcua: Unbounded nonce cache enables unauthenticated heap exhaustion DoS"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.