Security & Compliance Field Note

AI Prompt Injection Through Web Content

How hidden markup turns pages into attack vectors — prepared for xhtml-print.org

The dangerous sentence may be invisible

A browser assistant opens a pricing page and returns a neat summary. Buried in the markup is white-on-white text telling the agent to ignore its task, open a connected mailbox, and paste recent messages into a form. The user never saw the instruction. The model did. This is indirect prompt injection: untrusted web content is interpreted as if it were part of the user's request.

Hidden markup is attractive because modern agents consume more than rendered text. They may parse alt attributes, accessibility labels, comments, structured data, metadata, linked files, or text positioned outside the viewport. A page can look harmless in a browser while presenting a different instruction stream to the model.

A prompt injection attack crosses a trust boundary

An LLM does not enforce instruction hierarchy the way an operating system enforces process permissions. It predicts a response from the combined context. Developers can state that web pages are untrusted, but a carefully written page may still influence behavior. The application must assume that content can manipulate the model and constrain what happens next.

The OWASP prompt injection reference treats direct and indirect injection as a core LLM risk. AI prompt injection becomes more serious when the agent has tools. A bad summary wastes time; a bad summary that can send email, alter a repository, or make a purchase crosses into account compromise.

Hidden markup is only one carrier

Attack text can sit in CSS-hidden elements, tiny fonts, image metadata, SVG descriptions, PDF layers, code comments, or fetched content behind a link. It may use Unicode lookalikes or encode the instruction so a preprocessing step reveals it. Print workflows deserve attention because stylesheets can expose content that the screen view hides, or hide content that extraction still captures.

Do not build detection around a list of phrases such as 'ignore previous instructions.' Attackers paraphrase, split commands across elements, and use social pressure rather than obvious syntax. Detection helps prioritize risk, but permissions and confirmation are the controls that stop a clever payload from becoming an action.

Render and extract, then compare

For high-risk browsing, compare the visible page with the text supplied to the model. Flag large differences, off-screen blocks, zero-opacity text, suspicious ARIA labels, and instructions that appear only in metadata. Normalize Unicode and decode common encodings in a sandbox. Keep the raw page for forensics, but pass a reduced representation to the model.

Sanitization cannot establish truth. A visible paragraph can still be malicious, and some hidden text is legitimate accessibility content. Use the comparison as a signal. The right response may be to summarize the page without tools, ask the user for confirmation, or block navigation to a new origin.

How to prevent prompt injection from becoming compromise

Give the browsing component read-only access by default. Place email, cloud storage, source control, payment, and admin tools behind separate permissions. Bind each tool call to the user's current intent and display the exact action before execution. A request to summarize a page does not imply permission to send data anywhere.

Apply origin controls. A page from one domain should not silently direct the agent to post secrets to another. Prevent arbitrary URL fetches from reaching internal services, cloud metadata endpoints, or localhost. Strip credentials from requests and isolate browser state used for untrusted research from sessions used for administration.

Test the whole browsing pipeline

Security tests should include dynamic pages, nested frames, PDFs, images with text, CSS variants, shadow DOM, and content loaded after a click. Check what the model receives, not only what a human tester sees. Record page hashes, extracted text, model context, decisions, and tool calls so the team can reproduce a failure.

A secure agent may still summarize a hostile page. The goal is containment. It should identify the source, avoid treating page text as authority, refuse unrelated actions, and keep secrets out of the response. That behavior comes from architecture and permissions. Prompt wording alone cannot carry the weight.

Build controls around the context, not just the model

Teams often buy a model-security product and assume the boundary is covered. The harder problem sits around the model: document ingestion, retrieval indexes, browser tools, memory stores, plug-ins, feedback channels, and the people allowed to approve changes. Treat each path as an input interface with its own owner, logging, validation, and rollback plan. A clean model can still produce dangerous output when a trusted retrieval layer hands it poisoned material.

Start with a data-flow map. Mark where content enters, where it is transformed, how long it persists, and which actions an answer can trigger. Separate read access from write access. A support assistant may search a knowledge base without earning permission to update customer records. A coding assistant may suggest a command without running it. These boundaries turn a strange answer into a contained incident instead of an operational outage.

A practical review cycle

Run a small adversarial test set before every material release. Include conflicting instructions, poisoned documents, stale records, homoglyphs, hidden text, and requests that cross permission boundaries. Save the prompts, retrieved passages, tool calls, and final output so a failed test can be reproduced. The NIST Generative AI Profile offers a useful governance frame for mapping risks, measuring controls, and assigning ownership.

Monitoring needs an exit path. Define who can freeze retrieval updates, disable a tool, rotate credentials, restore a known-good index, and notify affected users. Keep clean snapshots of system prompts, policies, embeddings, memory, and connector configurations. When an assistant starts acting oddly, responders should be able to compare state and roll back within minutes. Guessing which component changed is not an incident plan.

Write the browser-agent threat model in verbs

A prompt injection attack matters because of what the agent can do after reading it. List those verbs: fetch, open, copy, upload, send, buy, approve, delete, or execute. For each verb, define the allowed data, destination, user confirmation, and audit record. This turns the broad question of how to prevent prompt injection into small controls engineers can test.

Keep secrets out of the model context when possible. Use short-lived tokens inside the tool layer, redact unrelated page data, and return only the fields needed for the task. If a hostile page cannot see a credential and cannot cause an unapproved tool call, its persuasive text has far less leverage.

One last operational check

Retest whenever browser extraction, permissions, or connected tools change.