Images & PDFs
A prompt injection does not have to be typed. It can be hidden in a picture or a PDF your agent opens — white text on a white background, text too small or too faint to notice — and the AI model reads it even though a person doesn't. AgentGuards reads the text in images and PDFs and screens it with the same checks as a prompt.
Stops InkJect-style PDF injection. InkJect (DeepKeep, 2026) hides instructions in a document as white, 1 pt, invisible or off-page text — the model reads the text layer, a person sees a clean page. AgentGuards reads that hidden layer and runs it through its strictest prompt checks, so a poisoned PDF your agent opens is blocked before it reaches the model. Verified end-to-end against our live API.
At a glance
- On automatically — there is nothing to turn on.
- Works through the Anthropic proxy (see below for what that is) and the Claude Code and Codex plugins — update the plugin to the latest version. Gemini CLI and Copilot CLI plugins: not yet.
- Anything that can't be screened is allowed and recorded in your decisions log — unless you turn on blocking.
What is scanned, by setup
| Your setup | Examples | Images your agent opens | Images you paste | PDFs | Text documents |
|---|---|---|---|---|---|
| Anthropic proxy | Claude Code with an API key, or your own app using the Anthropic SDK, pointed at AgentGuards | ✅ Scanned | ⚪ Not scanned | ✅ Scanned | ✅ Scanned |
| Claude Code plugin | Including Claude Pro / Max logins. Plugin 0.2.39 or later | ✅ Scanned — opened with Read, or named in a shell command | ⚪ Not scanned | ✅ Scanned — opened with Read, or named in a shell command | — Plain files aren't images or PDFs |
| Codex plugin | Plugin 0.2.25 or later | ✅ Scanned — opened with view_image, or named in a shell command | ⚪ Not scanned | ✅ Scanned — named in a shell command | — Plain files aren't images or PDFs |
| Gemini CLI, Copilot CLI plugins | Hook-based plugins | ⚪ Not yet | ⚪ Not yet | ⚪ Not yet | ⚪ Not yet |
| Gateway API (OpenAI-compatible) | /v1/chat/completions | — Not sent to the model | — Not sent to the model | — Not sent to the model | — Not sent to the model |
| REST API / MCP check_input | You send text to be checked | — Text only | — Text only | — Text only | — Text only |
| Self-hosted appliance | AWS Marketplace AMI | ⚪ Not yet | ⚪ Not yet | ⚪ Not yet | ⚪ Not yet |
✅ scanned · ⚪ passed through unscreened and recorded — your block option decides · — not applicable. The self-hosted appliance gets image and PDF screening in a future release.
What is "the Anthropic proxy"?
Normally your app or agent sends its requests straight to Anthropic (api.anthropic.com). With the proxy, it sends them to AgentGuards instead; we screen everything in the request — the prompt, and now the images and PDFs in it — and forward clean requests to Anthropic with the Anthropic key you saved in Settings. You are on the proxy if your client's Anthropic base URL is AgentGuards. Two examples:
Claude Code, signed in with an API key
{
"env": {
"ANTHROPIC_BASE_URL": "https://prod.agentguards.co",
"ANTHROPIC_API_KEY": "ag_YOUR_AGENTGUARDS_TOKEN"
}
}Your own app, using the Anthropic SDK
from anthropic import Anthropic
client = Anthropic(
base_url="https://prod.agentguards.co", # AgentGuards instead of api.anthropic.com
api_key="ag_YOUR_AGENTGUARDS_TOKEN", # your AgentGuards token, not an Anthropic key
)Claude Pro / Max logins can't use the proxy — they use the Claude Code plugin, which scans images and PDFs too (next section). Full setup: Claude Code proxy.
On the Claude Code and Codex plugins
When the agent is about to open an image or a PDF, the plugin sends the file to AgentGuards first. A clean file opens as normal. A file with an attack isn't opened: the agent is told why, and the attempt appears in your decisions log. A file is read the same way as on the proxy, so the PDF and image rows of the next table apply.
| The agent… | Scanned? |
|---|---|
| Opens an image or PDF (Claude Code Read, Codex view_image) | ✅ Yes |
| Runs a command that names one: pdftotext report.pdf, cat logo.png | base64, --in=scan.pdf | ✅ Yes — up to 3 files per command |
| Runs a command that only moves files: cp, mv, ls, git add, git commit | — Not needed: the agent doesn't see the content |
| Opens a file inside a script, or through a wildcard (*.pdf) | ⚪ Not seen by the plugin |
| Opens a file over 5 MB | ⚪ Not sent — your block option decides |
| Is shown a screenshot you pasted | ⚪ Not scanned — it's your own input |
If AgentGuards can't be reached, the file isn't opened, like every other check in the plugin (unless you configured it to fail open). Files are scanned and not stored; your log records only the file type, size and result — never its name or content.
What happens to each kind of file (on the proxy)
| Content | Result |
|---|---|
| PDF with a text layer (attached by you or read by your agent) | ✅ All text screened, including hidden text: white, tiny, invisible or off-page text, comments and form fields |
| Scanned PDF that has a text layer (OCR'd "searchable" PDF) | ✅ Screened — the invisible OCR layer is read like normal text |
| Scanned PDF page that is only a picture | ⚪ Not screened |
| Password-protected PDF | ⚪ Not screened |
| The part of a PDF beyond page 300 | ⚪ Not screened (the first 300 pages are) |
| Text document block | ✅ Screened |
| Image your agent opened (from a file, a web page or a tool) | ✅ Text read and screened, including faint text: white-on-white, light grey, dark-on-dark |
| Image with rotated, skewed or stylised text | ⚪ Not fully readable — screened with a vision model only if you turn that option on |
| Screenshot or image you paste into the chat yourself | ⚪ Not scanned — it's your own input, and scanning would slow every screenshot |
| Image or PDF sent by URL or file ID | ⚪ Not screened |
| Animated GIF / WebP | ✅ First frame · ⚪ other frames not screened |
| More than 8 images in one request | ✅ First 8 · ⚪ the rest not screened |
| A request over 8 MB in total, files included | ❌ Rejected (HTTP 413) — the request doesn't go through at all |
Text a person couldn't see (hidden or faint) is checked with the strictest prompt checks — nobody hides text in a document for the reader's benefit. Visible text is checked the way we check web pages your agent fetches.
Your options
All three are on the Checks page. The first is on by default; the other two are off.
| Option | What it does | When to turn it on |
|---|---|---|
| Scan images and PDFs your plugin agents open | The Claude Code and Codex plugins send each image or PDF the agent opens to AgentGuards before the agent sees it. Turn it off and the plugins send nothing — those files are then not checked. | Leave it on, unless files must never leave the developer's machine. |
| Block what AgentGuards can't screen | Everything marked ⚪ above is blocked instead of allowed. | Your agents handle files from places you don't control: cloned repos, web pages, email attachments, customer uploads. |
| Read hard-to-read images with my own API key | Images with rotated or stylised text are read by a vision model (Claude Haiku or GPT-4o mini) using the Anthropic or OpenAI key in your Settings. About $0.0025 per image, paid to your provider; each image is read once. Images only — PDFs don't need it. | You want those images screened rather than allowed or blocked. |
What a block looks like
On the proxy, the request never reaches the model; your client receives an error like:
AgentGuards blocked this prompt (media_scan): hidden text in image:
prompt_injection - Prompt injection pattern detected (critical)On a plugin, the file isn't opened and the agent is told:
🛡️ [AgentGuards] File blocked
Reason: media_scan - hidden text in image: prompt_injection - Prompt injection pattern detected (critical)media_scan means the text we read was an attack. unscreened_media means you turned on blocking and the request contained something we couldn't read. Both appear in your decisions log.
Privacy, speed and limits
- Images and PDFs are read on AgentGuards' own scanning server and are not stored; only the text is checked.
- Typical added time per image: well under a second for most, about 2–3 seconds when the text is rotated.
- Limits per request: 8 MB in total, files included (larger requests are rejected); 8 images scanned; 300 pages per PDF. Images and pages beyond those counts are not screened (⚪).
- Plugins: 5 MB per file; larger files aren't sent (⚪). A scan can add a few seconds before the agent opens the file.
- Only the newest message is scanned; earlier messages were scanned when they were new.
Questions? Contact us.