Written for: Engineering leads and product security owners shipping chat assistants, retrieval search or AI agents
Securing LLM-powered features: prompt injection, agents and the OWASP Top 10 for LLM Applications
Prompt injection, agent risks and data leaks through rendered output, mapped to the OWASP Top 10 for LLM Applications (2026 update), with fixes and a test plan.
Published · Updated · 13 min read
With a language model in the product, text that used to be inert, such as a support ticket, a PDF a customer uploads or a web page your assistant summarises, can steer software that holds your users' data and, once it has tools, the power to act on it.
Why prompt injection is different from SQL injection
SQL injection has a structural fix. Parameterised queries keep the code channel and the data channel apart, so an apostrophe in a surname can never become a command. Large language models have no equivalent boundary: the system prompt, the user's message, a retrieved document and a tool's output all arrive as one sequence of tokens, and the model decides what to treat as an instruction. In December 2025 the UK's National Cyber Security Centre wrote that current models make no distinction between data and instructions, and that prompt injection attacks may never be totally mitigated in the way SQL injection was.
The NCSC suggests treating the model as an inherently confusable deputy, and that framing changes the engineering question. Filtering hostile input still helps, but the decisive question is what the system can do, and to whom, on the day the model is fooled. A feature whose worst case is an embarrassing reply has a content problem. A feature whose worst case is sending another customer's records to an attacker has a security architecture problem, and that has to be solved outside the model.
| Question | SQL or command injection | Prompt injection |
|---|---|---|
| Where is the boundary? | Between code and data, enforced by the database driver or a safe API | There is none inside the model: instructions and data share one input |
| Is there a complete fix? | Yes: parameterised queries, safe APIs and output encoding | No known complete fix, so you reduce the likelihood and limit the impact |
| Does input filtering work? | Allow-list validation is effective | Filters and classifiers catch known phrasings and miss new ones |
| What does a test prove? | That a specific parameter is or is not exploitable | What the system allows once the model follows hostile text |
| Where does the control live? | In how the query or command is built | In permissions, confirmation steps and output handling around the model |
Direct and indirect prompt injection
The OWASP Top 10 for LLM Applications 2025 lists prompt injection first, as LLM01:2025, and separates two forms. Direct injection happens when a user's own input alters the model's behaviour, such as the familiar instruction to ignore previous guidelines typed into a chat box. Indirect injection happens when the model accepts input from external sources, such as websites or files, and that content alters its behaviour. The idea was set out in a 2023 paper by Greshake and colleagues, who argued that applications which retrieve data blur the line between data and instructions, so an attacker can plant instructions in content the system is likely to fetch later.
Direct injection mostly threatens your own content policies. Indirect injection is the serious one for most products, because the attacker never needs an account: they only need to get text in front of the model. These are the paths we test:
- Documents customers upload for summarising, extraction or question answering
- Web pages fetched by a browsing or research tool
- Emails, support tickets, chat transcripts and calendar invitations processed by an assistant
- Entries in a retrieval knowledge base, including pages any employee can edit
- Responses from tools and third-party APIs that the agent calls
- Code, comments, README files and issue threads read by a coding agent
- Text hidden from people but not from the model: white-on-white text, HTML comments, image alt text and metadata
A well-documented example is CVE-2025-32711, a critical flaw in Microsoft 365 Copilot published in June 2025, which researchers at Aim Labs called EchoLeak. The attacker sent an ordinary-looking business email containing hidden instructions, phrased as if written for a person so that Microsoft's injection classifier let it through. When the recipient later asked Copilot a related question, the retrieval engine pulled the email into the model's context, and the injected instructions made the model place internal data inside a link or image pointing at the attacker. Nobody had to click anything. Microsoft fixed it on the server side, reported no evidence of exploitation, and customers had nothing to install.
Agents, tools and the confused deputy
Once a model can call tools, injection stops being a content problem and becomes an access-control problem. A confused deputy is a program that holds authority and is tricked by a less privileged party into misusing it. An agent is a deputy by design: it holds the user's session, an API key or a service account, and it reads text written by people who hold none of those. OWASP calls the resulting risk Excessive Agency, LLM06:2025, and traces it to three root causes.
| Root cause | What it looks like in a product | Design response |
|---|---|---|
| Excessive functionality | An assistant that only needs to look up orders is given a general web fetch, a shell or a free-form database query tool | Offer only the tools the task needs, each narrow and single-purpose, and avoid open-ended extensions |
| Excessive permissions | Tools run as a service account that can read every tenant's data or write anywhere | Run each action in the context of the requesting user, with the least privilege it needs |
| Excessive autonomy | Refunds, emails, deletions and permission changes happen before anyone sees them | Require a person to approve high-impact actions before they run |
OWASP adds a principle that matters more than any prompt: complete mediation. Authorisation belongs in the downstream systems, which check every request on its own merits, instead of in the model's judgement about whether an action is allowed. If your billing API would refuse a refund to an ordinary user, it must refuse the same refund when the agent asks on that user's behalf.
For agent designs, the most useful single test we know is Simon Willison's lethal trifecta. An agent that combines access to private data, exposure to untrusted content and the ability to communicate externally can be made to hand that data to an attacker, and the only reliable defence is to avoid the combination entirely. The NCSC cites a related principle: when a model processes information from a party, its privileges should drop to that party's. In practice, the agent that reads inbound email should not also hold the tools that query your customer database or send messages outside the company.
Data exfiltration through rendered output
The quietest exfiltration channel needs no tools at all. If the model can be persuaded to write a markdown image whose address contains your data, the user's browser requests that address automatically and delivers the data to the attacker's server. OWASP's prompt injection entry describes exactly this scenario. Microsoft's Security Response Center lists HTML and markdown images and clickable links among the exfiltration techniques demonstrated against LLM-based systems. After a researcher reported exfiltration through markdown image injection, Microsoft took steps to block that technique deterministically, and took similar steps against others, such as the generation of certain untrusted links. EchoLeak showed the second-order problem: a content security policy only helps if no allow-listed domain can be abused to carry the data out.
The wider weakness is Improper Output Handling, LLM05:2025: model output passed to other components without validation. OWASP's examples include output entered directly into a system shell or into exec or eval, JavaScript or markdown returned to a user's browser, SQL generated by the model and executed without parameterisation, file paths built from output, and email templates filled with unescaped text. The fix is old and unglamorous: treat the model like any other untrusted user.
- Treat model output as untrusted text and encode it for the context it lands in: HTML, markdown, SQL, shell or file path.
- Do not render images or preview links from arbitrary domains; strip or proxy them, and allow-list the few you need.
- Keep a strict content security policy, and review every allow-listed domain for ways to carry data out.
- Use parameterised queries for any database operation that involves model output, and never pass output to a shell, exec or eval.
- Validate structured output against a schema before any downstream system acts on it.
- Remove hidden content such as HTML comments from retrieved text before it reaches the model.
The OWASP Top 10 for LLM Applications: the 2025 list and the 2026 update
The OWASP GenAI Security Project published the 2025 edition on 18 November 2024, and this guide was first written against it. We now map findings to the OWASP Top 10 for LLM Applications 2026, described below, alongside MITRE ATLAS, because it gives your engineers, auditors and customers a shared vocabulary. Teams building autonomous agents should also read the OWASP Top 10 for Agentic Applications for 2026, published in December 2025.
| 2025 entry | 2026 entry | Risk | What we look for |
|---|---|---|---|
| LLM01:2025 | LLM01:2026 | Prompt Injection | Direct and indirect instructions that change behaviour, through every path text takes to the model |
| LLM02:2025 | LLM02:2026 | Sensitive Information Disclosure | Other users' or tenants' data, internal records and secrets appearing in responses |
| LLM03:2025 | LLM04:2026 | Supply Chain | Third-party models, adapters, plugins and datasets with unknown provenance or licences |
| LLM04:2025 | LLM05:2026 | Data and Model Poisoning | Training, fine-tuning or embedding data that an outsider can influence |
| LLM05:2025 | LLM10:2026 | Improper Output Handling | Model output reaching browsers, shells, databases or APIs without validation |
| LLM06:2025 | LLM03:2026 | Excessive Agency | Tools, permissions and autonomy beyond what each task needs |
| LLM07:2025 | LLM08:2026 | System Prompt Leakage (Hidden Context Exposure in 2026) | Credentials, internal rules or security logic placed in the system prompt |
| LLM08:2025 | LLM09:2026 | Vector and Embedding Weaknesses | Retrieval that ignores document permissions, and leakage between tenants in a shared vector store |
| LLM09:2025 | LLM07:2026 | Misinformation | Confident, wrong answers that users or systems act on without a check |
| LLM10:2025 | LLM06:2026 | Unbounded Consumption | Missing quotas, rate limits and cost caps, including agent loops that never end |
How we test an LLM feature, in seven steps
An AI and LLM application test treats the model as one component of a system and attacks the system. We run it grey-box: we need the prompts, the tool definitions and the identities those tools run as, because that is where the impact lives.
- 1
Map the feature
We draw the data flows with your engineers: the model and its version, system prompts, retrieval sources, tools, the credentials behind each tool, and every place output is displayed or consumed. For a feature still being designed, this is a short threat model.
- 2
Build an injection corpus for your content
Direct prompts, plus indirect payloads planted in each ingestion path you have: uploaded files, web pages, emails, tickets and knowledge base entries, including hidden text and attacks spread over several turns.
- 3
Attack the boundaries between users
We try to retrieve other users' and other tenants' documents, extract the system prompt, and check whether retrieval respects the permissions of the person asking.
- 4
Drive every tool
For each tool we try to make the agent call it with parameters we choose, skip or spoof the confirmation step, and reach data or actions the user could not reach directly.
- 5
Try every way out
Markdown images, links, HTML, tool calls to external addresses and anything else that can carry data out of the conversation.
- 6
Test the ordinary surface
The model sits behind an ordinary API that needs authentication, authorisation, rate limits and cost controls, so we test it as we would any web application.
- 7
Report, and hand over a regression set
Every finding comes with an attack transcript you can replay against your deployment, mapped to the OWASP Top 10 for LLM Applications 2026 and MITRE ATLAS, plus regression prompts your team re-runs after every model or prompt change. The engagement includes a free retest of every fixed finding within 30 days of report delivery.
Most engagements take 4 to 10 working days, depending on how many tools and ingestion paths the feature has.
Design controls and a pre-release checklist
No single control is enough, so build layers that fail independently. In rough order of value:
- Least privilege for tools. Narrow, single-purpose tools, read-only by default, acting with the requesting user's credentials rather than a shared service account.
- Complete mediation. Every downstream system enforces its own authorisation on each request the agent makes.
- Human confirmation for consequential actions. Show the exact action and its parameters before anything is sent, paid, deleted or shared. Microsoft takes this route in Outlook: Copilot drafts the text, but the user must approve it and send the email themselves.
- Break the trifecta. Separate the component that reads untrusted content from the one that holds private data or an outbound channel.
- Allow-lists wherever you can. For the domains you render, the addresses tools may fetch, the tools an agent may call and the recipients it may contact.
- Output handling. Encode, parameterise and schema-check model output before anything acts on it.
- Mark untrusted content. Delimit or tag retrieved text so the model can tell it apart from instructions. Microsoft calls its version spotlighting and describes it as probabilistic, which is the right way to think about every technique in this category.
- Limits and logging. Rate limits, token and cost quotas, and logs of prompts, tool calls and outputs that your team can investigate.
Before release, check each of these against the build you are about to ship:
- Every tool is listed with the identity it runs as and the worst action it can take.
- High-impact actions need a person's approval, and the approval screen shows the real parameters.
- Downstream APIs reject requests the user could not make directly, whoever sends them.
- Retrieval filters documents by the asking user's permissions before ranking, in every tenant.
- No credentials, connection strings or authorisation rules live in the system prompt.
- Images and links from domains outside the allow-list are not rendered in model output.
- Model output is encoded for the browser and never reaches a shell, eval or an unparameterised query.
- Indirect injection has been tested through every ingestion path, including hidden text.
- Quotas and rate limits stop runaway agent loops and cost abuse.
- A regression prompt set runs before every model, prompt or tool change.
If you are about to ship a chat assistant, a copilot or an agent, start with the pentest scoping call. A 45-minute scoping call ends with a fixed quote and a proposed start date; the written scope follows by email. If the feature is still on a whiteboard, a threat modelling workshop is the faster route and changes the design while it is still easy to change. Where the model sits inside a larger product, an application security audit reads the code paths that decide what the agent is allowed to do.
Sources
- OWASP Top 10 for LLM Applications 2026 (opens in a new tab) · OWASP GenAI Security Project · 3 August 2026
- OWASP Top 10 for LLM Applications 2025 (opens in a new tab) · OWASP GenAI Security Project · 18 November 2024
- LLM01:2025 Prompt Injection (opens in a new tab) · OWASP GenAI Security Project
- LLM05:2025 Improper Output Handling (opens in a new tab) · OWASP GenAI Security Project
- LLM06:2025 Excessive Agency (opens in a new tab) · OWASP GenAI Security Project
- LLM07:2025 System Prompt Leakage (opens in a new tab) · OWASP GenAI Security Project
- LLM08:2025 Vector and Embedding Weaknesses (opens in a new tab) · OWASP GenAI Security Project
- OWASP Top 10 for Agentic Applications for 2026 (opens in a new tab) · OWASP GenAI Security Project · 9 December 2025
- Prompt injection is not SQL injection (it may be worse) (opens in a new tab) · National Cyber Security Centre (UK) · 8 December 2025
- Not what you've signed up for: Compromising Real-World LLM-Integrated Applications with Indirect Prompt Injection (opens in a new tab) · arXiv (Greshake, Abdelnabi, Mishra, Endres, Holz and Fritz) · 23 February 2023
- The lethal trifecta for AI agents: private data, untrusted content, and external communication (opens in a new tab) · Simon Willison's Weblog · 16 June 2025
- How Microsoft defends against indirect prompt injection attacks (opens in a new tab) · Microsoft Security Response Center · 29 July 2025
- CVE-2025-32711: AI command injection in Microsoft 365 Copilot (opens in a new tab) · CVE Program · 11 June 2025
- Zero-click AI data leak flaw uncovered in Microsoft 365 Copilot (opens in a new tab) · BleepingComputer · 11 June 2025