Skip to content

Auto-port 5.0: MQTT: Reject malformed no-payload packets with non-zero Remaining Length#16889

Merged
chrisvest merged 2 commits into
5.0from
auto-port-pr-16852-to-5.0
Jun 4, 2026
Merged

Auto-port 5.0: MQTT: Reject malformed no-payload packets with non-zero Remaining Length#16889
chrisvest merged 2 commits into
5.0from
auto-port-pr-16852-to-5.0

Conversation

@netty-project-bot

Copy link
Copy Markdown
Contributor

Auto-port of #16852 to 5.0
Cherry-picked commit: d89cf88


Motivation:

MqttDecoder.decodePayload's default branch returns null for payload-less message types (PINGREQ, PINGRESP, DISCONNECT, AUTH, CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP) without checking that bytesRemainingInVariablePart is 0. A fixed header that claims a non-zero Remaining Length for one of these types is silently accepted, and the leftover bytes are interpreted as another packet.

The reporter's exact repro from #16851 is C0 02 D0 00: a PINGREQ with Remaining Length 2 (invalid per MQTT 3.1.1 and MQTT 5.0, which both require Remaining Length 0 for PINGREQ) is currently decoded as a valid PINGREQ followed by a valid PINGRESP.

Modification:

Call validateNoBytesRemain(0) at the start of the default branch. The helper — already used by the SUBSCRIBE and UNSUBSCRIBE payload decoders — subtracts 0 from bytesRemainingInVariablePart and throws DecoderException when the result is non-zero, surfacing a single invalid message instead of letting leftover bytes leak into the next decode pass.

Added MqttCodecTest#testPingReqWithNonZeroRemainingLengthIsRejected that feeds the reporter's exact byte sequence and verifies a single failed message is produced. Confirmed it fails on the unfixed code (expected: <true> but was: <false>) and passes with the fix; all 112 codec-mqtt tests pass locally.

Result:

Malformed payload-less MQTT frames are flagged as a single invalid message rather than allowed to silently spill into the next packet. The fix applies uniformly to every message type that goes through the default branch.

Fixes #16851.

…gth (#16852)

Motivation:

`MqttDecoder.decodePayload`'s `default` branch returns `null` for
payload-less message types (`PINGREQ`, `PINGRESP`, `DISCONNECT`, `AUTH`,
`CONNACK`, `PUBACK`, `PUBREC`, `PUBREL`, `PUBCOMP`) without checking
that `bytesRemainingInVariablePart` is `0`. A fixed header that claims a
non-zero Remaining Length for one of these types is silently accepted,
and the leftover bytes are interpreted as another packet.

The reporter's exact repro from #16851 is `C0 02 D0 00`: a `PINGREQ`
with Remaining Length `2` (invalid per [MQTT
3.1.1](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html)
and [MQTT
5.0](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html),
which both require Remaining Length `0` for `PINGREQ`) is currently
decoded as a valid `PINGREQ` followed by a valid `PINGRESP`.

Modification:

Call `validateNoBytesRemain(0)` at the start of the `default` branch.
The helper — already used by the `SUBSCRIBE` and `UNSUBSCRIBE` payload
decoders — subtracts `0` from `bytesRemainingInVariablePart` and throws
`DecoderException` when the result is non-zero, surfacing a single
invalid message instead of letting leftover bytes leak into the next
decode pass.

Added `MqttCodecTest#testPingReqWithNonZeroRemainingLengthIsRejected`
that feeds the reporter's exact byte sequence and verifies a single
failed message is produced. Confirmed it fails on the unfixed code
(`expected: <true> but was: <false>`) and passes with the fix; all 112
`codec-mqtt` tests pass locally.

Result:

Malformed payload-less MQTT frames are flagged as a single invalid
message rather than allowed to silently spill into the next packet. The
fix applies uniformly to every message type that goes through the
`default` branch.

Fixes #16851.

---------

Co-authored-by: Norman Maurer <norman_maurer@apple.com>
Co-authored-by: Chris Vest <christianvest_hansen@apple.com>
(cherry picked from commit d89cf88)
@chrisvest chrisvest merged commit e44bb27 into 5.0 Jun 4, 2026
11 of 13 checks passed
@chrisvest chrisvest deleted the auto-port-pr-16852-to-5.0 branch June 4, 2026 19:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants