GitHub rated GHSA-xggf-m53x-jc3f (CVE-2026-95860) critical on November 10, 2026: an unauthenticated OPC UA Anonymous client can Write protected variables and Call privileged methods on nodes that lack explicit per-node RolePermissions, even when operators believed they locked the namespace down with setDefaultRolePermissions(). Affected npm packages include node-opcua, node-opcua-address-space, and node-opcua-server from 2.42.0 through 2.179.x. The fix ships in v2.180.0. If you run JavaScript OPC UA servers—especially prototypes agents scaffolded for IoT or shop-floor dashboards—upgrade, restart listeners, and verify enforcement with the advisory’s proof-of-concept pattern, not only by reading config code.
TL;DR
| Question | Answer |
|---|---|
| Am I affected? | Any deployment on node-opcua < 2.180.0 that relies on namespace-default RBAC without per-node RolePermissions on every sensitive node |
| Is there a fix? | 2.180.0 for node-opcua, node-opcua-address-space, and node-opcua-server |
| Attacker prerequisites? | Network reachability to the OPC UA port; Anonymous allowed (common in dev templates) |
| Severity? | Critical, CVSS 9.1 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N per advisory) |
| False sense of safety? | setDefaultRolePermissions() alone may not change what the server enforces |
| Agent angle? | Coding agents often spawn permissive demo servers; they do not audit OPC UA auth paths |
What the advisory says
The GitHub-reviewed advisory credits reporter Velluso and remediation by maintainer erossignon. It distinguishes two configurations:
- No
RolePermissionsdeclared anywhere — the server stays permissive by documented design. StockOpc.Ua.NodeSet2.xmlshipsDefaultRolePermissionswith no value, so this is an insecure default (CWE-1188), not the 9.1 bypass. - A policy is declared but silently ignored — the operator calls
setDefaultRolePermissions(), believes Anonymous is excluded, yet runtime enforcement never consults that field. This is the critical bypass.
OPC UA Part 3 §4.8.3 requires default-deny: if permission bits for the current operation are not set, the server returns Bad_UserAccessDenied. The advisory argues node-opcua instead fails open when the applicable policy resolves to null.
Root cause in three bugs
Bug 1 — getPermissionForRole(null) returns all permissions. In packages/node-opcua-address-space/source/session_context.ts, when rolePermissions === null, the function returns allPermissions (Read, Write, Call) for any role checking in, including WellKnownRoles.Anonymous. That inverts OPC 10000-3 default-deny semantics cited in the advisory.
Bug 2 — the namespace default resolves to null on the enforcement path. Runtime reads DefaultRolePermissions / DefaultUserRolePermissions under Server/Namespaces/<ns>. NodeSet-loaded namespaces ship those properties without a value; programmatic namespaces may lack NamespaceMetadata entirely. Additionally, server_engine.ts rewrites these nodes to a Null-typed value on initialize() without restoring operator settings.
Bug 3 — two disconnected enforcement paths. Path A: Namespace.setDefaultRolePermissions() stores policy in a private JavaScript field read by getters such as BaseNodeImpl.getRolePermissions(inherited=true). Path B: session enforcement queries the DefaultRolePermissions UAVariable node, not the field. Unless the operator calls setNamespaceMetaData() to bindVariable(), the API call does not affect authorization. On NodeSet2-loaded namespaces, setNamespaceMetaData() can throw "INamespace meta data already exists", leaving no working way to activate the namespace default (PoC-C in the advisory).
The advisory measures: with setDefaultRolePermissions([Operator]) applied, namespace.getDefaultRolePermissions() returns the policy while getApplicableRolePermissions() returns null.
Weaknesses listed: CWE-285, CWE-636, CWE-863, CWE-1188. EPSS was about 0.596% (49th percentile) when the advisory was reviewed. NVD published November 3, 2026; GitHub review completed November 10, 2026.
Mechanism step by step
- Operator hardens namespace — They exclude Anonymous and grant Operator
Read | Write | Browse | CallviasetDefaultRolePermissions(), assuming nodes without explicitRolePermissionsinherit that deny-by-role policy. - Server starts with anonymous enabled — Many templates set
allowAnonymous: trueandSecurityPolicy.Nonefor lab use, which matches the advisory’s TCP proof of concept. - Enforcement path loads null — Session context reads the UAVariable metadata node (or gets null when metadata is missing), not the private field written in step 1.
- Fail-open grant —
getPermissionForRole(null)returns all permission bits to Anonymous. - Attacker session — Client connects, creates an Anonymous session, Writes a double setpoint and Calls a bound shutdown method; status codes return Good in the vulnerable configuration (PoC-B output in the advisory).
- Mitigation that works in PoC — Running the same server with
setNamespaceMetaData(ns)after setting permissions (PoC-B--safe) yieldsBadUserAccessDeniedon Write and Call—demonstrating the gap is binding, not operator intent.
Nodes with explicit per-node RolePermissions remain enforced (PoC-A control case). The bypass targets inheritance-only nodes—the common case when developers add variables and methods under a device object without copying RBAC onto each node.
Who is affected
In scope:
- Production or lab node-opcua servers on < 2.180.0 where Anonymous is allowed on the network path
- Teams that called
setDefaultRolePermissions()but did notsetNamespaceMetaData()and did not set per-node permissions on critical methods - NodeSet2/DI namespaces where metadata binding throws, so namespace defaults cannot be activated at all (PoC-C)
Lower risk:
- Installations already on 2.180.0
- Nodes with explicit
setRolePermissions()on each sensitive variable and method - Servers with Anonymous disabled and strong message security—network exposure still matters, but the advisory’s PoC assumes Anonymous allowed
This is not a Claude Code or MCP bug. It is authorization logic in a widely used npm OPC UA stack. It still shows up on developer machines when agents add node-opcua to monorepos for edge gateways, synthetic data feeds, or test harnesses—same pattern as FastAPI generator RCE from untrusted OpenAPI: generated or scaffolded servers ship with dangerous defaults.
How to tell if you were exposed
The advisory does not describe confirmed in-the-wild exploitation, but the proof of concept is reproducible on 2.179.x with Anonymous sessions. If your server accepted Write or Call from Anonymous on nodes that only inherited namespace policy, assume the gap existed until patched.
Signals worth checking in logs (if you collect OPC UA audit events):
- Anonymous session performing Write on variables whose engineering docs say “Operator-only”
- Method invocations (
Call) on shutdown or maintenance methods without authenticated user tokens - Configuration reviews showing
setDefaultRolePermissions()in source but nosetNamespaceMetaData()and sparsesetRolePermissions()on child nodes
Version alone is not impact proof. A host still on < 2.180.0 that disabled Anonymous, required signed tokens, and set per-node RolePermissions on every sensitive node may have been harder to abuse than the advisory’s PoC—but the fail-open behavior still violated OPC default-deny expectations whenever inheritance was in play.
After upgrading, rerun the advisory’s PoC-B pattern against a non-production listener: vulnerable builds print Good status for Anonymous Write/Call; patched builds should return BadUserAccessDenied when policy is bound correctly.
What to do now
Version and inventory
npm ls node-opcua node-opcua-server node-opcua-address-space
Repeat in Dockerfiles, pnpm/yarn workspaces, and transitive dependency trees. Agents often add the meta-package once; CI images may pin an older server bundle.
Upgrade and restart
- Bump to
[email protected](and matchingnode-opcua-server/node-opcua-address-spaceversions per lockfile). - Restart every OPC UA listener after deploy—authorization state is in running processes.
Validate enforcement (not just config reads)
- After patch, run a negative test: Anonymous session should not Write or Call protected nodes.
- If you must stay on a patched line temporarily, add per-node
RolePermissionson every method and writable variable worth protecting—tedious but enforced in PoC-A. - For NodeSet2 namespaces, treat
setDefaultRolePermissions()as untrusted for security until you confirm metadata binding succeeds.
Hunt on the network
- OPC UA commonly listens on 4840/tcp or adjacent ports in demos (
48411/48412in the advisory scripts). - Segment plant interfaces from office LANs; do not expose Anonymous endpoints to the internet.
What this means if you run AI coding agents
Coding agents increasingly scaffold full-stack demos—REST plus OPC UA bridges for digital twins, MQTT translators, or “connect factory simulator” tasks. Those flows often:
- Add
node-opcuawith anonymous and None security for speed - Call
setDefaultRolePermissions()because a prompt mentioned RBAC, withoutsetNamespaceMetaData() - Leave Methods bound to shutdown or reset handlers without per-node locks
An agent may commit working code that lies to operators: getters show a policy object; TCP clients prove Anonymous can still Write ReactorSetpoint and Call EmergencyShutdown—matching the advisory’s end-to-end script output.
Concrete checks for agent-heavy teams:
grep -r setDefaultRolePermissionsin repos agents touched this quarter; pair withsetNamespaceMetaDataor explicit per-node permissions.- Add a CI import or integration smoke test that attempts Anonymous Write/Call against a test namespace—static review misses fail-open paths, similar to call-time vs import-time generator RCE.
- Run
beam cve checkon Node lockfiles where you use AgentBeam (CVE check in CI) so GHSA entries surface before deploy—once the Beam CVE database syncs this id.
Offensive agents finding industrial bugs faster, as in Cipher’s EPICS Base disclosures, is a separate thread. CVE-2026-95860 is defender patch hygiene on a dependency agents may introduce casually.
Permission checklist for agent-generated servers (manual review still required):
| Check | Pass criteria |
|---|---|
| Package version | node-opcua ≥ 2.180.0 in lockfile |
| Anonymous | Disabled on any interface reachable beyond a single dev laptop |
| Namespace policy | setDefaultRolePermissions() and successful metadata bind, or explicit per-node ACLs |
| Methods | Every bound Method has RolePermissions or is unreachable to Anonymous |
Variables with CurrentWrite | Explicit RolePermissions or deny Anonymous at endpoint level |
| Agent diff review | No new allowAnonymous: true without matching network ACL |
If an agent opens a PR that adds OPC UA “for monitoring,” treat it like adding ssh on port 22: useful in a lab, hazardous on a flat VLAN.
What Beam can and cannot do here
Beam watches Claude Code, Codex, and similar agents on your machine—commands, file writes, and tool calls—not live OPC UA protocol traffic on a plant floor.
What it can help with:
- Flagging when an agent
npm installsnode-opcuaor writes a server file withallowAnonymous: trueand no per-nodeRolePermissionsin the same change set (what agent monitoring catches). beam cve checkon JavaScript lockfiles once/CVE sync includes GHSA-xggf-m53x-jc3f.- PreToolUse deny (enforce mode, supported harnesses) if policy blocks binding
0.0.0.0:4840or pushing unaudited industrial listeners—hook-based, not a network firewall.
What it cannot do:
- Patch
node-opcuaor enforce OPC UA RBAC at the protocol layer - Replace network segmentation, Anonymous disablement, or per-node permission design on embedded gateways
- Prove a remote plant was exploited—only local agent actions and dependency versions on dev laptops
See how Beam watches agents for scope.
Frequently asked questions
What is CVE-2026-95860?
Critical node-opcua authorization fail-open when namespace RBAC appears configured but enforcement resolves to null, granting Anonymous Write and Call on inheriting nodes.
Which versions are affected?
≥ 2.42.0 and < 2.180.0 on node-opcua, node-opcua-address-space, and node-opcua-server. Fix: 2.180.0.
Does setDefaultRolePermissions() protect me?
Not by itself. Runtime may ignore the private field unless metadata is bound; NodeSet2 paths may forbid binding altogether.
What should I run to verify?
Advisory PoCs: unit test test_poc_rbac_failopen.ts, TCP scripts poc_b_e2e_rbac.js and poc_c_nodeset_rbac.js—compare vulnerable output vs --safe.
Is this exploited in the wild?
The advisory does not claim in-the-wild use. EPSS ~0.596%. Treat OPC UA exposure on flat networks as high impact regardless.
Do coding agents make this worse?
They accelerate insecure demo servers into repos; review agent-generated industrial code with the same rigor as hand-written SCADA glue.
Related reading
- CVE-2026-63470: fastapi-code-generator call-time RCE
- Import-time fastapi-code-generator CVEs
- Cipher and EPICS Base: agents finding control-system bugs
- Check dependencies against known CVEs in CI
- What is AI agent monitoring?
- November 2026 attacks timeline
Primary sources: GHSA-xggf-m53x-jc3f, NVD CVE-2026-95860, node-opcua v2.180.0 release, OPC 10000-3 §4.8.3.
Package versions, CVSS vector, and PoC filenames match the GitHub advisory as of November 10, 2026.

