Can text under a redaction be recovered?
Usually, yes, and it takes no skill: select the blacked-out area and copy it, or open the file with anything that extracts text. A black rectangle is an instruction to paint over a region, not an instruction to remove what is there, so the words survive in the page's content stream exactly as they were written.
A page is a list of drawing instructions
A PDF page is a content stream: operators executed in order, from the first to the last. Text is drawn inside a text object, which opens with BT and closes with ET. Between them Tf picks a font and size, Td sets a position, and Tj draws a string. A rectangle is two operators: re adds it to the current path and f fills it with whatever colour rg last set.
Here is the entire content stream of a 637-byte PDF built for this page. It looks, on screen, like a line of text with a black bar across it.
BT
/F1 14 Tf
72 700 Td
(Account number 4029 1174 5583 9920) Tj
ET
0 0 0 rg
68 694 260 24 re
f
Handed to pdf.js 4.10.38, the same engine version this site serves to X-RAY and SEAL, getTextContent() on that page returns Account number 4029 1174 5583 9920. Nothing removed the Tj. The rectangle is drawn afterwards, and later operators paint over earlier ones rather than deleting them, so the string is exactly where it was. Select the area in any reader and the same thing happens: the reader is reading the operators, not the picture.
Kerned text hides nothing either. The TJ operator takes an array of strings with numbers between them for spacing, so a name can be split across several pieces. A stream containing [(Wit) 20 (ness: Mar) -15 (ia Delacroix)] TJ comes back from the same call as Witness: Maria Delacroix, reassembled the way the renderer would have assembled it.
Four more ways a redaction fails
The box is an annotation, not part of the page
Many editors draw their black box as an annotation: a separate object listed in the page's /Annots array. In a second fixture the box is object 6, << /Type /Annot /Subtype /Square /Rect [68 694 328 718] /IC [0 0 0] >>, and the content stream is untouched. Removing one entry from an array puts the page back to how it was. Flattening stops that particular trick, because it burns the appearance into the page and drops /Annots — but it never touches the text underneath, and it should not be mistaken for redaction.
A picture drawn over is still a picture
On a scanned page, the thing being covered is usually an image, and the image is a separate object with its own stream. A fixture here holds << /Type /XObject /Subtype /Image /Width 4 /Height 2 /ColorSpace /DeviceRGB /BitsPerComponent 8 >> drawn with /Im0 Do, then a filled rectangle over half of it. Reading the stream straight out of the file, without looking at the page at all, gives back 255 0 0 · 0 255 0 · 0 0 255 · 255 255 0: the original samples, in order, unaffected by anything painted on top.
The file still says what the document was about
The trailer's /Info dictionary and the document outline are not page content, so no amount of drawing covers them. A fixture with a rectangle over a witness's name still answers getMetadata() with Title: Delacroix statement FINAL unredacted.docx and Author: J. Okonkwo, and its outline with a single bookmark: Statement of Maria Delacroix. The same names turn up in XMP packets and in the file name itself.
Earlier versions of the file are still inside it
A PDF is changed by appending to it. The editor writes the new objects at the end, then a new cross-reference section whose trailer carries /Prev, the byte offset of the previous one. Both revisions are in the same file; a reader follows the chain from the last startxref and shows you the newest.
Taking the fixture above and appending a revision that replaces the content stream with (Account number [REDACTED]) Tj produced an 860-byte file with two %%EOF markers, whose new trailer reads /Prev 454. pdf.js now reports Account number [REDACTED]. The string 4029 1174 5583 9920 is still in the file, at byte offset 312. Nothing was deleted; something was added in front of it.
This is the chain PDFSIG walks when it examines a signed document: it finds the last startxref, reads the trailer, follows /Prev back through every revision, cuts the file at each %%EOF and lists what each revision changed. Run a file you thought was clean through it and count the revisions.
What removing the content actually takes
There are two honest approaches. One is surgical: take the glyphs out of the content stream, take the image out of the resources, clear the metadata and the outline, then write the whole file out fresh so no earlier revision survives. It keeps selectable text everywhere else, and it is fiddly, because a text run has to be split around the part that goes and the positioning around it has to still make sense.
The other is to throw the structure away: render each page to a bitmap, destroy the pixels that should not be there, and build a new document out of the painted bitmaps. Nothing from the content stream, the annotations, the fonts, the metadata or an earlier revision survives, because none of it is carried across.
SEAL takes the second route, and it is worth being precise about what it does. Each page is rendered with pdf.js at twice its natural size, the areas you drag are filled black straight into that canvas with fillRect, and each painted canvas is encoded as JPEG and embedded as a new page. The output's title, author, subject, keywords, producer and creator are set to empty strings rather than left to the library, and the SHA-256 of the bytes you downloaded is shown so the file can be identified later.
The cost is stated rather than hidden: the result is images. Text in it is no longer selectable or searchable, and the file is larger than the original. That is the mechanism, not a side effect. A redaction that kept the text layer would not be a redaction.
What to do with a document you are about to send
- Look at it before you decide. X-RAY renders each page, then compares every text run against the pixels where it should be. It sorts those pixels into sixteen brightness bands: rendered glyphs are anti-aliased and spread across many bands, while a flat fill lands entirely in one. Text the file contains but the page does not show is reported. It is a heuristic and it says so, because a scanned page with an OCR layer is invisible text by design; when nearly all of a page's text is invisible X-RAY calls it OCR rather than a failed redaction.
- Redact by rasterising. SEAL, above. One file at a time, marked by hand.
- Deal with forms and comments separately. FLATTEN draws each form field's value permanently onto the page and removes the field, so there is no second, editable copy of the answers to read out. It also removes fields marked hidden before it draws anything, rather than printing across the page a value somebody had made invisible, and it deletes the catalogue's XMP metadata stream as well as the
/Infofields. - For disclosure work, the discovery walkthrough covers the order to do these in and the chain-of-custody side.
What this does not tell you
None of the checks here find sensitive content for you. SEAL removes what you cover and nothing else; X-RAY reports what a page contains and does not judge whether it should, and its hidden-text pass stops after the first twelve pages. Headers, footers, margins, the second column and page 40 are yours to read.
Rasterising defeats extraction from the file. It does not defeat reading the picture: if a rectangle is too small, or is drawn at the wrong place because a viewer laid the page out differently, the pixels that show through are simply visible. Check the preview.
And an image-only PDF is not anonymous. The library that writes it stamps a /CreationDate and a /ModDate at the moment of export whatever else has been cleared, and the file still has a size and whatever name you give it.
What this is, and what it is not
Covering is not removing. Every failure on this page comes from the same confusion. Drawing, flattening and hiding change what a reader displays. Redaction has to change what the file contains, which means rewriting it.
The test is the one anybody can run. Open the finished file, select the redacted area, and paste it somewhere. If any text comes out, it is not redacted. That test costs ten seconds and catches the whole first category of mistake.
SEAL trades the text layer away on purpose. Its output is page images. Nothing in it is selectable or searchable and the file is bigger, because rebuilding the document from painted bitmaps is precisely what leaves nothing underneath.
Nothing here is uploaded. The document is read, rendered and rewritten in the browser tab. The PDF engine is served from this site rather than a third-party CDN, so no part of the file, and no record that you opened it, goes anywhere.
This is not legal advice. Whether a particular redaction meets a court's or a regulator's requirements is a question for the rules that apply to you. This explains what the file does.
Questions people ask
How do people get the text back out from under a black box?
By copying it. The words are still in the page's content stream, so selecting the area and pasting it, or running any text extractor over the file, returns them. There is no tool to obtain and no technique to learn, which is why this mistake keeps producing real disclosures.
Does flattening a PDF make a redaction safe?
No. Flattening merges annotations into the page, which stops the black box being deleted as a separate object. The text object underneath is not what flattening removes. Save the flattened file, select the area and copy it: if text comes out, nothing was redacted.
I deleted the page and saved. Is the content gone?
Not necessarily. A PDF is normally changed by appending, so the version with the page in it can still be sitting earlier in the same file, reachable by following the /Prev entries in the cross-reference chain. Ask your editor to save a fresh copy rather than an incremental update, and then check the result.
Can a redacted scan be recovered?
If the box was drawn over the image, yes: the image is a separate object carrying its own pixels, and painting on the page does not alter it. Only a redaction that rewrites the image data, or that rebuilds the page from a bitmap that has already been painted, removes what was there.
Does removing the text also remove the name from the metadata?
It does not, unless something removes that too. The /Info dictionary, an XMP packet, the document outline and the file name are separate from page content and routinely name exactly what was taken out. X-RAY lists them; SEAL's output carries none of them across; FLATTEN clears them in place.
Is there a way to check a file before sending it?
Open it in X-RAY, which reports text the file contains but the page does not display, along with the metadata and any active content. Then do the copy-and-paste test by hand on every page you redacted. Both are quick, and between them they catch the failures described here.