What a PrivHaven report actually proves
“I removed the personal data, but I cannot show anyone what was removed or prove it later.”
Removing personal data from a file is the easy half. The hard half arrives later, when somebody asks what you removed, from which version of the file, and how you know.
"I ran a tool on it" is not an answer anyone can check. This is what PrivHaven records instead, and, just as importantly, what that record does not amount to.
The problem with a report that just lists findings
A list of findings is only as good as your ability to reproduce it. Run the same tool on the same file six months later and you might get a different list, for reasons that have nothing to do with the data:
- the tool updated and its rules changed
- someone added a custom rule and forgot
- the findings came back in a different order because the file was read in a different number of chunks
None of those are errors. All of them make the old report unverifiable, because you can no longer tell whether a difference means the data changed or the tool did.
What gets recorded
Every report carries a core record with four identifying parts.
The engine. A version string and the SHA-256 of the WebAssembly module. The page computes that hash over the exact bytes it instantiated, so the report names the code that ran rather than the code we intended to ship. A malformed value is ignored rather than stored, so a bad call cannot put a fake hash into a report.
The input. The SHA-256 of the file and its length in bytes. Not the filename, which anyone can change, and which tells you nothing about content.
The ruleset. A version and hash, plus a separate hash of your custom rules if you have any. That last one matters more than it looks. A report produced with custom rules is not reproducible unless the custom rules are identified too, so leaving them out would quietly make a subset of reports unverifiable while looking complete.
The run. Whether it was a scan or a scrub, and which inputs it covered.
Why the ordering rules exist
Findings are sorted by type, then by column, before anything is hashed. They are deliberately not left in detection order.
Detection order is an artefact of how the file happened to be read. Feed the same CSV in two chunks instead of five and the same findings arrive in a different sequence. If the report hash covered that sequence, two identical scans of an identical file would produce two different hashes, and the hash would be worthless as an identifier.
The canonical form also sorts keys and contains no floating point numbers. Floats are excluded because their text representation varies between platforms and serialisers, which is the same failure in a subtler form.
The result is that the report hash is a SHA-256 over a form that depends on the findings and nothing else. Same engine, same rules, same bytes, same hash.
The chain
Each report also links to the previous entry in your local audit log, by hashing the previous link together with the current report's core hash.
That gives an append-only structure. Changing an old report changes its hash, which breaks every link after it, so an alteration shows up as a chain that no longer joins rather than as a document that quietly reads differently.
The whole thing is computed locally and there is no key involved.
What this does not prove
That last sentence is the important one, and it is where most write-ups of a feature like this would stop and let you assume more than is true.
No key means this is not a signature. The chain is tamper evident, not tamper proof. It will catch a report edited after the fact, because the links stop matching. It will not stop somebody who holds the entire log from recomputing every link so that the chain is consistent again. If you need a guarantee against a motivated insider rather than against accident and drift, you need a countersignature from something outside the machine, and PrivHaven does not provide one.
The engine hash attests, it does not certify. It tells you which module this page instantiated. Its value is comparative: two reports from the same build carry the same hash, and a report produced by a different build is visibly different. It is not a claim that the build was blessed by anyone.
Reproducibility is not correctness. A report proving that the same rules found the same things says nothing about whether those rules should have found something else. A false negative reproduces exactly as reliably as a true positive.
What it does give you is the thing that is usually missing when the question comes back months later. You can say which code ran, over which bytes, under which rules, and show that the record has not moved since. That is a narrower claim than "proof", and it is one that holds up.
Checking it yourself
Scan the same file twice and compare the report hashes. They should match.
Change one character in the file and scan again. The input hash changes, and so does the report hash.
Then open the Network tab and do all of the above. Nothing carrying your file leaves the tab, which is the claim the rest of this rests on and the only one you do not have to take from us.