GHSA-5pv3-rhf5-gwgq: Out-of-bounds Write via TLS 1.3 HelloRetryRequest Cookie in NetX Secure TLS Clients
GHSA ID |
|
|---|---|
CVE ID |
CVE‑2026‑103415 |
Severity |
Critical |
CVSS score |
9.8 ( |
CWE |
|
Published |
2026‑10‑02 |
Last updated |
2026‑10‑02 |
Description
Summary
When a TLS 1.3 client processes a HelloRetryRequest, it copies the server’s cookie into its second ClientHello without checking that the cookie fits in the outgoing packet. Both the length and the contents of that cookie come from the peer, and the write happens before certificate authentication completes, so a malicious or compromised server can overwrite memory past the caller supplied TLS packet buffer without presenting a certificate.
Only the client path is affected.
Details
The ServerHello extension parser, _nx_secure_tls_process_serverhello_extensions, checks that the cookie is contained within the received extension and stores both the remote 16 bit length and a pointer to the received bytes in the TLS session. That check validates the received buffer, not the later ClientHello destination.
In the HelloRetry state, _nx_secure_tls_send_clienthello_extensions writes the cookie extension into the second ClientHello with no capacity check. The copy of the cookie body is unchecked, and so are the three two byte header writes that precede it. A later extension may report NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL, but only after memory has already been overwritten.
The cookie block is the only writer in that file which does not consult available_size. Every neighbouring extension builder already bounds its writes, and the DTLS cookie path in _nx_secure_dtls_send_clienthello checks the full ClientHello against the packet’s data end before writing. This block is the lone outlier rather than a gap in an unguarded area.
Increasing the configured TLS packet size does not fix this. The cookie length is a 16 bit value chosen by the peer, so a larger packet raises the threshold without bounding the write.
Impact
A malicious or compromised TLS endpoint controls both the length and the contents of a write past the caller supplied TLS packet pool buffer, before certificate authentication completes.
The reporter demonstrated this reaching control flow. With a one packet static TLS pool followed by an application callback, a cookie byte lands in the callback, where the peer places an address the application subsequently calls. A successful run produces:
ERROR: AddressSanitizer: global-buffer-overflow CHAIN_STAGE2: adjacent callback is now <attacker target> CHAIN_PASS: attacker-selected callback target executed
The demonstration used a 32 bit non position independent test layout. What bounds it is object placement: impact beyond a crash depends on what follows the packet buffer in a given build and on whatever memory protection the platform applies, and no embedded product layout was tested. Our own validation saw both outcomes — one build crashed outright, another corrupted memory silently.
Affected configurations
Exposure requires opting into TLS 1.3. NX_SECURE_TLS_TLS_1_3_ENABLED defaults to 0 and is only set when the integrator defines NX_SECURE_TLS_ENABLE_TLS_1_3, which has been true since v6.0. ECC is the opposite, on by default unless NX_SECURE_DISABLE_ECC_CIPHERSUITE is set. A default build with TLS 1.3 left off is not affected.
The affected configuration is therefore a TLS 1.3 build with ECC ciphersuites enabled, acting as a TLS client, where the configured TLS packet is smaller than the attacker selected cookie plus the other ClientHello fields.
All releases from v6.0_rel through 6.5.1.202602 are affected. The cookie block is byte-identical across that range.
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H, 9.8, Critical.
The vector is scored for a build with TLS 1.3 enabled, as described above. No privileges or user interaction are required because an embedded client reaches this by connecting to its configured endpoint, and the attacker’s position is that endpoint or anyone able to impersonate it.
Patches
Fixed in NetX Duo 6.5.2.202603.
The cookie block now requires six bytes plus the cookie length at the current offset and returns NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL before any write. The reporter’s suggestion to use overflow safe arithmetic is what shipped, in the form of subtracting the offset from available_size rather than adding the 16 bit cookie length to it, since that addition can itself overflow. The fix also clears the cookie pointer and length on every exit from the block, because the pointer aims into the ServerHello packet and must not outlive it.
Separately, the return value of _nx_secure_tls_send_clienthello_key_share_extension was being discarded, leaving the status variable holding the preceding extension’s NX_SUCCESS, so a KeyShare that did not fit was reported as success with a stale extension length. That is now assigned.
A new regression test covers the boundaries the reporter suggested: a 0xFFFF cookie, exact fit, one byte short, a partial header, and a KeyShare that does not fit. Against the unfixed source the 0xFFFF case copies 65535 bytes into a 512 byte buffer and seven assertions fail. With the fix, 155/155 on the TLS 1.3 build and 179/179 on the default build. Not run on hardware.
The cookie copy had no coverage before this. Instrumenting the block and running the whole TLS 1.3 regression suite shows it is entered by exactly one test, the new one. nx_secure_tls_1_3_hello_retry_cookie_test looks like it covers this — it builds a HelloRetryRequest with a cookie and registers a callback to check the cookie is echoed — but its client half never builds a second ClientHello, so the cookie is never copied and that check never runs. That test is being corrected separately.
A related overrun of a different buffer on the same HelloRetryRequest path is addressed separately as GHSA-4x76-j955-qhq2. This fix does not cover it: the bound here is the room left in the outgoing packet, which is larger than the capacity of the handshake message cache that advisory describes.