How it's built
PDF Changer is a solo project. I built it to learn, to solve my own problem, and to see how far I could push browser-based document processing. This page is the honest breakdown of what's under the hood.
The stack
- React 19 + React Router (SPA)
- Tailwind CSS (utility-first, no component library)
- Vite (build tooling + dev server)
- Workbox (service worker for offline use)
- pdf-lib (create, modify, merge, split)
- PDF.js (rendering for redact, flatten, export)
- Tesseract.js (OCR text extraction)
- Web Crypto API (SHA-256, HMAC, ECDSA)
- Cloudflare Pages (hosting, headers, CDN)
- Stripe (payments, no custom billing)
- WebAuthn passkeys (no passwords stored)
- Vitest (125 tests across 31 files)
- TypeScript strict mode throughout
- Bundle budget enforcement (14 limits)
- Content validation pipeline (5 scripts)
The interesting problems
Verified Processing Environment
"We don't upload your files" is easy to say. Proving it is harder. I built a system that wraps every PDF operation in three concurrent monitors: a PerformanceObserver watching all network requests, a CSP violation listener catching blocked exfiltration attempts, and a MutationObserver detecting injected scripts or tracking pixels.
WebRTC is monkey-patched during processing to prevent IP leaks via ICE candidates. The sandbox iframe runs with an opaque origin and a CSP that blocks all outbound connections. After processing, the system produces a tamper-evident audit report with HMAC-chained entries and SHA-256 hashes of input and output.
Threat model based on analysis of 45+ browser exfiltration vectors. Full architecture doc · Vector analysis
Steganography detection
Most printers embed invisible yellow tracking dots (Machine Identification Code) that encode the printer serial number, date, and time. If you scan a printed document back to PDF, those dots survive. The scrubber includes a heuristic detector that renders pages at high resolution and scans margin areas for yellow pixel patterns matching known MIC grids.
Structure randomization
PDFs have internal object ordering. If every output from this tool had identical structure, that structure itself becomes a fingerprint. The paranoid scrub mode shuffles internal object insertion order using Fisher-Yates. Two identical inputs produce visually identical but structurally different outputs.
2,900-line build plugin
The static site generation is a custom Vite plugin that pre-renders 500+ pages at build time. It parses markdown, generates JSON-LD structured data, builds the sitemap, generates RSS, creates the sandboxed processing iframe, and enforces CSP headers. The build also runs five content validation scripts including prohibited-phrase detection.
Font fingerprinting
When you create a PDF with a custom font, the authoring tool embeds a font subset with a randomly generated prefix unique to that export. The scrubber detects these subsets and warns you, with a link to the flatten tool which destroys all font data by converting pages to images.
How competitors do it
Every major free PDF tool uploads your document to their servers for processing. Some claim to delete files after an hour; some don't say. Either way, your document leaves your device, crosses the network, and sits on someone else's infrastructure.
PDF Changer processes everything in a sandboxed iframe inside your browser tab. The iframe's Content Security Policy blocks all outbound connections. Three monitors verify that nothing leaked. The difference isn't just a privacy policy — it's a fundamentally different architecture.
Try it
Process a sample PDF and watch three monitors prove zero data left your browser.
Drop in a PDF and see the full report — metadata stripped, hashes computed, audit badge attached.
Threat models, exfiltration analysis, and residual risk disclosures.