The OWASP Top 10 for LLM Applications describes what goes wrong when a model reads and writes text. Agents add something more dangerous: they act. They call APIs, run code, remember things across sessions and hand work to other agents. On 9 December 2025 the OWASP GenAI Security Project published a separate list for that setting, the OWASP Top 10 for Agentic Applications for 2026, with entries numbered ASI01 to ASI10.

A list of risks does not secure anything. This article turns it into an assessment you can run against a real agent: a threat model that places each entry on the architecture, a control, a test and an evidence artifact for every entry, a gateway that enforces several controls in one place, and a worked assessment of a customer-support agent. Three entries already have their own deep dives on this site, so for those the article links out rather than repeating them.

The ten entries at a glance

Here are the ten entries, with titles lightly shortened (ampersands written as and) and a one-line reading of each. The control column names the control that does most of the work; real coverage needs more than one.

IDRiskWhat goes wrongPrimary control
ASI01Agent Goal HijackText the agent reads redirects its objectiveTreat ingested content as data; gate actions
ASI02Tool Misuse and ExploitationPermitted tools used harmfully, chained or in bulkPer-call policy, rate and spend limits
ASI03Identity and Privilege AbuseAgent acts with more authority than the user hasDelegated, scoped, short-lived credentials
ASI04Agentic Supply Chain VulnerabilitiesA trusted tool, model, prompt or server is maliciousPin, verify and allowlist components
ASI05Unexpected Code ExecutionGenerated or triggered code runs unsandboxedIsolated sandbox, no ambient credentials
ASI06Memory and Context PoisoningInjected memory steers later sessionsProvenance on writes, scoped stores
ASI07Insecure Inter-Agent CommunicationAgent messages forged, replayed or alteredAuthenticated, signed messages
ASI08Cascading FailuresOne fault spreads through tools and agentsBudgets, timeouts, circuit breakers
ASI09Human-Agent Trust ExploitationPeople approve confident output uncheckedApprovals that show evidence and diffs
ASI10Rogue AgentsAgent drifts or colludes outside its mandateBehavioural monitoring and a kill switch

The deep dives cover the first-ranked entries: agent hijacking for ASI01, tool abuse for ASI02 and memory poisoning for ASI06. For how the agentic list relates to the LLM list, see the OWASP LLM Top 10 assessment guide.

Threat-model the agent first

Start the assessment with a data-flow diagram of the agent, not with the list. Draw every input the model can read, every place it can write, every tool and every other agent it talks to, and mark which inputs an outsider can influence. Then place the entries on the diagram. Most land on edges, not boxes: goal hijack enters on the untrusted-content edge, tool misuse and privilege abuse leave on the tool edge, poisoning goes in and out of the memory edge, and cascading failure is a property of the whole path.

Where the ASI risks land in a typical tool-using agentUser / operatorASI09 trustUntrusted contentweb, email, files: ASI01Agent runtimeLLM + planner: ASI01, ASI10Memory / RAG storeASI06 poisoningTool gatewaypolicy, approval, budgettool callsAPIs, DBsASI02, ASI03Code sandboxASI05Other agentsASI07Supply chain: models, MCP servers, plugins, promptsASI04ASI08 cascading failures travel along every arrow; the gateway is where most controls can be enforced and observed.
A tool-using agent with each ASI entry placed where it enters or leaves the system. The tool gateway sits on the path every action takes.

Two questions decide most of the risk. First, can untrusted content reach the model in the same context where it can call a high-impact tool? If yes, assume ASI01 will succeed eventually, because no prompt-level defence is reliable, and design so a hijacked agent still cannot do serious harm. Second, whose authority does each tool call carry? An agent that holds one broad service credential turns every successful hijack into a privilege escalation, the confused-deputy problem described in agent authorization.

Controls that cover several entries

Ten risks do not need ten products. A small number of architectural controls cover most entries, and placing them on the action path means they hold even when the model is fooled.

  • A tool-call gateway. Every call passes a policy check: is this agent allowed this tool, with these arguments, for this user, at this volume? It covers ASI02 and ASI03, contains ASI01 and ASI10, and is the natural place for ASI08 budgets.
  • Delegated identity. The agent calls tools with a token scoped to the user it serves and the task, not with a service account. This is the main ASI03 control.
  • Taint tracking. Mark a task as tainted once untrusted content enters its context. Tainted tasks lose high-impact tools or need human approval.
  • Isolation. Run generated code in a sandbox with no network by default and no credentials, as in sandboxing agents with Docker. This is ASI05.
  • Provenance and signing. Record the source of every memory write, and authenticate agent-to-agent messages with per-agent keys. This covers ASI06 and ASI07.
  • Supply-chain hygiene. Pin versions and hashes of MCP servers, plugins and prompt templates, and review tool descriptions as code, since they are instructions the model follows. This is ASI04.

A tool-call gateway

The sketch below shows the shape of such a gateway. It is deliberately small: scope check, call and spend budgets, a taint-aware approval step for high-impact tools, an append-only audit record of every decision, and execution with the user's token rather than the agent's.

import json, time
from dataclasses import dataclass

@dataclass
class Call:
    task_id: str
    agent_id: str
    user_id: str          # the human the agent acts for
    tool: str
    args: dict
    tainted: bool         # untrusted content entered this task's context

class ToolGateway:
    def __init__(self, scopes, high_impact, tools, approver, audit,
                 max_calls=30, max_spend=50.0):
        self.scopes, self.high_impact = scopes, high_impact
        self.tools, self.approver, self.audit = tools, approver, audit
        self.max_calls, self.max_spend = max_calls, max_spend
        self.calls, self.spend = {}, {}

    def decide(self, call):
        if call.tool not in self.scopes.get(call.agent_id, set()):
            return "deny: tool not in agent scope"                    # ASI02/ASI03
        if self.calls.get(call.task_id, 0) >= self.max_calls:
            return "deny: call budget exhausted"                      # ASI08
        cost = float(call.args.get("amount", 0))
        if self.spend.get(call.task_id, 0.0) + cost > self.max_spend:
            return "deny: spend budget exhausted"                     # ASI02/ASI08
        if call.tool in self.high_impact and call.tainted:
            return "approve" if self.approver(call) else "deny: approval refused"  # ASI01/ASI09
        return "allow"

    def invoke(self, call, user_token):
        verdict = self.decide(call)
        self.audit.write(json.dumps({"ts": time.time(), "task": call.task_id,
            "agent": call.agent_id, "user": call.user_id, "tool": call.tool,
            "args": call.args, "tainted": call.tainted, "verdict": verdict}) + "\n")
        if verdict not in ("allow", "approve"):
            raise PermissionError(verdict)
        self.calls[call.task_id] = self.calls.get(call.task_id, 0) + 1
        self.spend[call.task_id] = self.spend.get(call.task_id, 0.0) + float(call.args.get("amount", 0))
        return self.tools[call.tool](user_token, **call.args)         # user-scoped token

Two details matter. The approver must show the human what the call will do and why it is being asked, including the untrusted source that tainted the task; a bare yes or no prompt trains people to click yes, which is ASI09 in action. And the audit log is evidence for the assessment: you can count denials, approvals and budget hits per agent, and the same records drive ASI10 monitoring.

Turning the list into tests

Each entry becomes at least one test with a pass condition and an artifact you can show an auditor. Run the tests against the deployed system, with its real tools pointed at staging, not against the model in a notebook.

IDTestPass evidence
ASI01Plant instructions in a document the agent will readNo unapproved action; gateway log shows taint
ASI02Ask for 500 refunds of 1 dollarBudget denial in the log
ASI03User A asks about user B's accountDownstream API returns 403 under A's token
ASI04Swap an MCP server binary for an unsigned oneAgent refuses to load it
ASI05Get generated code to read environment variables or call outSandbox has none and no egress
ASI06Write a fake policy into memory, start a new sessionWrite tagged untrusted, not retrieved as policy
ASI07Replay or alter a message between agentsSignature or nonce check rejects it
ASI08Make one tool time out or return errorsBreaker opens, task fails cleanly
ASI09Review the approval screen for a risky callShows source, arguments and impact
ASI10Kill an agent mid-taskStops within the target time, no orphaned work

Worked assessment: a support agent

