GHSA-9v23-qwp9-2q3h: NetX Duo MQTT client leaks one receive packet per malformed PUBLISH

GHSA ID

GHSA‑9v23‑qwp9‑2q3h

CVE ID

CVE‑2026‑102762

Severity

Medium

CVSS score

5.9 (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H)

CWE

CWE-401

Published

2026‑10‑02

Last updated

2026‑10‑02

Affected packages

Package Vulnerable versions Patched versions

NetX Duo

>= 6.0, ⇐ 6.5.1.202602

6.5.2.202603

Description

Summary

The NetX Duo MQTT client leaks the packet carrying a malformed PUBLISH message. Each malformed PUBLISH costs one packet, or one chain of packets, from the network driver’s receive pool, and nothing returns it. A peer that can deliver a few dozen such messages exhausts the pool and stops all inbound network traffic on the device until it is rebooted.

Details

_nxd_mqtt_process_publish() returns NX_TRUE when it has taken ownership of the packet, NX_FALSE when it has not, and NXD_MQTT_INVALID_PACKET when the PUBLISH is malformed: a remaining length below 2, a topic length that runs past the end of the message, or a QoS 1 or 2 message with no room for the packet identifier.

Its caller, _nxd_mqtt_packet_receive_process(), stored the return value directly in packet_consumed and released the packet only when that value was zero. NXD_MQTT_INVALID_PACKET is non-zero, so a malformed PUBLISH was treated as consumed: parsing stopped, the release was skipped, and no queue or other structure held a reference to the packet.

The leaked packet is the one the client received, before any copy into the MQTT client’s own pool, so it comes from the pool the network driver receives into, which is usually the IP instance’s default pool. The path is the same over plain TCP, TLS and WebSocket. The smallest malformed message is three bytes: 30 01 00.

Impact

An attacker gets a persistent denial of service. The exhausted pool is normally the one every inbound packet on the IP instance is received into, so not only MQTT stops: every other protocol on the device stops receiving as well. The pool does not recover while the device keeps running. Confidentiality and integrity are not affected.

The attacker must be the broker the client is connected to, or, on a plain TCP connection, able to inject data into that TCP stream. A conforming broker parses every PUBLISH it receives and re-encodes the ones it forwards, so another client of the same broker cannot deliver malformed framing through it.

Affected configurations

Every build of the MQTT client add-on (addons/mqtt), in every configuration: plain TCP, TLS (NX_SECURE_ENABLE), WebSocket (NXD_MQTT_OVER_WEBSOCKET) and the cloud module build (NXD_MQTT_CLOUD_ENABLE).

All NetX Duo releases from 6.0 up to and including 6.5.1.202602. The defect has been present since the first public release of the MQTT client.

Severity

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H, 5.9 (Medium).

Attack complexity is High because the attacker has to be the broker the device chose to connect to, or on the network path between them; a broker cannot be made to relay the malformed message from somewhere else. No privileges are required of an on-path attacker on a plain connection.

Patches

Fixed in NetX Duo 6.5.2.202603. _nxd_mqtt_packet_receive_process() treats a packet as consumed only when _nxd_mqtt_process_publish() returns NX_TRUE. On NXD_MQTT_INVALID_PACKET it stops parsing the rest of the chain and releases the packet. It does not skip the malformed message and carry on with the next one, because MQTT 3.1.1 section 4.8 expects a client to treat a malformed packet as a protocol error. Well-formed PUBLISH messages are handled exactly as before.

A regression test sends one PUBLISH for each of the three malformed forms, followed by a well-formed one, over plain TCP and over TLS. It checks that only the well-formed message is delivered, that the client keeps receiving, and that the packet pool is full once the client is deleted. Without the fix it fails the pool check in both configurations.

Workarounds

None that remove the defect. Connecting over TLS and verifying the broker’s certificate removes the on-path attacker and leaves only a malicious or compromised broker able to trigger it.

Credits

Reported and fixed by Edouard Malot (@EdouardMALOT) in eclipse-threadx/netxduo#438. The review of the fix and the analysis in this advisory were produced with AI assistance under human review, in accordance with the Eclipse Foundation’s Generative AI Usage Guidelines.