Skip to content
Open62541 Pull 8298

Open62541 Pull 8298

github.com • October 24, 2026

Build the fuzz plugin objects from the sources matching the configured encryption provider instead of always selecting mbedTLS. Also propagate the provider include directory to the fuzz plugin target so OpenSSL and LibreSSL builds work with non-system installations.

Merge remote-tracking branch 'origin/1.4' into merge_14_15

# src/server/ua_services_nodemanagement.c

# src/server/ua_subscription_alarms_conditions.c

fix(plugin): sanitize certificate subject before use as filestore fil…

The filestore security policy derives the filename for a certificate

written by ServerConfiguration.UpdateCertificate from the certificate's

Subject Common Name. On the mbedTLS backend, the subject-name renderer

preserves path separator characters found in the CN field, so a

certificate with a CN such as "../../trusted/certs/x" or containing

backslashes causes the resulting .der/.key files to be written outside

the intended own/certs and own/private directories once ApplyChanges is

called, including into other parts of the certificate store.

createCertName() now sanitizes the subject-name substring used to build

the filename: '/', '\', and control characters are replaced with '_'

before the string is combined with the certificate thumbprint. Since the

sanitized value can no longer contain a path separator, it cannot be used

to address any file outside the fixed own/certs and own/private

directories, independent of how a given crypto backend renders the

Internal Vulnerability Advisory: open62541-SA-2026-0016

Thanks-to: Chuan Wei [SCU] for the responsible disclosure.

fix(pubsub): off-by-one in getFieldMetaData pre-auth heap-OOB read

An off-by-one error in getFieldMetaData() at src/pubsub/ua_pubsub_networkmessage_binary.c

used a strict > comparison instead of >=, allowing a one-past-the-end pointer

to be returned when index == emd->fieldsSize.

This is reachable pre-auth via UDP-multicast UADP PubSub RawData field encoding.

craft a DataSetMessage that triggers the off-by-one, causing decodeRawField() to

read heap memory adjacent to the fields[] array as a UA_FieldMetaData structure.

Impact: Pre-auth heap-OOB read, potential information disclosure, and possible

Thanks-to: Chuan Wei [SCU] for the responsible disclosure.

fix(plugin): replace substring URI match with exact comparison in ver…

UA_CertificateUtils_verifyApplicationUri() checked the certificate's Subject

Alternative Name URI field using a substring : the function returned

success whenever the expected applicationURI appeared anywhere inside the

An attacker who can present a certificate trusted by the peer (e.g. a

self-signed certificate added to the trust list, or any certificate issued by

a trusted CA) can craft a URI SAN of the form

"urn:attacker.example:padding: :suffix". The substring

accepts this certificate as if it belonged to the legitimate application,

allowing impersonation of any OPC UA endpoint whose ApplicationUri is known.

OpenSSL backend: replace the UA_Bstrstr() call with a length-and-memcmp exact

match against the first URI SAN entry extracted by OpenSSL.

