Case study · rsync
99 findings filed against rsync. Ten had been there since 1996.
Proof ran continuously through the 3.5.0 release cycle. The complete board — including 28 findings we later withdrew — is public, and every fixed issue is tied to upstream evidence.
01 · The problem
A flood of reports, many of them AI-generated.
While this audit ran, rsync’s maintainer described the incoming load in public: Many of those reports are AI generated (not all though, there are some notable ones with very careful and high quality manual analysis).
Reading a report, reproducing it and disproving it costs maintainer time whether the report holds up or not.
Andrew Tridgell, rsync and outrage, 3 June 2026, as reported by LWN.
Nothing this audit filed had to be taken on trust.
Every requirement was written down, and every finding became a check that runs. Here is what the checks found:
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 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. It is widely shipped across Linux and Unix systems.
FIRST RELEASE 1996 · AUTHOR ANDREW TRIDGELL · WIDELY SHIPPED ON LINUX AND UNIX · C CODEBASE
03 · The findings
What the audit found.
The audit filed 99 findings. The 3.5.0 release shipped 33 security fixes from the combined focused audit, daemon-protocol fuzzing, Trail of Bits work, and other external research. Below are six of this audit's own 99: the standout vulnerabilities and the hardening, each fixed upstream and each with its own entry in the release notes.
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, setting attacker-chosen ACLs 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 · cross-device confinement in the rename path · 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. The audit's board runs to 99 findings, counted out below. Every one of the 33 security fixes in 3.5.0 carries its own CVE advisory in the release notes; those 33 came from the combined focused audit, daemon-protocol fuzzing, Trail of Bits work, and other external research.
04 · The method
Every requirement became an executable 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 temporary state
While the defect is live, the tripwire pins the broken behaviour and exits 0, so the finding has a running witness. When the fix lands the pin stops holding, the tripwire exits 1, and it is rewritten into a regression test that asserts the fixed behaviour from then on.
While the bug is live the test asserts the broken output. Exit 0 means the defect still reproduces.
At the fix the assertion fails. Exit 1 is the signal that the defect is gone.
After the fix the same file is flipped to assert the correct output and stays in the suite as a regression test.
So no test in this suite claims a bug is correct. A pinned assertion is a detector with an expiry date, and the flip is recorded on the finding.
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
The audit moved with the 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 board shrank when the evidence changed.
The audit disproved 28 of its own findings during the release cycle. Each one stays on the board with the evidence that overturned it, because a register that only ever grows has been edited.
findings filed by this audit
Every one carried a reproducer before it was filed.
findings the audit later withdrew
Taken back by the audit itself, and still published.
findings present since rsync's first release in 1996
Ten of the 99 sit in code paths that have been there since the first 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
99 findings filed · 45 open · 21 fixed · 28 withdrawn · 5 reviewed
board read 30 August 2026; the audit is still running, so open and fixed move · withdrawn: the audit disproved its own finding, and 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 from researchers beyond this audit
13 high · 41 medium · 43 low · 2 low-medium
our assessment, weighted by reachability and impact; a starting point for the maintainers' triage, and no CVSS determination
5 fixes authored by Proof · propagated across five maintenance branches
07 · Where the findings came from
Different methods found different things.
Four efforts hardened rsync 3.5.0, and the release notes credit all of them.
This audit formalized rsync's path-handling and daemon-protocol requirements, then ran each one as a tripwire against every upstream change. It filed 99 findings.
A daemon-protocol fuzzing pass reached protocol states no written requirement had named. Some of the release's fixes came from there, and none of them are counted as ours.
Trail of Bits worked this release alongside us through its “Patch the Planet” program. We found issues they did not. They found issues we did not.
Independent researchers reported through the upstream process on their own timetable, and their findings sit in the same release notes.
Each method has a blind spot the others cover. That is what a mature security practice looks like: several efforts, checking each other. The collaboration was good, and rsync is better off for it.
The release notes name the reporter behind each fix. The entries for this audit's findings name Leonid Bugaev, who validated every one of them before it was filed upstream.
08 · What's next
The audit is still running.
The work did not 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, the way the jsonparser gate runs in CI.
Thirty years of code, kept honest on every change. Watch this page.
09 · The receipts
Open the receipts.
Do not take this page's word for any of it. The board, the withdrawals and the upstream fixes are all published where you can read them.
This is the Continuous Correctness Audit, run on your component: the same loop, the same receipts. Request demo →