# CVE-2021-22945: UAF and double-free in MQTT sending

libcurl MQTT send path frees mq->sendleftovers without nulling it, causing use-after-free and double-free when a partial write leaves nsend set.

- Payout: hidden
- Severity: medium
- Program: curl
- Found by: z2_
- Disclosed: 2021-09-15
- CVE: CVE-2021-22945
- Write-up quality: 7/10
- Original: https://hackerone.com/reports/1269242
- Library page: https://bugbountylibrary.com/r/h1%3A1269242
- Tags: area:oss domain:oss impact:data-leak kind:bounty platform:hackerone sev:medium tech:curl technique:incomplete-fix technique:source-review vuln:dos vuln:memory-corruption

**Target:** libcurl MQTT protocol handler (lib/mqtt.c mqtt_doing)
**Root cause:** mqtt_doing frees mq->sendleftovers after a partial send but never resets mq->sendleftovers or mq->nsend, so a subsequent invocation re-sends and re-frees the same chunk.
**Steps:**
1. Checkout curl-7_77_0
2. Patch Curl_write to force bytes_written=0 once, simulating EAGAIN/EWOULDBLOCK partial write
3. Rebuild curl
4. Run `nc -lp 5678`
5. Run `curl mqtt://127.0.0.1:5678/`
6. Observe `free(): double free detected in tcache 2` and freed chunk contents sent to netcat
**How found:** Code reading of mqtt_doing lines 556-563 spotted the free without NULL assignment, then traced where nsend/sendleftovers are set in mqtt_send on short writes (EAGAIN/EWOULDBLOCK) to build the trigger sequence.
**Exploitation:** Trigger a partial MQTT write so mq->sendleftovers/nsend are set; next mqtt_doing frees the buffer, and a further call re-sends freed heap contents over the socket and frees again. On glibc <2.29 tcache double-free is exploitable; at minimum leaks heap metadata.
**Insight:** When auditing send/recv state machines, check that buffers freed after partial I/O also reset the associated length/count fields; a stale count re-enters the free path. Force short writes (EAGAIN) to exercise these branches.
