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.
```
**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.
```
Basic Information
ID
H1:3484319
Published
Jan 1, 2026 at 21:51
Modified
Jan 1, 2026 at 22:50