Case study · rsync
We audited rsync.
rsync ships on virtually every Linux system and has moved the world's files since 1996. Proof audited it continuously through the development of its latest release — and the audit is still running.
01 · The problem
Generic AI review does not survive this codebase.
While this audit ran, rsync's maintainers were drowning in AI-generated review noise. Simple prompts, fed the code, came back with confident findings — non-exploitable edge cases, invented threats — that consumed review time and buried the real work.
rsync is too complex, and too old, for that to ever work.
So we did it differently: every requirement written down, every finding a running check. And the checks found what the noise was hiding:
A hosts-deny rule that failed open
An unresolvable hostname admitted the host it was meant to block. Now fails closed. HIGH · CVE-2026-70452 · fixed in 3.5.0
Control characters, injected into an administrator's terminal
Transferred filenames carried raw control bytes into the log file, ready to fire escape sequences when the log was read. Now escaped. CWE-117 log injection · fixed in 3.5.0
An uninitialized heap byte, handed to the remote shell
A counter and a writer disagreed on a quoted filename; the byte went out with --protect-args off. The counter now mirrors the writer. fixed in 3.5.0
Every item above carries its own entry in the release notes.
02 · The subject
A defect here is not an edge case. It is infrastructure.
rsync moves files inside most backup pipelines, cloud images and deployment scripts. Its core paths have been touched continuously since Andrew Tridgell's first release in 1996 — and virtually every Linux system on earth ships it.
FIRST RELEASE 1996 · AUTHOR ANDREW TRIDGELL · SHIPS ON VIRTUALLY EVERY LINUX SYSTEM · C CODEBASE
03 · The findings
What we found in rsync.
The audit filed 99 findings against rsync; the 3.5.0 security release shipped 33 security fixes. Below is a sample — 6 of the 99: the standout vulnerabilities and the hardening, most of it credited to Leonid Bugaev by name in the release notes — each fixed upstream, each with its own entry there.
A sample · 6 of 99 findings
hosts deny failed open — an unresolvable hostname admitted the host it was meant to block
Receiver ACL/xattr writes followed a symlink race — attacker-chosen ACLs set on files outside the destination tree
Log injection — raw control characters from transferred filenames reached the administrator's terminal
Uninitialized heap byte leaked in a quoted filename, handed to the remote shell
--safe-links bypass through --backup hardlinks · robust_rename() cross-device confinement · MSG_IO_ERROR exit-code masking
clean_fname() dot-dot normalization · .cvsignore clear-list abort · --chmod=a+s setgid bit · wildcard bracket case-folding
This is a sample, not the register. The audit's board runs to 99 findings, counted out in section 06 below. Every one of the 33 security fixes in 3.5.0 carries its own CVE advisory in the release notes, linked again in the receipts at the end.
04 · The method
Every rsync requirement became a tripwire.
Proof formalized rsync's path-handling and daemon-protocol requirements, then turned each one into an executable check against the real code.
The tripwire contract
A tripwire exits 0 while the defect still reproduces. It exits 1 when the fix lands — and then it retires.
Between those two states there is no interpretation. The requirement runs; the code answers.
ASAN HARNESSES · MC/DC HARNESSES · PROPERTY TESTS · MANUAL REVIEW · MERGE REVIEW
MC/DC — modified condition/decision coverage: the strongest structural coverage measure short of formal proof.
05 · Continuous, not one-off
We audited through the whole release.
rsync 3.5.0 took months to develop, and the audit ran through all of it. Every time upstream changed the code, we re-merged it, re-ran the entire tripwire suite, and corrected the record — findings re-checked, fixed ones retired, new ones added. When the release shipped, the record was current.
06 · The numbers
The release, quantified.
security issues fixed in rsync 3.5.0
findings filed by the audit
CVE IDs across the release cycle
33 security issues fixed · 39 CVE IDs across the cycle · shipped 13 Aug 2026
rsync 3.5.0 notes: a focused audit, a daemon-protocol fuzzing pass, and external researchers · each of the 33 fixes carries one CVE ID; the other six of the 39 were fixed mid-development, in the interim 3.4.3 security release
99 findings filed · 45 open · 21 fixed · 28 withdrawn · 5 reviewed
withdrawn — the audit disproved its own finding, the board shrinks honestly · reviewed — re-examined by a person and allowed to stand · the release's 33 fixes include findings from the fuzzing pass and other researchers beyond this audit
13 high · 41 medium · 43 low · 2 low-medium
10 findings present since rsync's inception in 1996
5 fixes authored by Proof · propagated across five maintenance branches
07 · With one of the top audit firms
Two audits are better than one.
Trail of Bits worked on this release with us, through its “Patch the Planet” program. We found issues they didn't. They found issues we didn't. Every one of them made rsync 3.5.0 harder to attack.
That is what a mature security practice looks like — not one audit, but several, checking each other. The collaboration was genuinely good, and rsync is better off for it.
08 · What's next
The rsync audit is now continuous.
The work didn't end with the release. The tripwires stay in place. We are building the standing continuous audit for rsync — code reviews on upstream changes, triage for new findings, and a full re-run of the suite on every release candidate, exactly the way the jsonparser gate runs in CI.
Thirty years of code, kept honest on every change. Watch this page.
09 · The receipts
Don't take this page's word for it.
This is the Continuous Correctness Audit — your component, the same loop, the same receipts. Request demo →