Skip to content

Validate decrypted PATH path_len against MAX_PATH_SIZE#1662

Open
weebl2000 wants to merge 1 commit intomeshcore-dev:devfrom
weebl2000:fix/path-len-max-size
Open

Validate decrypted PATH path_len against MAX_PATH_SIZE#1662
weebl2000 wants to merge 1 commit intomeshcore-dev:devfrom
weebl2000:fix/path-len-max-size

Conversation

@weebl2000
Copy link
Copy Markdown
Contributor

@weebl2000 weebl2000 commented Feb 11, 2026

Severity: High

Summary

The path_len field inside decrypted PATH payloads is validated against the decrypted buffer size (by #1654) but not against MAX_PATH_SIZE (64). A malicious contact can craft a PATH packet where the inner path_len encodes up to 189 bytes of path data (e.g. path_len = 0xBF: hash_size=3, hash_count=63). This passes #1654's payload-length check (the decrypted buffer can hold ~176 bytes) but far exceeds the 64-byte out_path[] and path[] buffers used downstream.

Actual impact (traced through full code flow)

The out_path[64] struct overflow described originally is mitigated by an existing check in Packet::writePath(), which returns 0 without writing if hash_count * hash_size > MAX_PATH_SIZE. However, Packet::copyPath() ignores that return value and always returns the raw path_len, so:

  1. Corrupt out_path_len metadata — all onPeerPathRecv implementations store the return value of copyPath into client->out_path_len / from.out_path_len. When writePath silently rejects the oversized path, out_path_len is set to the attacker's value (e.g. 189) while out_path[] contains stale data. Subsequent sends to this contact use the corrupt out_path_len, producing malformed packets on the wire (path_len header claims many hashes, no actual path data follows).

  2. sendDirect TRACE branch: real buffer overflow — the TRACE branch does an unbounded memcpy(&packet->payload[packet->payload_len], path, path_len) without checking payload_len + path_len <= sizeof(packet->payload). While not directly reachable from the PATH receive handler, sendDirect is called from many places and this is a genuine overflow of payload[184].

  3. sendDirect non-TRACE branch: malformed packetcopyPath catches the write via writePath but stores the bogus path_len in packet->path_len, producing a corrupt packet.

Who can exploit this: any peer in your contacts list (they need a shared key for the MAC/decryption to pass).

What it takes: a single crafted PATH packet over RF.

What users might see

A malicious contact could corrupt a node's routing state for the affected contact (stale/garbage path used for all subsequent sends), cause malformed packets to propagate through the mesh, or potentially crash the node via the TRACE sendDirect overflow path.

Fix

  • Add hash_size * hash_count > MAX_PATH_SIZE check in onRecvPacket after parsing path_len from the decrypted PATH payload, rejecting the packet before it flows into onPeerPathRecv or sendDirect
  • Add bounds check in sendDirect TRACE branch: payload_len + path_len > sizeof(packet->payload) → free packet and return
  • Add path_len > MAX_PATH_SIZE guard in sendDirect non-TRACE branch as defense-in-depth

Note: copyPath return value bug

Packet::copyPath() always returns the raw path_len even when writePath() rejected the write. This PR's early-reject in onRecvPacket prevents exploitation via the PATH vector, but the copyPath API remains a footgun for future callers. A follow-up fix would be:

uint8_t Packet::copyPath(uint8_t* dest, const uint8_t* src, uint8_t path_len) {
    return writePath(dest, src, path_len) ? path_len : 0;
}

Test plan

  • Normal PATH packet exchange still works (discovery, direct path return)
  • No regressions in flood/direct routing
  • Build tested on Heltec_v3_companion_radio_ble

Build firmware: Build from this branch

@weebl2000 weebl2000 force-pushed the fix/path-len-max-size branch 2 times, most recently from 5e59b41 to 914b024 Compare February 26, 2026 22:21
@weebl2000 weebl2000 force-pushed the fix/path-len-max-size branch 2 times, most recently from d46fd6f to dd5c0a0 Compare March 3, 2026 14:41
@weebl2000 weebl2000 force-pushed the fix/path-len-max-size branch from dd5c0a0 to 82573b6 Compare March 23, 2026 13:28
The path_len field inside decrypted PATH payloads was validated against
the decrypted buffer size but not against MAX_PATH_SIZE (64). A malicious
contact could send a PATH packet with path_len up to 178, overflowing
out_path[64] in onPeerPathRecv and packet->path[64] in sendDirect.

Add a MAX_PATH_SIZE check after parsing path_len from the decrypted
PATH payload. Also add defensive bounds checks in sendDirect for both
the TRACE payload-append path and the normal path-copy path.
@weebl2000 weebl2000 force-pushed the fix/path-len-max-size branch from 82573b6 to 33868dc Compare April 4, 2026 11:19
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.

1 participant