MQTT state machine confusion: PINGRESP/DISCONNECT with non-zero remaining_length dispatches to stale nextstate
Medium
Vulnerability Details
## Summary:
In `lib/mqtt.c`, the state machine in `mqtt_doing` (lines 894-911 in curl 8.20.0) does not validate that PINGRESP (0xD0) and DISCONNECT (0xE0) packets have `remaining_length == 0` as required by MQTT 3.1.1 spec sections 3.13.1 and 3.14.1. A malicious broker can send a PINGRESP fixed header with non-zero remaining_length followed by trailing bytes, and the state machine will dispatch to whatever `mqtt->nextstate` was set to from a previous cycle (typically MQTT_PUBWAIT after a SUBSCRIBE) and parse the trailing bytes as that state's payload. Depending on `nextstate`, this allows a malicious broker to inject PUBLISH payload data, fake a SUBACK/CONNACK, or otherwise corrupt the client's protocol state. A patch is available at https://github.com/GovClawAPI/curl/commit/7ad90263bc which validates remaining_length == 0 for both packet types before state dispatch and returns CURLE_WEIRD_SERVER_REPLY on violation.
## Affected version
curl 8.20.0 (the current stable release at time of audit). The affected code in `lib/mqtt.c:894-911` appears unchanged in current main. Built and tested on Linux x86_64.
## Steps To Reproduce:
1. Run a malicious MQTT broker that completes the standard CONNECT/CONNACK and SUBSCRIBE/SUBACK handshake with a curl client.
2. After the SUBACK, instead of a normal PUBLISH or PINGRESP, send the bytes `0xD0 0x02 0x00 0x00` (PINGRESP fixed header claiming remaining_length=2, plus two payload bytes).
3. Observe that curl does not reject the malformed PINGRESP. The state machine consumes the two trailing bytes as the start of the next expected message (typically the variable-header of a PUBLISH), corrupting subsequent message parsing.
4. The same applies to DISCONNECT (0xE0) packets with non-zero remaining_length.
## Again: there is no bug-bounty for curl. We do not offer any rewards, only proper credits.
## Impact
## Summary:
A malicious or compromised MQTT broker can cause protocol-level state confusion in curl's MQTT client. The trailing bytes from a malformed PINGRESP or DISCONNECT are interpreted as the payload of whatever state was queued in `mqtt->nextstate`. Concrete consequences depending on the queued state: trailing bytes parsed as PUBLISH payload allow the broker to inject arbitrary content into the client's receive callback; trailing bytes parsed as SUBACK can cause the application to believe a subscription was confirmed when it was not; trailing bytes parsed as CONNACK can cause incorrect connection-state assumptions. The exposure is to MQTT clients connecting to untrusted or compromised brokers, which is a realistic threat model for MQTT given its common deployment across IoT and edge environments.
Actions
View on HackerOneReport Stats
- Report ID: 3702718
- State: Closed
- Substate: informative
- Upvotes: 2