BASALT · JOURNAL
PDF redaction not working: the five things that are usually wrong
When you find your PDF redaction not working, the cause is almost always one of five specific things, and four of them leave the original words physically present in the file. The fifth leaves them in an earlier revision that is still inside the document you are about to send.
None of them is visible on the rendered page, which is why the problem surfaces after distribution rather than during review. Each has a distinct signature you can check in a terminal.
Five reasons for PDF redaction not working
One: the mark is an annotation, not an edit
The most common failure. Markup tools create an object in the page's /Annots array with a rectangle, a /Square subtype, a color, and an appearance stream: a comment shaped like a rectangle, sitting beside the page content rather than inside it.
Deleting that annotation reveals the page exactly as it was, because the text operators were never touched. That is documented, intended behavior for annotations.
Two: the box was flattened but the glyphs were not removed
Flattening merges the annotation into the content stream so the rectangle can no longer be deleted as an object, and it is often mistaken for a fix. The text-showing operators are untouched: Tj and TJ still hold the original character codes, and extraction walks those operators directly without regard for painting order.
Three: a scan was covered and the OCR layer survived
Scanned pages usually carry an invisible text layer produced by OCR, drawn in text rendering mode 3 and positioned over the picture of the words so the document is searchable. Cover the image with a mark and that layer is still fully extractable, and some tools that do redact the visible image leave it alone because it is not what you clicked on. This is the case handled in redacting a scanned PDF with an OCR layer.
Four: the same string lives somewhere that is not page content
A name can be excised from the visible glyph run and still be present in several places that never appear on the page you are reviewing.
/ActualText and /Alt entries hold plain text equivalents of marked content spans for accessibility. Form field values live in the field dictionary rather than in page content, so covering a widget's appearance leaves the value intact. Annotation /Contents strings, bookmark titles, and embedded attachments each carry their own.
Five: the file was saved as an incremental update
PDF permits appending a new revision to the end of a file, leaving the earlier bytes and an older cross reference table in place, and many applications save this way by default because it is fast and preserves signatures. Save a redaction that way and the pre-redaction page is physically inside the file you distributed, recoverable by walking the update chain back one generation. The page looks redacted and the document contains both versions.
How to tell which one you have
The checks read the file, not the rendering. Install Poppler, qpdf, and exiftool with Homebrew and work on a copy.
Start with extraction, which catches causes one, two, and three.
pdftotext -layout suspect.pdf - | grep -i "smith"
A clean result is not proof, because fonts with a missing or wrong /ToUnicode map can hold the original character codes while producing empty output. Expand the structure and read it directly.
qpdf --qdf --object-streams=disable suspect.pdf expanded.pdf
strings expanded.pdf | grep -i "smith"
In the expanded file, search for /Annots and /Subtype /Square to identify cause one, and for /ActualText, /Contents, and /OCGs to identify cause four. Form field values appear under /V in the dictionaries reachable from /AcroForm.
Count generations for cause five.
strings suspect.pdf | grep -c "%%EOF"
More than one marker means earlier revisions are present. Signing and ordinary editing also append revisions, so this is a prompt to look rather than a verdict.
Then check the carriers never on a page: exiftool -a -u -g1 suspect.pdf for the information dictionary and XMP packet, and pdfdetach -list suspect.pdf for embedded files.
For scans, extract the images and open them, since a page-level mark does nothing to the pixels inside an embedded image object.
pdfimages -all suspect.pdf ./extracted/img
The full sequence is in how to verify a PDF redaction.
Fixing it properly
Go back to the source document, because a repaired copy inherits the update chain, the metadata, and the thumbnails from the failed attempt.
Real redaction is a content stream edit. The text operators are parsed into individual glyph runs with real page positions, accounting for the text matrix, font size, horizontal scaling, character and word spacing, and the kerning adjustments inside a TJ array. Because a TJ array usually holds a whole line, the excision is per glyph, and surviving glyphs are re-emitted in place.
Image pixels under a mark are overwritten and the image re-encoded, so the original DCTDecode stream cannot be extracted whole, and invisible OCR text at the marked coordinates is excised alongside the visible content. /ActualText, form field values, annotation strings, and optional content groups are cleared rather than covered.
The file is then written as a single generation with a fresh cross reference table, and metadata, XMP, attachments, and stale thumbnails are stripped in the same pass. What a PDF still carries after you think you cleaned it has the inventory.
The last requirement is evidence: verify the output with a parser other than the one that wrote it, because a confirmation dialog reports intent rather than outcome.
Frequently asked questions
Why is my PDF redaction not working in Preview?
Because Preview's markup tools create annotations, which are removable objects sitting beside the page content rather than replacing it. Even the redaction-labeled option in some versions produces a covering rather than a content stream excision plus metadata strip, as set out in why redacting in Preview is not redaction.
I applied redactions in Acrobat and the text still comes out. What happened?
Most often the redactions were marked but never applied, since marking and applying are separate steps and the marked state already looks like a finished black bar. Check that the apply step ran, then confirm with pdftotext on the saved output. Also verify that the OCR layer on any scanned page was included.
Does saving as a different PDF version fix a failed redaction?
No. The PDF version number affects which features are permitted, not whether specific bytes are still in the file. Re-saving can rewrite the file as a single generation, which removes earlier revisions, but it does nothing about text operators, OCR layers, form field values, or accessibility strings.
Why does my redaction work on some pages but not others?
Usually because those pages are structurally different from the rest: a scanned page among digital ones, a page with a form field, or a page where text sits inside an optional content group. Tools that handle the common case can silently skip the exception, so check each failing page individually in the expanded file.
How do I tell if a redaction removed the text or just covered it?
Extract the text with pdftotext and search for the terms, then expand the file with qpdf --qdf --object-streams=disable and search the structure. If the terms appear in either, the content is still present. Covering and removing produce identical renderings, so the file is the only place the answer exists.
Does my redaction fail if the PDF has multiple %%EOF markers?
Multiple end-of-file markers mean the document contains more than one revision saved as incremental updates, and the earlier bytes remain in the file. That is a failure if one of those revisions holds the unredacted page. Signatures and ordinary edits also produce extra revisions, so inspect what each generation contains.
Can I fix a broken redaction without the original file?
You can produce a file that passes the checks, but you cannot be certain nothing survives, because you are working on top of an unknown history. If the original is unavailable, write the repaired document as a single generation, strip every off-page carrier, and verify the output independently.
What should I check before a document leaves my machine?
Run text extraction, structural inspection of the expanded file, image extraction on scanned pages, a count of end-of-file markers, exiftool on the metadata, and pdfdetach -list on attachments. Scripting that so it exits non-zero on any hit turns it into a gate rather than an optional step, and a worked version is in the redaction checklist to run before filing.
Doing it in Basalt
Basalt addresses all five causes in one operation: text is excised from the content stream glyph by glyph with surviving text re-emitted in place, image pixels under a mark are destroyed and re-encoded, invisible OCR layers are handled with the visible content, off-page carriers are stripped, and the file is written as a single generation. Before anything is saved, a verifier re-opens the written bytes with an independent parser and proves the content is gone, and if it cannot prove that, no file is written and it says why. The Inspector reports what a document still carries that is not on any page, so you can see the problem before you start. Every tool writes a new file, and the engine has no network entitlement, enforced by macOS at the code signature level, so documents never leave your Mac. It is $29 once, lifetime, up to three Macs, free for 24 hours.
Redaction that proves itself
Basalt destroys the content you mark, then re-opens the file it wrote and proves the content is gone before it saves anything. Your documents never leave your Mac.