HACKERONE

curl: MQTT Protocol Violation & Integer Overflow in libcurl_H1:3484319

Description

## Executive Summary

**Vulnerability Type:** CWE-190
**Component:** lib/mqtt.c
**Function:** mqtt_decode_len

**Affected Architectures:**
- **All architectures:** Protocol non-compliance leading to stream desynchronization
- **32-bit architectures:** Deterministic integer overflow in length decoding

libcurl does not correctly enforce the MQTT v3.1.1 specification limit for the “Remaining Length” field when decoding incoming packets. This allows malformed MQTT packets to be parsed incorrectly, leading to protocol desynchronization and potential denial of service. On 32-bit systems, the decoding logic additionally allows a deterministic integer overflow.

---

## Root Cause: Inconsistent Length Handling

The issue is caused by an inconsistency within `lib/mqtt.c`.
The encoder correctly enforces the MQTT specification limit, while the decoder does not.

### Correct Behavior (Encoding)

In `mqtt_encode_len`, the implementation explicitly limits the Remaining Length field to four bytes, as required by the specification:

```c
for(i = 0; (len > 0) && (i < 4); i++) {
unsigned char encoded;
encoded = len % 0x80;
/* ... */
}
````

This ensures protocol compliance.

### Incorrect Behavior (Decoding)

In contrast, `mqtt_decode_len` does not enforce the same limit:

```c
for(i = 0; (i < buflen) && (encoded & 128); i++) {
encoded = buf[i];
len += (encoded & 127) * mult;
mult *= 128;
}
```

The loop continues as long as the continuation bit is set and input is available, allowing more than four bytes to be consumed as part of the Remaining Length field.

---

## Specification Violation

According to the MQTT v3.1.1 specification, Section 2.2.3 (Remaining Length):

> “The number of bytes in the Remaining Length field MUST NOT exceed four bytes.”

By accepting and processing length fields longer than four bytes, libcurl violates the MQTT specification and enters an undefined protocol state.

---

## Integer Overflow on 32-bit Systems

On 32-bit architectures, `size_t` is a 32-bit unsigned integer.
The variable `mult` is repeatedly multiplied by 128 during decoding.

Example progression on a 32-bit system:

| Iteration | mult value | Operation | Result |
| --------: | ----------- | --------- | ---------------- |
| 0 | 1 | 1 × 128 | 128 |
| 1 | 128 | 128 × 128 | 16,384 |
| 2 | 16,384 | × 128 | 2,097,152 |
| 3 | 2,097,152 | × 128 | 268,435,456 |
| 4 | 268,435,456 | × 128 | **Overflow → 0** |

After the overflow, `mult` becomes zero, and any further bytes consumed contribute nothing to the decoded length. This allows a large or malformed Remaining Length field to be partially “hidden” while still advancing the input pointer.

---

## Impact

# Impact

### Protocol Desynchronization (All Architectures)

By consuming more than four bytes for the Remaining Length field, libcurl can become desynchronized from the MQTT stream. Bytes intended to be part of the payload or subsequent packets may instead be interpreted as length data, causing incorrect parsing of later packets.

### Denial of Service

This desynchronization can result in malformed packet handling, unexpected connection termination, or repeated protocol errors such as `CURLE_WEIRD_SERVER_REPLY`.

No memory corruption or code execution is claimed.

---

## Recommended Fix

The decoding logic should explicitly enforce the four-byte limit defined by the MQTT specification.

Example fix:

```c
for(i = 0; (i < buflen) && (encoded & 128); i++) {
if(i >= 4) {
/* Malformed Remaining Length */
return 0; /* or propagate an error to the caller */
}
encoded = buf[i];
len += (encoded & 127) * mult;
mult *= 128;
}
```

Optionally, the decoded length can also be checked against the implementation limit:

```c
if(len > MAX_MQTT_MESSAGE_SIZE)
return 0;
```

---

## Verification Notes

The issue was verified through code inspection and logic simulation, confirming that `mqtt_decode_len` accepts more than four bytes for the Remaining Length field and allows arithmetic overflow on 32-bit systems. Runtime exploitation was not required to demonstrate the protocol violation.

---

## Conclusion

This is a protocol parsing bug caused by missing enforcement of a mandatory MQTT specification limit. While it does not directly result in memory corruption, it allows malformed MQTT packets to desynchronize the client’s protocol state and cause denial of service. Aligning the decoder with the existing encoder logic resolves the issue cleanly.

```
Visit Original Source

Basic Information

ID H1:3484319
Published Jan 1, 2026 at 21:51
Modified Jan 1, 2026 at 22:50

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.