BASALT · JOURNAL
How to check a PDF for hidden text aimed at AI tools
To check a PDF for prompt injection, compare what you can see with what a text extractor returns, then search the file's text, metadata and annotations for instructions. On a Mac, mdimport -t -d3 document.pdf prints the text Spotlight extracts, including invisible, white and tiny text. Text placed outside the page isn't in that output, so a second look with qpdf is needed.
This works because many AI tools read a PDF's extracted text, instead of or alongside the rendered page. A line that's white on white, a fraction of a point tall or set to draw nothing is invisible to you and ordinary to the extractor. No check proves a file is clean, and each AI tool extracts differently, so treat the steps below as a way to look, not a guarantee.
Where an instruction can hide in a PDF
Each of these places is part of the file itself.
- Invisible text. Text rendering mode 3, set by the operator
3 Tr, draws nothing but still extracts. - White text. Text filled with white on a white page.
- Tiny text. A font size of a point or less, which renders as a speck.
- Off-page text. Text positioned outside the page area. It never shows on a page, and whether an extractor returns it varies.
- Metadata. The Subject, Keywords, Title or an XMP field.
- Annotations. A note's contents, or a hidden annotation that has its hidden flag set.
- Form field values. Text stored in a field, apart from the page.
- ActualText. A tag that tells an extractor to return different words than the ones drawn.
Text inside an image is a separate case, since it reaches an AI tool through OCR or image reading, not through the text layer. None of the checks below can see it.
Compare what you see with what extracts
Start with the text view, which needs nothing but Terminal. It prints everything Spotlight reads from the file and stores nothing in the index:
mdimport -t -d3 document.pdf
Find the line starting kMDItemTextContent. On macOS 15, a sample page with a render-mode-3 line, a white line and a 0.5-point line returned all three, and a line placed outside the page was missing. A page written by macOS's own PDF writer gave the same result. The same output shows the Subject and Title in kMDItemDescription and kMDItemTitle.
Read it as a person would. Any instruction-like sentence that isn't on the page you saw, such as "ignore the previous instructions" or a request addressed to an assistant, is the thing you're looking for. Spotlight also ignores ActualText: for a sample file whose ActualText swapped the drawn words for others, it returned the drawn words. So a different extractor could return different text from the same file.
Search an expanded copy for the rest
Content streams are often compressed, so a plain search of the raw file can find nothing even when the text is there. Install qpdf (brew install qpdf) and write an uncompressed copy, which leaves the original untouched:
qpdf --qdf --object-streams=disable document.pdf expanded.pdf
First, count the switches to invisible text:
grep -a -o -E '\b3 Tr\b' expanded.pdf | wc -l
A count above zero means some text is set to draw nothing. That's normal in a scanned file, whose OCR layer is invisible text, so it's a reason to read that text, not a finding. White and tiny text are harder to catch this way, because files set color and size in several ways. A file written by macOS, for instance, sets white with 1 1 1 sc and puts the size in the text matrix, so a search for one pattern misses the others. For those two, the mdimport comparison above is the better check.
Then list the text stored away from the page, and search for the language of an instruction:
grep -a -o -E '/(Contents|Subject|Keywords|Title|ActualText|V) *\([^)]*\)' expanded.pdf
grep -a -n -i -E 'ignore (all )?(previous|prior)|system prompt|note to ai|assistant:' expanded.pdf
The first lists annotation contents, metadata strings, ActualText entries and form values (/V). The second finds instruction-like phrases in those fields, but often not in the page text: many files split each line into short pieces for spacing, and in a file written by macOS it found nothing in the page content. Strings can also be stored in hexadecimal or as UTF-16, which these patterns miss, so a quiet result isn't proof.
For off-page text, compare the page size with where text is placed:
grep -a -A5 '/MediaBox' expanded.pdf
grep -a -o -E '[-0-9.]+ [-0-9.]+ (Td|Tm)' expanded.pdf
The first prints each page box as four numbers, its corners in points. In the second, the two numbers before Tm are a position on the page, while Td moves relative to the line before. On a 612 by 792 page, a sample file's 900 900 Tm stood out at once. Treat it as a hint, because other operators can move text and change what the numbers mean.
What to do with a hit
If you found text you didn't expect, don't send the file to an AI tool as it stands. Ask where it came from. If you made the document, re-export it from the source. If someone sent it, the source is the better thing to question.
Removing is the safer route than relying on the AI tool to ignore it. Hidden text in a PDF covers how to get rid of text that isn't on the page, and how to redact a PDF before uploading it to an AI tool covers what to take out before upload for privacy reasons.
OCR layers deserve a mention. A scanned page often has an invisible text layer that's legitimate, and it extracts the same way as a planted line. Why an OCR layer matters for security explains how to tell the two apart. If the extracted text reads as nonsense, copying text from a PDF that comes out as gibberish is a different problem.
Frequently asked questions
Can a PDF contain a prompt injection?
Yes. Any text an AI tool extracts can contain instructions, including text you can't see on the page. White, tiny and invisible text, metadata, annotations and form values are all read by some extractors. Whether a particular tool acts on such text varies.
How do I check a PDF for hidden text?
Run mdimport -t -d3 document.pdf in Terminal and compare the extracted text with what you see on the pages. Then expand the file with qpdf and search it for invisible-text switches, metadata, annotation contents and form values. Text placed outside the page won't appear in the first step.
Is there a prompt injection scanner for PDFs?
Some tools claim to be one, and none can promise to find everything. An instruction is just words, so a scanner can only flag patterns, and an attacker can change the words. The approach here, comparing what you see with what extracts, shows you the text and leaves the judgment to you.
Does hidden text in a PDF show up when I search?
It can. Invisible and white text is still text in the file, so a tool that searches the text layer may find it, but that depends on the viewer. Off-page text and text in other fields may not turn up. Searching is a quick test, not a complete one.
Why can't I see the text an AI tool read in my PDF?
Because AI tools read the file's text layer, not the picture of the page. Text can be drawn with no ink, in white, at a tiny size or off the page, and it will still be returned by an extractor. Compare what you see with the extracted text to find the difference.
Does removing metadata remove a prompt injection?
Only if the instruction was in the metadata. Text on the page, annotations and form values aren't metadata and stay unless you take them out. Check each place before you rely on one fix.
Does Basalt's Inspect find hidden prompt text?
No. Inspect doesn't look for invisible, white or tiny text. It reports some places an instruction could sit, such as ActualText entries, optional layers, annotations, form fields and filled document properties, without quoting them. For a phrase you suspect, the Redact search described below finds text by what it says.
Doing it in Basalt
Basalt helps with two parts of this. Its Inspect tool reports ActualText entries, optional layers, annotations, form fields and filled document properties on any PDF, each with a severity and a plain explanation, without quoting the values. It doesn't look for invisible, white or tiny text, so it won't point hidden text out to you: that's what the Terminal steps above are for. Once you know or suspect a phrase, the Redact search covers the whole document and finds text by what it says, whatever its color or visibility, so you can mark it. Basalt then removes the text from the content stream and saves a new file, and a verifier re-opens the result to confirm the marked text is gone. Everything runs on your Mac, for $29 once, 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.