# REPRO-2026-00141: rsync: off-by-one out-of-bounds stack write in establish_proxy_connection ## Summary Status: published Severity: low Type: security Confidence: Unknown ## Identifiers REPRO ID: REPRO-2026-00141 CVE: CVE-2026-45232 ## Package Name: rsync Ecosystem: c Affected: < 3.4.3 Fixed: 3.4.3 ## Root Cause # RCA Report: CVE-2026-45232 ## Summary CVE-2026-45232 is an off-by-one out-of-bounds stack write vulnerability in the `rsync` utility. The bug resides in `establish_proxy_connection()` within `socket.c`. When rsync connects through an HTTP proxy (configured via `RSYNC_PROXY`), it reads the proxy's `CONNECT` response into a 1024-byte stack buffer. If the proxy returns an overlong response (1023+ bytes without a newline terminator), post-loop null-termination logic writes one byte past the buffer's end, corrupting adjacent stack memory. ## Impact - **Package**: `rsync` (C CLI tool) - **Affected versions**: `< 3.4.2` - **Fixed version**: `3.4.3` - **Risk level**: Low (NVD CVSS 3.1 base 3.1) - **Consequences**: A malicious or MITM'd HTTP proxy can trigger a single-byte stack overwrite, potentially leading to a crash or undefined behavior. The overwritten byte is always a null terminator (`\0`), and the attacker does not control the offset, limiting exploitability. ## Root Cause In `socket.c`, `establish_proxy_connection()` declares a stack buffer `char buffer[1024]` and reads the proxy response one byte at a time into `buffer[0]` through `buffer[1022]`. The loop condition is `cp < &buffer[sizeof buffer - 1]`. If no newline arrives before the buffer is filled, `cp` is left at `&buffer[1023]` (the last valid index). The post-loop code then executes: ```c if (*cp != '\n') cp++; *cp-- = '\0'; ``` Because `*cp` was never written by the loop (it contains stale stack data), the `if` is usually true, so `cp++` advances past the array to `&buffer[1024]`. The subsequent `*cp = '\0'` writes one byte out of bounds. **Fix commit**: `a5fc5ebe7a8ef1aa72f6e344599f97fd4427ecba` ("socket: reject over-long proxy response line") The fix: 1. Increases the buffer size to `PROXY_BUF_SIZE + 1` (1025 bytes) for safe null-termination 2. Adds an explicit check: if `cp == &buffer[PROXY_BUF_SIZE - 1]`, reject with `"proxy response line too long"` instead of writing past the buffer 3. Correctly null-terminates within bounds for shorter responses ## Reproduction Steps 1. `repro/reproduction_steps.sh` clones the rsync repository, checks out `v3.4.2` (vulnerable) and `v3.4.3` (fixed), and builds both with AddressSanitizer (`-fsanitize=address`). 2. It starts a minimal Python TCP mock proxy that binds to a local ephemeral port, accepts one connection, reads the `CONNECT` request headers, and sends exactly 1023 bytes of `'X'` with no newline terminator. 3. It runs `rsync` via `RSYNC_PROXY=127.0.0.1:` against each build. 4. Expected behavior: - **v3.4.2 (vulnerable)**: AddressSanitizer reports `stack-buffer-overflow` at `establish_proxy_connection` (`socket.c:95`), and rsync aborts. - **v3.4.3 (fixed)**: rsync prints `"proxy response line too long"` and exits with error code 10 (non-zero but no crash). ## Evidence - **Log files**: - `logs/rsync_v3.4.2_proxy.log` — ASan output for the vulnerable build - `logs/rsync_v3.4.3_proxy.log` — stderr for the fixed build - **ASan excerpt** (vulnerable build): ``` ==7440==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7f747c600940 WRITE of size 1 at 0x7f747c600940 thread T0 #0 establish_proxy_connection /tmp/.../rsync/socket.c:95 ... Memory access at offset 2368 overflows this variable [1344, 2368) 'buffer' (line 55) ``` - **Fixed build excerpt**: ``` proxy response line too long rsync error: error in socket IO (code 10) at clientserver.c(141) [Receiver=3.4.3] ``` - **Runtime manifest**: `repro/runtime_manifest.json` records build versions, exit codes, ASan excerpt, payload size (1023 bytes), and confirmation flags. ## Recommendations / Next Steps 1. **Upgrade** to rsync `>= 3.4.3` to obtain the bounds-check fix. 2. **Network controls**: Restrict proxy configurations (`RSYNC_PROXY`) to trusted infrastructure to reduce exposure to malicious proxies. 3. **Testing**: The upstream test `testsuite/proxy-response-line-too-long.test` should be included in CI to prevent regression. 4. **Build hardening**: Compile with `-fstack-protector-strong` and ASan in QA pipelines to detect similar stack overwrites early. ## Additional Notes - **Idempotency**: The reproduction script was run twice consecutively; both runs produced identical ASan crashes on `v3.4.2` and clean rejection on `v3.4.3`. - **Payload specifics**: 1023 bytes of `'X'` without a newline is the exact boundary that triggers the off-by-one. A shorter payload does not trigger the bug; a newline-terminated payload exits the read loop early. - **Build environment**: Tested on `x86_64-pc-linux-gnu` with GCC and AddressSanitizer. The bug is architecture-agnostic, but ASan makes the one-byte overwrite reliably observable. ## Reproduction Details Reproduced: 2026-05-22T10:23:58.910Z Duration: 1769 seconds Tool calls: 144 Turns: 117 Handoffs: 2 ## Quick Verification Run one of these commands to verify locally: pruva-verify REPRO-2026-00141 pruva-verify CVE-2026-45232 Or open in GitHub Codespaces (zero-friction, auto-runs): https://github.com/codespaces/new?ref=repro/REPRO-2026-00141&repo=N3mes1s/pruva-sandbox Or download and run the script manually: curl -O https://api.pruva.dev/v1/reproductions/REPRO-2026-00141/artifacts/repro/reproduction_steps.sh chmod +x reproduction_steps.sh ./reproduction_steps.sh WARNING: Run in a sandboxed environment. This exploits a real vulnerability. ## References - NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-45232 - Source: https://github.com/RsyncProject/rsync.git ## Artifacts - repro/rca_report.md (analysis, 4745 bytes) - repro/reproduction_steps.sh (reproduction_script, 5211 bytes) - vuln_variant/rca_report.md (analysis, 7568 bytes) - vuln_variant/reproduction_steps.sh (reproduction_script, 8468 bytes) - bundle/context.json (other, 2982 bytes) - bundle/metadata.json (other, 589 bytes) - bundle/ticket.md (ticket, 3563 bytes) - repro/runtime_manifest.json (other, 914 bytes) - repro/validation_verdict.json (other, 1330 bytes) - vuln_variant/root_cause_equivalence.json (other, 1174 bytes) - vuln_variant/patch_analysis.md (documentation, 3959 bytes) - vuln_variant/variant_manifest.json (other, 2342 bytes) - vuln_variant/runtime_manifest.json (other, 645 bytes) - vuln_variant/validation_verdict.json (other, 2031 bytes) - vuln_variant/source_identity.json (other, 703 bytes) - logs/variant1_vuln.log (log, 567 bytes) - logs/variant2_fixed.log (log, 521 bytes) - logs/variant1_fixed.log (log, 567 bytes) - logs/variant_run1.log (log, 1110 bytes) - logs/variant3_fixed.log (log, 567 bytes) - logs/variant_run3.log (log, 1040 bytes) - logs/variant_run2.log (log, 1041 bytes) - logs/rsync_v3.4.3_proxy.log (log, 526 bytes) - logs/rsync_v3.4.2_proxy.log (log, 3330 bytes) - logs/variant2_vuln.log (log, 3278 bytes) - logs/variant3_vuln.log (log, 567 bytes) ## API Access - JSON: https://api.pruva.dev/v1/reproductions/REPRO-2026-00141 - Script: https://api.pruva.dev/v1/reproductions/REPRO-2026-00141/artifacts/repro/reproduction_steps.sh - Web: https://pruva.dev/r/REPRO-2026-00141 ## For AI Assistants To help users with this reproduction: 1. The `pruva-verify` command is the simplest way to run the reproduction 2. The script downloads and runs automatically in an isolated temp directory 3. Always recommend running in a VM, container, or disposable environment 4. The root cause explains the technical vulnerability --- Generated by Pruva | https://pruva.dev