BASALT · JOURNAL

How to check whether a PDF was really redacted

2026-08-06 · how to check if a pdf is redacted

A redaction is a claim about the contents of a file, and claims about files are verifiable. The problem is that the usual way people check, looking at the page, is the one method guaranteed to tell you nothing. A page with the text removed and a page with a rectangle drawn on it render identically.

This is a procedure for checking a PDF before it goes out. It uses tools already on your Mac plus one open source utility, and it takes a few minutes per document.

Level one: the copy test

Open the file, drag-select across each redacted region, press Command-C, and paste into TextEdit with plain text mode on. Do the same with Command-A to select the entire document at once, which is faster for a long file.

If any supposedly removed term appears in the paste, stop. The document is not redacted and nothing further needs checking.

If nothing appears, you have learned very little. Copy and paste depends on the font's /ToUnicode mapping. A file with subset fonts and no reverse mapping can hold the characters perfectly well while pasting nothing useful. Treat this as a fast fail test, not a pass test.

Level two: extract text with an independent parser

The important word is independent. Do not use the application that wrote the file to check the file, because a bug in its writer is likely to be matched by the same assumption in its reader.

Install Poppler with Homebrew and use pdftotext:

brew install poppler
pdftotext -layout redacted.pdf - | grep -i "smith"

pdftotext reads the content streams and resolves the text-showing operators directly. Run it once per term you removed. Redirect the full output to a file and read it if you want to see what an opposing party's extraction tool would see.

Add -raw as a second pass. The two modes reconstruct reading order differently and occasionally surface fragments the other misses.

This catches text that survives in the page content. It will not show you metadata, attachments, or annotation values, so do not stop here.

Level three: the places text hides outside the page content

Several parts of a PDF hold readable text that never appears in a normal extraction.

Annotation values live in the /Contents string of each annotation and in its appearance stream. A sticky note or a free text annotation can carry a comment naming exactly what you redacted.

Form field values live in the field dictionary. Painting over a widget does not clear the value, and a form flattening step that misses one field leaves it intact.

/ActualText and /Alt store plain text equivalents for accessibility. Removing a word from the visible glyph run while leaving its /ActualText in place is a common partial failure.

Optional content groups let content be assigned to a layer that is switched off. The content renders nowhere and extracts fine.

Scanned pages usually carry an OCR text layer drawn in rendering mode 3, invisible but positioned over the image. If the redaction destroyed image pixels but not the OCR layer, the words are still readable.

To see all of this, decompress the file's object structure and read it. qpdf is the standard tool:

brew install qpdf
qpdf --qdf --object-streams=disable redacted.pdf expanded.pdf
grep -a -i "smith" expanded.pdf

--qdf rewrites the file in a readable, uncompressed form and --object-streams=disable unpacks objects that would otherwise be hidden inside compressed object streams. Grepping the expanded file catches strings anywhere in the document structure, which is exactly what you want at this stage.

Level four: metadata

Metadata lives in two places that can disagree with each other. The document information dictionary holds /Author, /Title, /Creator, /Producer, /Subject, /Keywords. The XMP packet is an XML block, often with a full edit history, a document identifier linking the file to its ancestors, and application-specific fields.

exiftool reads both:

brew install exiftool
exiftool -a -u -g1 redacted.pdf

Look for an author name, an original file path, a prior title, and the document ID. Documents where the black boxes held but the metadata named the author are a recurring pattern, and it is entirely avoidable. More detail is in what a PDF still carries after you think you cleaned it.

Also check for embedded attachments:

pdfdetach -list redacted.pdf

An attached spreadsheet inside a produced PDF is a full disclosure with no page to review.

Level five: the incremental update chain

This is the check almost nobody runs and the one that most often invalidates everything else.

PDF supports incremental updates. A new revision is appended to the end of the file with its own cross-reference section, and the earlier bytes remain in place. A viewer shows you the newest revision. The older ones are still there.

If a redaction was saved as an incremental update, the pre-redaction page is physically present in the file you are about to send.

Count the end-of-file markers:

grep -c "%%EOF" redacted.pdf

More than one means the file has multiple revisions. That is not automatically fatal, since a file can be signed or updated for benign reasons, but a redacted document should be written as a single generation. If the count is above one, extract the earlier revision and check it:

