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

CVE-2026-70452

hosts deny failed open — an unresolvable hostname admitted the host it was meant to block

highfixed

CVE-2026-53799

Receiver ACL/xattr writes followed a symlink race — attacker-chosen ACLs set on files outside the destination tree

mediumfixed

CWE-117

Log injection — raw control characters from transferred filenames reached the administrator's terminal

fixed

safe_arg()

Uninitialized heap byte leaked in a quoted filename, handed to the remote shell

fixed

hardening

--safe-links bypass through --backup hardlinks · robust_rename() cross-device confinement · MSG_IO_ERROR exit-code masking

fixed

bugs

clean_fname() dot-dot normalization · .cvsignore clear-list abort · --chmod=a+s setgid bit · wildcard bracket case-folding

fixed

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.

REQUIREMENTS TRIPWIRES RUN UPSTREAM MOVES RECORD CORRECTED STILL TRUE? FIXES RETIRE
Fig. 01 · The policy upstream accepted into its own release process — requirements become tripwires, every upstream change re-runs them, the record corrects itself, fixed findings retire: “Every fix ships with a regression test in the test suite that fails on the unfixed tree.” — rsync 3.5.0 release notes

06 · The numbers

The release, quantified.

33

security issues fixed in rsync 3.5.0

99

findings filed by the audit

39

CVE IDs across the release cycle

RELEASE

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

AUDIT

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

SEVERITY

13 high · 41 medium · 43 low · 2 low-medium

AGE

10 findings present since rsync's inception in 1996

SUBMITTED

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 →