Scrubber
Strip the hidden metadata out of your files — and prove it's gone.
I built Scrubber out of a small, slightly paranoid habit: before I post a photo anywhere, I want to know what's riding along inside it — the GPS coordinates of where I was standing, the phone that took it, the edit history buried in a document. Plenty of tools will strip that for you. Almost all of them do it the lazy way, and the lazy way is exactly what made me want to build my own.
The lazy way is to redraw the image onto a canvas and re-export it. The metadata vanishes — but so does fidelity. The JPEG gets re-compressed, the colour profile is dropped, and you've quietly degraded the photo in order to clean it. I didn't want a tool that protects your privacy by damaging your files, so the central decision — the one everything else hangs off — was to strip surgically: parse the real file structure, remove only the metadata segments, and leave the compressed image bytes untouched so the pixels come out byte-for-byte identical. That's more work than a canvas redraw, and it's the entire point.
The second decision was about trust. Stripping is easy to claim and hard to believe, so the tool re-parses every file after cleaning and shows you the result — and I gave it one hard rule: it can never show a green check it can't back up. When something structural genuinely can't be removed, it says so in amber and explains why, instead of smiling and lying. That honesty rule turned out to be the fiddliest part of the whole build. The re-scan kept surfacing things that looked like leftover metadata but weren't — intrinsic image properties like dimensions and colour type, or fields one parser could read and another couldn't — and each one threatened a false amber on a file that was actually clean. Getting "verified clean" to mean precisely that took more care than the stripping did.
The third decision was architectural, and it surfaced the moment I wanted a command-line version. The obvious move was a separate Go or Python CLI — but that would mean a second implementation of the exact surgical logic the tool's credibility rests on, and two implementations drift. So I kept the engine pure: bytes in, bytes out, no browser APIs, no DOM. The same code runs in the page and on the command line, which means the scrub CLI's output is identical to the browser's down to the byte — the byte-identical guarantee is provably the same guarantee in both places, not two that happen to agree.
The last constraint was that nothing leaves your machine, and I treated that as a discipline rather than a slogan. There's no backend to send a file to, no analytics, nothing — even the GPS callout links out to a map rather than embedding one, so the "nothing leaves the page" claim survives contact with the network tab. And since a privacy claim only means anything if you can check it, the whole thing is open source under MIT — including a history rewrite to keep my own planning notes out of the public repo.
Why it matters
Scrubber is small on purpose, and that's what I like about it as a piece of work. There's nowhere to hide. The entire value is whether you can trust what it tells you, so every decision came back to the same question: is this honest, and can the person using it prove it for themselves? Surgical instead of lossy, verified instead of asserted, one engine instead of two, open instead of opaque. It's the clearest example I have of a build where getting the trust right was the engineering.
What it does
Reveal → strip → verify
Every hidden field is shown by category, removed on one click, then the cleaned file is re-parsed to confirm zero remain — never a false green.
Surgical, not lossy
Images come out byte-for-byte identical — only the metadata segments are removed, with no re-encode and the ICC colour profile preserved.
Nothing leaves the page
No backend, no account, no analytics, no telemetry. Every byte is processed in the browser, it works offline, and the network tab stays empty.
One engine, web and CLI
The same surgical engine ships as an installable `scrub` command, so batch and scripted cleaning produces output identical to the web app.
Come knock on the door.
Got a strange idea, a collaboration, or just want to argue about history and dice math? I answer to all of it.
hello@malkav.pro