Executive Summary & Critical Infrastructure Exposure
The Cybersecurity and Infrastructure Security Agency (CISA) has released advisory ICSA-26-265-01 warning of a critical remote code execution vulnerability in the lwIP (Lightweight IP) TCP/IP Stack MQTT Client Application. Tracked under the identifier CVE-2026-87121, the flaw carries a near-maximum Common Vulnerability Scoring System (CVSS v3.1) base score of 9.8 (Critical) with the vector string:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
The defect is classified under CWE-787: Out-of-bounds Write. lwIP is the foundational networking library embedded within millions of real-time operating system (RTOS) implementations, smart electric utility meters, industrial programmable logic controllers (PLCs), solar inverters, and automotive telematics control units (TCUs).
The built-in MQTT (Message Queuing Telemetry Transport) client module (apps/mqtt/mqtt.c) is widely used by embedded field devices to publish operational sensor metrics and subscribe to command topics hosted on cloud brokers (such as AWS IoT Core, Azure IoT Hub, or private Mosquitto servers). Because CVE-2026-87121 allows an unauthenticated remote adversary—or an attacker who has compromised an intermediate MQTT broker—to achieve unrestricted remote code execution directly within the physical memory space of the controller, the flaw represents an acute risk to critical infrastructure reliability.
Vulnerability Taxonomy & Affected Components
The out-of-bounds write defect is present across all lwIP installations implementing MQTT Client Application versions 2.0.1 through 2.2.1:
| Firmware Component & Target | Vulnerable Versions | Remediation Baseline | Operational Exposure Risk |
|---|---|---|---|
| lwIP MQTT Client (apps/mqtt/mqtt.c) | v2.0.1 through v2.2.1 | lwIP Git Master / Upstream Commit Patch | Full remote code execution via malformed broker PUBLISH packet |
| Smart Energy & Advanced Metering (AMI) | Grid meters utilizing lwIP MQTT telemetry | OEM over-the-air (OTA) cryptographic firmware update | Grid meter tampering, unauthorized remote service disconnects |
| Industrial IoT Edge Gateways (Purdue L1/L2) | Sensors streaming Modbus-to-MQTT bridges | Vendor board support package (BSP) reflash | Subversion of plant sensor telemetry, false data injection (FDI) |
| Automotive & Fleet Telematics Units | Cellular telematics modules communicating via MQTT | Vehicle ECU firmware update / Secure gateway patch | CAN bus command injection via compromised telematics microcontroller |
Root Cause Dissection: Out-of-Bounds Buffer Write in mqtt.c (CWE-787)
In the MQTT protocol specification, a PUBLISH control packet delivers application messages across topics. The variable header of a PUBLISH packet contains a two-byte length field followed by the Topic Name string, followed by a Packet Identifier (for QoS > 0), followed by the binary application payload.
When the lwIP MQTT client receives incoming packets from a network broker, the internal state machine parses the stream within mqtt_parse_incoming() and dispatches the topic name and payload chunks to the application callback registered by the user.
// Vulnerable logic pattern in apps/mqtt/mqtt.c:
static err_t mqtt_parse_incoming(mqtt_client_t *client, struct pbuf *p)
{
u16_t topic_len;
/* Read 2-byte topic length prefix from variable header */
topic_len = (u16_t)pbuf_get_at(p, offset) << 8 | pbuf_get_at(p, offset + 1);
offset += 2;
/* FLAW: Insufficient validation verifying topic_len against client->msg_idx
and maximum static buffer allocations (MQTT_VAR_HEADER_BUFFER_LEN) */
// Memory copy without boundary enforcement:
pbuf_copy_partial(p, client->rx_buffer, topic_len, offset); // OUT-OF-BOUNDS WRITE
client->rx_buffer[topic_len] = ' '; // Null-byte write outside buffer boundary
return ERR_OK;
}
If an adversary sends a crafted PUBLISH packet where topic_len exceeds the bounds of client->rx_buffer (or where the packet is segmented across multiple TCP packet buffers with mismatched length offsets), pbuf_copy_partial() copies arbitrary bytes beyond the end of the allocated buffer.
Furthermore, the trailing null-byte write (client->rx_buffer[topic_len] = ' ') allows an attacker to corrupt adjacent memory pointers, including function pointers registered for the MQTT message received callback (client->data_cb).
Industrial Exploitation Dynamics & Attack Scenarios
Exploitation can be mounted through two primary threat scenarios:
Scenario A: Malicious / Compromised MQTT Broker
[Adversary Hijacks Cloud Broker (Mosquitto / HiveMQ)]
|
| 1. Broadcasts crafted PUBLISH packet on subscribed wildcard topic (#)
| 2. Packet contains topic_len = 0xFFFF (65,535 bytes) with shellcode payload
v
[Distributed Fleet of 10,000+ Field Smart Meters / RTUs]
|
| 3. lwIP mqtt.c processes incoming packet; buffer overflow occurs
| 4. Function pointer client->data_cb overwritten with payload address
v
[Simultaneous Fleet-Wide Takeover / Grid Microcontroller Hijack]
Scenario B: Man-in-the-Middle (MitM) on Unencrypted MQTT (TCP 1883)
[Local Field Attacker / Rogue Wi-Fi Bridge]
|
| 1. Injects TCP packet into unencrypted MQTT session on port 1883
| 2. Spoofs broker IP and SEQ number, delivering payload
v
[Target Water Treatment PLC / Solar Inverter Controller]
Remediation & Defense-in-Depth Checklist
Asset owners and firmware developers must execute the following remediation roadmap immediately:
1. Apply Upstream lwIP Source Patch
Integrate the upstream bounds validation patch into apps/mqtt/mqtt.c:
// Corrected logic verifying topic length against internal buffer capacity:
if (topic_len >= sizeof(client->rx_buffer)) {
/* Reject packet and disconnect malicious session */
mqtt_close(client, MQTT_CONNECT_DISCONNECTED);
return ERR_VAL;
}
2. Enforce Mutual TLS (mTLS) on All MQTT Connections
Disable cleartext MQTT communication on TCP port 1883. Mandate MQTT over TLS (port 8883) utilizing X.509 client and server certificates. This prevents network adversaries from executing packet injection or spoofing broker responses.
3. Snort / Suricata Industrial IDS Detection Rule
Deploy network signatures to detect oversized MQTT topic strings traversing operational networks:
alert tcp any 1883 -> $HOME_NET any ( msg:"CST THREAT-ALERT: lwIP MQTT Oversized Topic Length RCE Probe (CVE-2026-87121)"; flow:from_server,established; content:"|30|"; offset:0; depth:1; byte_test:2,>,1024,2; classtype:attempted-admin; sid:202687121; rev:1;)



