# Conflux-queued zero-length RELAY_END triggers heap out-of-bounds read

Zero-length RELAY_END copied through Conflux out-of-order queue yields exact-size heap alloc, causing OOB read of msg->body[0] in connection_ap_process_end_not_open.

- Payout: hidden
- Severity: medium
- Program: Tor
- Found by: geeknik
- Disclosed: 2026-09-10
- Write-up quality: 7/10
- Original: https://hackerone.com/reports/3709605
- Library page: https://bugbountylibrary.com/r/h1%3A3709605
- Tags: area:devices domain:network impact:dos kind:bounty platform:hackerone sev:medium tech:linux technique:chained technique:source-review vuln:dos vuln:memory-corruption

**Target:** Tor relay-cell handling / Conflux out-of-order delivery
**Root cause:** connection_ap_process_end_not_open() reads get_uint8(msg->body) before checking msg->length==0; normally masked by relay-cell backing storage, but Conflux's relay_msg_copy() allocates exactly sizeof(relay_msg_t)+length, so body points past the allocation when length is 0.
**Steps:**
1. Build zero-length RELAY_END for a non-open AP stream (e.g. AP_CONN_STATE_CONNECT_WAIT).
2. Pass it through conflux_process_relay_msg() out-of-order queue so relay_msg_copy() makes an exact-size heap copy.
3. Dequeue the heap-backed relay_msg_t and deliver via connection_edge_process_relay_cell().
4. connection_ap_process_end_not_open() calls get_uint8(msg->body) at relay.c:846 before the length check, reading past the 16-byte allocation.
5. Run under ASan: `./src/test/test relaycell/end_cell_conflux_copy_oob` reports heap-buffer-overflow READ of size 1.
**How found:** Code reading: noticed Tor explicitly permits zero-length RELAY_END (treated as END_STREAM_REASON_MISC) but connection_ap_process_end_not_open() reads body[0] before the length check; realized normal relay-cell backing storage masks the OOB, then traced Conflux's relay_msg_copy() exact-size allocation as the path that unmasks it.
**Exploitation:** Attacker acting as relay/exit on a linked Conflux pair sends a zero-length RELAY_END for a stream still in CONNECT_WAIT, with an out-of-order sequence gap forcing the cell through Conflux's copy path; the copied message's body pointer lands just past the heap allocation, and the unguarded read crashes ASan/hardened builds.
**Insight:** When a length check exists but is ordered after a read, look for alternate code paths that change the backing allocation size — copy/serialization paths that allocate exactly msg->length turn a benign over-read into a true heap OOB.
