BASALT · JOURNAL
Someone sent you a redacted PDF. Here is how to check it
To check if a PDF is really redacted, you have to read the file rather than look at the page, because a correct redaction and a black rectangle drawn over intact text render identically. Six checks, all runnable from Terminal in a couple of minutes, cover the ways content survives a failed redaction.
This matters in both directions. If you are receiving a production you need to know whether you can rely on it, and if you are forwarding one someone else prepared, their mistake becomes your disclosure.
Why the page tells you nothing
A PDF page is a program. The content stream is a sequence of operators executed in order: set a font, set the text matrix, show glyphs with Tj or TJ, set a fill color, define a path, fill it. A viewer runs that sequence and paints as it goes, so a rectangle emitted after a line of text hides it on screen while every character code stays in place.
Extraction tools do not replay the painting. They walk the text operators directly and return what is there, which is why a covered name comes straight back out. The same applies to invisible OCR text drawn in rendering mode 3, to /ActualText accessibility strings, to form field values in the field dictionary, and to content inside a switched-off optional content group.
There is also the update chain. PDF allows a new revision to be appended with the earlier bytes and an older cross reference table left in place, so a document can show a redacted page and still contain the unredacted one from a generation ago. The mechanism is set out in why a redacted PDF still shows the text.
So visual review, which is what most document workflows perform, cannot detect this class of error. A careful reader checking every page will pass a completely unredacted file.
How to check if a PDF is really redacted, in six passes
Install Poppler, qpdf, and exiftool with Homebrew and work on a copy. The first pass is text extraction, which catches the commonest failure: a mark that covered without removing.
pdftotext -layout received.pdf - | less
Read the output where the black bars are. If words appear there, the redaction is cosmetic. Search for anything you expect to have been withheld, such as a party name or an account number.
The second pass is structural. Expand the file into readable objects and search it, which catches text that extraction misses because a subset font has no usable /ToUnicode map.
qpdf --qdf --object-streams=disable received.pdf expanded.pdf
strings expanded.pdf | grep -i "smith"
In the expanded file, look for /Annots with a /Square subtype near the marked coordinates, for /ActualText and /Alt entries, for /OCGs and /OCProperties indicating optional content groups, and for /AcroForm field dictionaries whose /V values hold unshown data.
The third pass is images, since a mark drawn on a page does nothing to the pixels inside an embedded image object and a scan can carry the original picture whole.
pdfimages -all received.pdf ./extracted/img
Open them. If material you expected to be withheld is visible, the tool painted over the page and left the DCTDecode stream intact.
The fourth pass is generations. More than one end-of-file marker means the file contains earlier revisions.
strings received.pdf | grep -c "%%EOF"
Signatures and ordinary edits also append revisions, so a count above one is a reason to look rather than a verdict. What matters is whether a prior revision holds an unredacted page.
The fifth pass is metadata, which is never on a page and is often forgotten.
exiftool -a -u -g1 received.pdf
The document information dictionary and the XMP packet can disagree, and both survive most redaction attempts. Author names, original file paths, prior titles, producing software, and the document identifier linking this file to earlier versions all live here. Removing PDF metadata on a Mac covers what each field leaks.
The sixth pass is attachments and scripts.
pdfdetach -list received.pdf
Embedded files travel inside the PDF and are invisible in normal viewing. A spreadsheet attached to an exhibit carries its own metadata, its own revision history, and often the unredacted data the exhibit summarizes. Search for /JavaScript and /OpenAction too, and see what a PDF still carries after you think you cleaned it for the rest.
What to do when a check fails
If you are the recipient of a production and a check comes back positive, stop and notify the sender rather than reading what was meant to be withheld. Reviewing withheld material can carry professional and legal consequences depending on the context you work in, and the fact that it was recoverable does not change that it was withheld. Record the exact commands and their output, which gives the other side something they can re-run.
If the failed file is one you are about to forward or publish, do not repair it in place, since a repaired copy inherits the update chain and any metadata from the failed attempt. Go back to the source and redact properly: excise the glyphs from the content stream, overwrite and re-encode image pixels under the mark, remove invisible OCR text at the same coordinates, clear off-page carriers, and write the result as a single generation.
For your own outgoing work, the same six passes belong in a script that exits non-zero on any hit, which turns verification into a gate rather than an optional review step. A worked version is in the redaction checklist to run before filing.
Frequently asked questions
How do I check if a PDF is really redacted?
Extract the text with pdftotext and read what appears where the black bars are, then expand the file with qpdf --qdf --object-streams=disable and search the raw structure for the same terms. Follow that with image extraction, a count of %%EOF markers, exiftool on the metadata, and pdfdetach -list on attachments. Any single pass is weak evidence, and the combination is what tells you.
Can I tell by looking at the pages?
No, and that is the central problem. A correctly redacted page and a page with a rectangle drawn over live text render identically at every zoom level, because rendering is the step that discards the distinction. Visual review will pass an entirely unredacted document without anything looking wrong.
Is it legal to check a redacted PDF someone sent me?
Running structural checks on a file you were given is ordinarily reasonable, and reading material that was deliberately withheld is a different question that depends on your jurisdiction, your professional obligations, and the terms of production. The safe practice is to test whether content is recoverable, stop there, and report the finding to the sender.
What does it mean if pdftotext returns nothing?
It means text extraction found nothing it could map to characters, which is encouraging but not conclusive. Extraction depends on the font's /ToUnicode table, and a subset font with a missing map can hold the original character codes while producing empty output. Confirm by expanding the file with qpdf and reading the content stream.
How can I check a scanned PDF that has no selectable text?
Extract the embedded images with pdfimages -all file.pdf ./out/img and open them, since a mark drawn on the page leaves the image object untouched. Then run pdftotext anyway to check for an invisible OCR layer, because scanned files are usually processed for search and that layer sits in rendering mode 3 over the picture of the words.
Does the number of %%EOF markers matter?
More than one end-of-file marker means the document contains multiple revisions saved as incremental updates, with the earlier bytes still present. Signatures and ordinary editing also produce extra revisions, so the count alone proves nothing. What matters is whether an earlier generation contains a page before it was redacted.
Should I check metadata even if the pages look fine?
Yes, because metadata is never rendered and survives nearly every redaction attempt. The information dictionary and the XMP packet carry author names, original file paths, prior titles, producing application details, and an identifier linking the file to earlier versions. Run exiftool -a -u -g1 and read both, since they frequently disagree.
What should I ask the sender for if a check fails?
Ask for a replacement produced from the source document rather than a repaired copy of the file you have, and ask what tool was used. A repaired copy can retain the pre-redaction page in its update chain, so the fix has to start upstream. Independent verification of the replacement is worth requesting.
Doing it in Basalt
Basalt includes an Inspector that reports what a document still carries off-page: metadata, XMP, embedded files, hidden layers, annotations, OCR text layers, JavaScript, and saved generations. It is the fast version of the six passes above for a file that just landed in your inbox. When you redact, text is excised from the content stream glyph by glyph, image pixels under a mark are destroyed and re-encoded, the file is written as a single generation, and a verifier re-opens the produced bytes with an independent parser to prove the content is gone before anything is saved. If it cannot prove that, no file is written and it tells you why. The engine has no network entitlement, enforced by macOS at the code signature level, so nothing leaves your Mac, and 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.