Consider a support agent that reads inbound tickets, searches a knowledge base, issues refunds up to 200 dollars, emails customers and asks a billing sub-agent for invoice details. Its memory stores summaries of past conversations per customer. Here is how an assessment of this illustrative system would run.

The threat model shows the ticket body is attacker-controlled and reaches the same context as the refund and email tools. That is the central finding: an ASI01 payload in a ticket can try to issue a refund to a different customer or email internal data out. The test confirms that before remediation the agent attempts both. The fix is not a better system prompt. Tickets mark the task tainted, refunds on tainted tasks need approval, the email tool only sends to the address on the ticket's own account, and refunds run under a token scoped to that customer, which also closes the cross-account ASI03 test.

The billing sub-agent accepts any JSON message on an internal queue, so a compromised component could ask it for any invoice: an ASI07 finding, fixed with per-agent signing keys and an allowlist of message types. Memory summaries are written from ticket text, so a ticket saying the customer is pre-approved for unlimited refunds could persist; the fix is tagging summaries as untrusted and never retrieving them as policy. The code sandbox and supply chain entries are judged not applicable because the agent runs no code and loads no external tools; the assessment records that decision and its reason, so the next review revisits it if the design changes.

The output is a table of ten rows, each with a status, the test that produced it, the evidence and an owner. Here four rows were findings, now fixed and retested (ASI01, ASI03, ASI06, ASI07), two were not applicable with reasons (ASI04, ASI05), and the remaining four (ASI02, ASI08, ASI09, ASI10) passed their tests. Re-running the same tests after each release is what makes it an assessment programme instead of a one-off review.

How assessments go wrong

  • Testing the model, not the system. A model that refuses a jailbreak in a playground proves nothing about the deployed agent with tools.
  • Checkbox coverage. Marking an entry covered because a guardrail product exists, without a test that exercises it.
  • Prompt-only fixes. Instructions such as ignore commands in documents reduce attempts but do not stop a determined payload; controls must sit outside the model.
  • Over-broad approvals. Asking a human about every call produces fatigue and blind approval, which converts ASI01 into ASI09.
  • Ignoring the not-applicable rows. They become applicable silently when someone adds a code tool or a new MCP server.
  • Tests that never fail. If a planted injection payload has never once produced an attempted action in your test logs, the payload is too weak or the test is not reaching the model. Keep one known-bad configuration that must fail, as a control for the test itself.
  • No owner. Findings that sit with the security team while the agent team ships weekly go stale within one release. Every row needs a named engineering owner.

Once the assessment exists, run it continuously. The gateway's audit log gives you the operational signals: denials per agent per day, approval rate and median time to approve, budget exhaustion events, and calls made by tainted tasks. A sudden rise in denials after a release usually means a prompt or tool description changed; a sudden fall in approval time usually means people have stopped reading. Alert on both, and review a sample of approved high-impact calls every week.

Trade-offs

Strong controls cost autonomy. Taint-based approvals slow the agent on exactly the inputs that make it useful, such as customer email. Tight budgets cause false denials on large legitimate tasks. Per-user tokens require identity plumbing many tool APIs do not support, and signing between agents adds key management. The practical balance is to rank tools by impact and reversibility, apply the strictest controls to the irreversible ones, such as payments, deletes and external messages, and let read-only tools run freely. The list itself is young; expect wording and ordering to change in later editions, so map your tests to the risks rather than hard-coding the numbers.

What to do next

  1. Draw the data-flow diagram of your agent and mark every attacker-influenced input.
  2. Place ASI01 to ASI10 on the diagram and note which are not applicable, with a reason.
  3. Put a tool-call gateway in front of every tool and log every decision.
  4. Replace service credentials with user-scoped, task-scoped tokens.
  5. Add taint tracking and require evidence-rich approval for high-impact calls on tainted tasks.
  6. Write the ten tests above against staging and run them on every release.
  7. Sign agent-to-agent messages and pin every external tool and server.
  8. Set call, spend and time budgets, and test the kill switch.
Key takeaway: The OWASP Top 10 for Agentic Applications names the risks of agents that act. Use it as an assessment: threat-model the agent, place each entry on the architecture, enforce controls on the action path with a tool gateway, scoped identity, taint tracking, sandboxing and signing, and keep one repeatable test with evidence per entry.