mbedTLS backend ( = 3.4.0

already used UA_String_equal() and is unaffected.

Internal Vulnerability Advisory: open62541-SA-2026-0019

Co-authored-by: Joerg Fischer

Thanks-to: Chuan Wei [SCU] for the responsible disclosure.

fix(server): guard targetNameHash computation against NULL targetNode…

Operation_addReference() sets targetNode only when UA_ExpandedNodeId_isLocal()

returns true for the request item's targetNodeId. When the ExpandedNodeId is

non-local (serverIndex != 0 or namespaceUri.length != 0) and targetServerUri is

empty, targetNode remains NULL but the function unconditionally evaluated

UA_QualifiedName_hash(&targetNode->head.browseName);

causing a null-pointer dereference before any OPC UA status code was returned.

An authenticated client with AddReferences permissions could send a single

crafted request—setting targetNodeId.serverIndex to a non-zero value while

leaving targetServerUri empty—to crash the server thread.

The fix guards the hash computation: when targetNode is NULL (non-local target),

a hash of 0 is used. This is safe because for non-local targets the backward

reference on the target node is intentionally skipped, so the hash value is

never used for a node lookup in the same request.

Internal Vulnerability Advisory: open62541-SA-2026-0022

fix(core): reject custom-DataType definitions that overflow memSize/m…

UA_DataType_fromStructureDescription() accumulated the in-memory layout

size of a custom structured DataType directly into the 16-bit memSize

bitfield, and truncated the field count directly into the 8-bit

membersSize field. Neither assignment was guarded, so a structure

definition whose cumulative member size exceeds 65535 bytes (or whose

field count exceeds 255) silently wrapped/truncated instead of being

A DataType built this way ends up with a memSize far smaller than its

true member layout. Decoding a value of such a type then writes each

member at its true (larger) offset into a buffer allocated with the

wrapped, too-small memSize, corrupting adjacent heap memory.

UA_DataType_fromEnumDescription() truncates membersSize the same way.

Accumulate the layout size in a wide (size_t) temporary throughout

UA_DataType_fromStructureDescription() and only commit it to the

bitfield once validated to fit. Reject the definition with

BADENCODINGLIMITSEXCEEDED as soon as the running size would exceed

UA_UINT16_MAX, and reject field counts above 255 up front in both the

structure and enum builders instead of truncating them.

Internal Vulnerability Advisory: open62541-SA-2026-0025

Co-Authored-By: BUG|PWN Research

Co-Authored-By: Sadoc ADONON

fix(server): Guard against use-after-free in GDS ApplyChanges

fix(client): Validate NamespaceArray ReadResponse before dereferencing

responseReadNamespacesArray() checked !resp->results but not

resp->resultsSize. A resultsSize==0 with empty-array encoding yields

UA_EMPTY_ARRAY_SENTINEL (0x1, non-NULL), bypassing the check and

dereferencing results[0] at 0x19 -> SEGV (GHSA-x6vg-5px6-f6jh, CWE-125).

Fix: validate serviceResult, resultsSize>=1, hasValue, sentinel, array

type, and minimum length 2 before dereferencing. Single patch covers

fix(client): Limit recursion depth in UA_Client_getRemoteDataTypes

browseDataTypesRecursive() traverses the remote HasSubtype graph using

unbounded depth-first recursion. A server can return a chain of

previously unseen DataType NodeIds at each Browse step, bypassing the

visited-node deduplication and driving the recursion depth without

bound until the client stack is exhausted.

UA_MAX_REMOTE_DATATYPE_DEPTH (64) – maximum recursion depth

UA_MAX_REMOTE_DATATYPE_NODES (4096) – maximum discovered node count

Both are checked at the entry of browseDataTypesRecursive(). A depth

parameter is threaded through recursive calls. Exceeding either limit

aborts traversal with UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED and logs a

The change preserves the existing behaviour for well-formed servers and

does not affect the public API. A depth of 64 is consistent with the

UA_EVENTFILTER_MAXDEPTH bound already used elsewhere in the codebase for

the same purpose, and comfortably exceeds the deepest DataType subtype

chain (5 levels) found across the full OPC UA nodeset and companion

Internal Vulnerability Advisory: open62541-SA-2026-0034

test(core): use encodable type for ExtensionObject roundtrip

Use UA_Range, which has a binary encoding NodeId, instead of wrapping the built-in Int32 type in an ExtensionObject. Verify that the roundtrip preserves the decoded type and value. This keeps the test compatible with strict ExtensionObject body-length validation.

fix(core): release ExtensionObject content after decode errors

Mark allocated ExtensionObject content as decoded before validating the body length. This lets the normal decoder error cleanup release the allocation when length validation or content decoding fails.

fix(tests): wait for reverse-connect socket events

fix(core): release ExtensionObject content after decode errors

Mark allocated ExtensionObject content as decoded before validating the body

length. This lets normal decoder error cleanup release the allocation when

length validation or content decoding fails.

(fix(core): validate ExtensionObject body length against decoded byte count)

fix(discovery): validate mDNS path before changing state

Reject oversized discoveryUrl paths before they reach the earlier newUrl VLA or modify discovery and mDNS state.

(fix(discovery): cap discoveryUrl path length to prevent VLA stack exhaustion)

fix(core): validate ExtensionObject length without pointer overflow

Compare the declared body length with the remaining input before computing the

end pointer. This avoids undefined pointer arithmetic for oversized lengths.

Merge remote-tracking branch 'origin/1.3' into merge_13_14_4

# src/server/ua_services_discovery_multicast.c

fix(core): validate ExtensionObject array body lengths

Check each declared body length against the remaining input before advancing or forming an end pointer in the 1.4-only ExtensionObject-array decoder.

Correct the array handling introduced while merging

Merge remote-tracking branch 'origin/1.4' into merge_14_15

Add this suggestion to a batch that can be applied as a single commit.

This suggestion is invalid because no changes were made to the code.

Suggestions cannot be applied while the pull request is closed.

Suggestions cannot be applied while viewing a subset of changes.

Only one suggestion per line can be applied in a batch.

Add this suggestion to a batch that can be applied as a single commit.

Applying suggestions on deleted lines is not supported.

You must change the existing code in this line in order to create a valid suggestion.

This suggestion has been applied or marked resolved.

Suggestions cannot be applied from pending reviews.

Suggestions cannot be applied on multi-line .

Suggestions cannot be applied while the pull request is queued to merge.

Suggestion cannot be applied right now. Please check back later.