Multimodal Injection · 4 of 5L3offensive security
Document and OCR Channels: Invisible Text, Layout Tricks, and Metadata as Injection Surfaces
A document is not what you see — it is what the parser extracts, and the gap between the two is where an instruction hides from the human but not from the agent.
Abstract
Agents that read files are everywhere: summarize this PDF, extract fields from this invoice, review this contract. Each of those tasks runs a parser or an optical-character-recognition step that turns a document into text the model treats as authoritative, and documents are unusually rich hiding places. This article examines the document injection surface: text that is invisible to a human but extracted by a parser, layout and rendering tricks that separate what is seen from what is read, optical-character-recognition channels in scanned files, and metadata fields that carry instructions no reader inspects. It formalizes the core gap between the rendered view and the extracted content, and pairs each channel with a concrete sanitization or containment defense. The key takeaway is that a document has two contents — the visible one and the extractable one — and an agent acts on the second, so defending it means normalizing extraction and treating everything it produces as untrusted data.
Ask a person and a parser to read the same PDF and you may get two different documents. The person reads the rendered page: the words laid out in visible ink at readable size and contrast. The parser reads the file: every text object, including ones drawn in white on white, sized to a single pixel, positioned off the page, layered beneath an image, or tucked into a metadata field that never renders at all. An agent asked to summarize the file acts on the parser's version, and an attacker who understands the difference can write an instruction that the human proofreader will never see and the agent will faithfully obey. The document injection surface is precisely this gap between what is displayed and what is extracted.
Two contents: the rendered view and the extracted text
A document format like PDF or a word-processing file is a program for producing a rendered page, not a plain string. It contains text objects with positions, colors, sizes, and layering, plus structures like annotations, form fields, and metadata that may or may not appear when rendered. A human sees the render; a parser walks the object model and extracts text regardless of whether it was visible. These are two different contents, and the security problem is that the agent consumes the extracted content while any human review inspects the rendered one.
This is the document instance of the cross-modal threat model: a perception step — here, parsing or optical character recognition — converts an artifact into text the model treats as trusted context. Greshake and colleagues established that indirect injection works through any content an application feeds the model, and documents are an especially effective channel because the format is designed to separate presentation from content, giving an attacker many places to put text that renders invisibly.
The defensive consequence is that you cannot secure a document by looking at it. The render tells you nothing about what the parser will extract. Defense must operate on the extraction: normalize it, strip the channels that carry invisible content, and label whatever remains as untrusted data.
- Operate defenses on the extracted text, not the rendered view, since the two can differ arbitrarily.
- Strip or flag text objects that would not render visibly (zero-size, transparent, off-page, fully occluded).
- Label all extracted document text as untrusted data before it enters the model's context.
Invisible text and layout tricks
The simplest document payload is text the render hides. White text on a white background, a font size of zero or near-zero, transparent fill, text positioned outside the visible page bounds, or text drawn beneath an opaque image all produce object-model content that a naive text extractor happily returns while a human sees nothing. An attacker places an instruction this way in an otherwise ordinary-looking document, and any agent that summarizes or reasons over the extracted text encounters the instruction.
Layout tricks are a richer variant. Because a document specifies exact positions, an attacker can interleave visible and invisible fragments so that the rendered reading order and the extraction order differ, or so that visible words form an innocent sentence while the extraction concatenates hidden fragments into an instruction. The parser's linearization of a two-dimensional layout is where this ambiguity lives, and different parsers linearize differently, so a payload can even target a specific extraction pipeline.
The defense is extraction hygiene: render-aware extraction that discards text which would not be visible, normalization that collapses the document to what a human would actually read, and treating the result as data. Where fidelity to hidden content is never needed — which is almost always for untrusted documents — the safest extractor is one that only returns visibly rendered text.
# DEFENSIVE PATTERN — keep only text a human would actually see
function extract_visible(document):
out = []
for obj in document.text_objects:
if obj.alpha == 0: continue # transparent
if obj.font_size < MIN_VISIBLE: continue
if not within_page_bounds(obj): continue
if is_occluded_by_opaque(obj): continue # under an image
if color_matches_background(obj): continue # white-on-white
out.append(obj.text)
text = linearize_reading_order(out) # stable, documented order
return label_untrusted(text) # never instructions- Use render-aware extraction that drops transparent, zero-size, off-page, occluded, or background-colored text.
- Linearize with a single documented reading order so extraction cannot be steered by layout ambiguity.
- For untrusted documents, prefer an extractor that returns only visibly rendered text.
Metadata and structural fields
Beyond the body text, documents carry structured fields that many extractors include: title, author, subject, and keyword metadata; annotations and comments; form-field default values; embedded file attachments; and, in office formats, hidden document properties. None of these render as page content, yet a naive pipeline that concatenates title and keywords ahead of the body — a common convenience — hands an attacker a channel that requires no rendering trick at all.
This is dangerous because metadata feels like housekeeping, not content, so it is rarely sanitized. An instruction placed in a document's subject field or a comment thread flows into the model with the same authority as the body if the extractor includes it. The attacker does not even need invisibility; they need only a field the pipeline reads and the reviewer ignores.
The control is an allow-list of fields the pipeline consumes, with everything else discarded, and the same untrusted-data labeling applied to any metadata that is genuinely needed. Treating metadata as content-with-provenance rather than as trusted structure closes the channel.
- Allow-list the specific fields the pipeline consumes and discard all other metadata, annotations, and hidden properties.
- Never concatenate metadata ahead of body text as trusted structure; label any needed field as untrusted data.
- Strip embedded attachments and comment threads from untrusted documents before extraction.
The OCR channel in scanned documents
When a document is a scanned image rather than digital text, the pipeline runs optical character recognition, which reintroduces the image-injection surface from the vision channel. An attacker can place low-contrast text, text at the edge of legibility, or characters shaped to be read by the OCR engine but overlooked by a hurried human, and the recognized text becomes prompt content. This merges the document and image threat models: the file is parsed like a document, but the payload is delivered like an image.
OCR also inherits the robustness dynamic of image payloads. A payload must survive the OCR engine's preprocessing — binarization, deskewing, denoising — which means a defender who normalizes aggressively and uses a well-behaved OCR configuration degrades fragile payloads. But the more common OCR payload is not adversarial at all; it is simply legible text placed where a reviewer will not read it, which normalization alone will not remove.
The unifying defense is the same as for every other channel: treat OCR output as untrusted data, apply the visibility and contrast hygiene that removes clearly-hidden content, and never let recognized text reach a consequential action without independent authorization.
- Treat OCR output identically to other extracted text: untrusted data, structurally delimited, never an instruction.
- Apply contrast and legibility hygiene to scanned inputs to remove clearly-hidden low-contrast text.
- Do not let OCR-recognized content trigger high-impact actions without independent authorization.
Deciding what to trust: an extraction gate
Because a document has two contents, the pipeline needs an explicit decision about what to extract and how much to trust it. The gate below captures that decision: extract only visibly rendered body text through a documented reading order, discard non-allow-listed metadata and non-visible objects, run any OCR through the same visibility hygiene, and emit the result labeled as untrusted data. Anything that fails the visibility or allow-list checks is dropped rather than passed through, because for untrusted documents there is no legitimate need for content a human cannot see.
The reason to make this an explicit gate rather than an implicit default is that convenience pushes the other way. Extractors are built to return everything, metadata is easy to concatenate, and OCR returns whatever it recognizes. Each convenience is a channel. Naming the gate and enforcing it in one place — through which all document ingestion flows — is what turns a scattered set of parser behaviors into a governed control.
Downstream, the same containment applies as for every modality: least privilege on tools, confirmation for high-impact actions, and egress controls, so that a payload which somehow survives extraction still cannot reach anything valuable.
- Route all document ingestion through one explicit extraction gate that enforces visibility, allow-listing, and labeling.
- Drop, do not pass through, any content that fails visibility or allow-list checks.
- Contain downstream with least privilege, confirmation, and egress controls in case a payload survives.
Why this matters for file-reading agents
Document injection is the most business-relevant multimodal channel because reading files is a flagship agent use case: processing invoices, reviewing contracts, summarizing reports, triaging support tickets with attachments. These agents routinely ingest documents from outside the trust boundary — a vendor's invoice, a customer's upload, a crawled web PDF — and act on what they extract, often invoking tools to record data, send responses, or update systems. A hidden instruction in such a document is a direct path to unauthorized action.
The synthesis is that the document channel is defined by the gap between rendering and extraction, and the defender controls the extractor. Close the gap — extract only what a human would see, allow-list metadata, label everything untrusted — and the invisible-text, layout, metadata, and OCR channels collapse into one governed surface. Combined with minimal agent authority, a file-reading agent can be handed a booby-trapped document and still do no harm, which is the only durable success criterion given that documents will always be an attractive hiding place.
- Funnel all file ingestion through one hardened extraction gate shared across the agent's document tasks.
- Keep agent authority minimal and require confirmation for irreversible or exfiltrating actions triggered by document content.
Key takeaways
- A document has two contents — the rendered view a human sees and the extracted text an agent acts on — and the gap between them is the injection surface.
- Invisible text (white-on-white, zero-size, off-page, occluded) and layout tricks let an attacker hide instructions from readers but not from parsers.
- Metadata, annotations, and form fields are an unrendered channel that naive pipelines concatenate as trusted content without any rendering trick.
- OCR on scanned documents reintroduces the image-injection surface, merging the document and vision threat models.
- Human review of the rendered document is not a control, because the payload exists only in the extracted content.
- The defense is an explicit extraction gate — visible-only, allow-listed metadata, labeled untrusted — plus minimal agent authority so surviving payloads are contained.
Practitioner Toolkit
Copy-paste, strictly defensive artifacts you can use today. Nothing here attacks a real system.
Run before allowing any agent to act on file content.
- Extraction returns only visibly rendered text (no transparent, zero-size, off-page, occluded, or background-colored objects).
- A single documented reading order is used so layout cannot steer extraction.
- Metadata, annotations, and hidden properties are allow-listed, with everything else discarded.
- OCR output passes the same visibility and contrast hygiene as digital text.
- All extracted content is labeled untrusted data and structurally delimited.
- High-impact actions triggered by document content require least privilege and confirmation.
Sanitized skeleton that flags documents whose extraction exceeds what renders (defensive only).
# DEFENSIVE PROBE — does the parser return more than the page shows?
function render_extract_diff(document):
visible = extract_visible(document) # render-aware
raw = extract_all(document) # naive, everything
hidden = raw.minus(visible)
if hidden.nonempty():
flag(document, reason="extraction exceeds render", sample=hidden.head())
# A large hidden delta == likely hidden-channel payload.
# Route flagged documents to stricter handling / human triage.Illustrative least-authority policy for the file path.
document_policy:
extraction:
mode: render_aware # visible text only
reading_order: documented_single
drop_non_visible: true
metadata:
allow_list: [body] # discard title/subject/comments by default
label: untrusted_data
ocr:
visibility_hygiene: true
label: untrusted_data
framing:
delimit: required
concatenate_raw: forbidden
authority:
post_document_tool_calls: least_privilege
high_impact: require_confirmationDo these first if your agent reads files.
- Switch to render-aware extraction that returns only visible text.
- Discard metadata, annotations, and hidden properties by default.
- Run OCR output through the same visibility hygiene and label it untrusted.
- Put high-impact post-document tool calls behind least privilege and confirmation.
Glossary
- Rendered view
- The visible page a human sees when a document is displayed or printed.
- Extracted text
- The text a parser or OCR step returns from a document, which can include content that never renders.
- Invisible text
- Document text that is present in the file but not visible when rendered, such as white-on-white or zero-size text.
- Layout trick
- An arrangement of visible and hidden fragments that makes the rendered reading order differ from the extraction order.
- Metadata channel
- Structured document fields (title, subject, comments, form defaults) that carry extractable text without rendering.
- Optical character recognition (OCR)
- The process of recognizing text from an image of a document, reintroducing image-injection risk.
- Render-aware extraction
- Extraction that returns only text which would actually be visible when the document is rendered.
- Extraction gate
- A single enforced pipeline step that decides which document content is extracted, trusted, and labeled.
References
- Greshake et al., Not What You've Signed Up For: Compromising Real-World LLM-Integrated Applications with Indirect Prompt Injection (arXiv 2302.12173)
- Bagdasaryan et al., Abusing Images and Sounds for Indirect Instruction Injection (arXiv 2307.10490)
- Carlini & Wagner, Audio Adversarial Examples: Targeted Attacks on Speech-to-Text (arXiv 1801.01944)
- OWASP Top 10 for LLM Applications (LLM01 Prompt Injection)
- MITRE ATLAS (Adversarial Threat Landscape for AI Systems)