qpdf --show-npages redacted.pdf
qpdf --qdf redacted.pdf - | grep -a -c "%%EOF"

A tool that writes one generation and discards prior revisions removes this question entirely. That is the standard to hold, and it is one of the specific reasons redacting in Preview is not redaction, since viewers commonly save by appending.

Level six: images

If your redaction covered part of a scan or a photograph, confirm the pixels are gone rather than covered. Extract the images and look at them:

pdfimages -all redacted.pdf ./out/img

Open the extracted files. If the sensitive area is visible in the extracted image, the redaction painted a rectangle on the page and left the image object untouched. A real image redaction overwrites the pixel data and re-encodes the image, so the extracted file shows the destroyed region.

Making this repeatable

Six levels per document does not scale by hand. Two things make it practical.

First, automate the checks. The commands above compose into a shell script that takes a file and a list of terms and exits non-zero on any hit. Run it as the last step before production, not as an optional review.

Second, prefer a tool that verifies its own output with an independent parser and refuses to write a file it cannot prove. That turns verification from a step you might skip into a property of the artifact. See also a black box over text is not a redaction.

Frequently asked questions

How can I check if a PDF is properly redacted?

Extract the text with an independent parser such as pdftotext and search the output for the terms you removed, then decompress the file with qpdf --qdf --object-streams=disable and grep the expanded structure for the same terms. Also inspect metadata with exiftool, list attachments with pdfdetach, and count %%EOF markers to detect retained earlier revisions.

Does copying and pasting prove a PDF is redacted?

No. Copy and paste is a useful fast fail test, but passing it proves very little. Extraction depends on the font's /ToUnicode mapping, so a file with subset fonts can hold the original characters while pasting nothing readable. A parser that maps glyphs directly will still recover the text.

Can redacted text be recovered from a PDF?

Yes, whenever the redaction only covered the text instead of removing it from the content stream. Recovery methods include text selection, command line extraction, deleting the annotation that formed the black box, and walking back through the incremental update chain to an earlier revision of the page. None of these require specialist software.

What does more than one %%EOF in a PDF mean?

More than one %%EOF marker means the file contains multiple revisions saved as incremental updates, and the earlier bytes are still present. That is not always a problem, since signing and legitimate edits also append revisions, but a redacted file should be written as a single generation. If earlier revisions exist, check whether any of them contain the unredacted page.

How do I check PDF metadata on a Mac?

Run exiftool -a -u -g1 file.pdf from Terminal after installing exiftool with Homebrew. It reads both the document information dictionary and the XMP packet, which can disagree with each other. Look for author names, original file paths, prior titles, edit history, and the document identifier that links the file to earlier versions.

Will Preview or Adobe show me hidden text in a PDF?

Generally no. Viewers render the page and show you the visible result, which is the one view that cannot distinguish a real redaction from a drawn rectangle. Hidden material such as switched-off optional content groups, /ActualText entries, form field values, and earlier revisions is not surfaced in a normal viewing interface.

How do I confirm an image was redacted and not just covered?

Extract the embedded images with pdfimages -all file.pdf ./out/img and open the extracted files directly. If the sensitive area is visible in an extracted image, the tool painted a rectangle on the page and left the original image object intact. A real image redaction overwrites the pixel data and re-encodes the image.

Should I trust a tool that says the redaction succeeded?

Only if it can show evidence from something other than itself. A confirmation dialog reports intent, not outcome, and a writer bug is often mirrored by the same assumption in the same application's reader. Independent verification, a signed certificate, or byte-reproducible output that a third party can re-run are the forms of evidence that hold up.

Doing it in Basalt

Basalt runs this verification for you and makes it non-optional. After a redaction is written, an independent parser re-opens the produced bytes and proves the text is absent from content streams, annotation values, form fields, accessibility text, and metadata. If it cannot prove it, no file is written at all.

Each redaction produces an Ed25519-signed certificate you can verify with shasum and openssl without installing anything from us. Output is byte-reproducible, so the same source plus the same marks gives a byte-identical file and a third party can re-run it and confirm.

The engine runs in a separate process with 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.

DOWNLOAD BASALT 2.3.0 BUY $29 FREE FOR 24 HOURS · MACOS 13+