Your Agent's Tools Are Its Real Permissions. Scope Them Accordingly.
A model that can call tools has exactly the authority of those tools — not the authority you intended, and not the authority its prompt politely requests. The gap is where agentic incidents live.
There is a comforting way to secure an agent that fails quietly: write a careful system prompt. Tell the model what it must never do, list the forbidden actions, add a stern paragraph about safety, and feel protected. The system prompt shapes behaviour, and on a good day it shapes it well. What it does not do is constrain power. The model's real permissions are not in its instructions. They are in its tools.
A model that can call a tool has exactly the authority that tool carries — no more because the prompt was polite, and no less because the prompt forgot to mention it. The prompt is a request the model may or may not honour. The tool is a grant the model can always spend. When those two disagree, the tool wins, and the gap between the authority you intended and the authority you actually conferred is where agentic incidents live.
Tools are the attack surface
On its own, a language model only produces text. It is a strong autocomplete with no hands. The moment you connect it to tools — functions it can invoke, APIs it can reach, a shell it can drive — it gains the ability to act on the world, and your security problem changes shape entirely. The attack surface of an agent is not the prompt and not the model weights. It is the union of everything its tools can do.
That surface is reached through a planner you cannot fully trust. Because of prompt injection, the text that decides which tool to call and with what arguments can be influenced by untrusted content the model has read. So you must assume that any tool the agent holds can be invoked at an attacker's chosen moment, with arguments the attacker had a hand in. The right mental model is not can the model be convinced to misbehave but what can the tools do when something convinces it.
The agent is a confused deputy
This is an old problem wearing new clothes. A confused deputy is a privileged program tricked by a less-privileged party into misusing its authority — the classic example is a compiler with permission to write to a protected directory, fooled into overwriting a file it should have refused. The deputy is not malicious. It is confused about whose intentions it is serving.
An LLM agent is a nearly perfect confused deputy. It holds credentials and can call privileged tools. It is, by design, instructable — built to follow directions expressed in ordinary language. And it reads untrusted content as part of its normal work. Put those together and you have a privileged actor that takes direction from whoever can get text into its context. The agent executes with its own authority, on behalf of an attacker, and every individual step looks legitimate.
Authorization belongs outside the model
The instinct is to fix this inside the prompt: only call the delete tool if the user is an administrator. That is not authorization. It is a wish. It depends on the model correctly determining who the user is, correctly remembering the rule, and not being talked out of it by a later instruction — three things you cannot guarantee and an attacker will attack.
Authorization has to be deterministic code that sits between the model's proposal and the tool's execution, checks the acting identity and its permissions against a policy, and refuses calls that fall outside it — regardless of how persuasively the model asked. The model proposes; the policy layer disposes. The model's job is to decide what it wants to do. Deciding whether it is allowed to is not the model's job and never can be.
A tool call is not a suggestion the model makes to itself; it is an action your system takes with your credentials, and only your code — never the prompt — can decide whether that action is allowed.
Scope per tool, not per agent
Agents are too often given one broad credential and a pile of tools that all ride on it. A single compromise then reaches everything. Scope belongs at the level of the individual tool, not the agent as a whole.
- Per-tool credentials — each tool holds its own minimal credential rather than sharing one over-powered token, so compromise of one path does not unlock the others.
- Bind to the end user — a tool should act with the permissions of the human it is serving, not a superuser service account that can see every tenant at once.
- Narrow the data domain — a lookup tool should read the single record the task needs, enforced on the server, not trusted to read only what the model claims it will.
- Separate read from write — different tools, different credentials, different gates; a read that leaks is recoverable, a write that is abused often is not.
- No capability by default — a tool exists because the task requires it; unused reach is removed rather than left connected and dormant for an attacker to find.
Validate parameters like any untrusted input
The arguments to a tool call are attacker-influenced data. The model emits them, and injection can steer them, so they deserve exactly the scrutiny you would give any value arriving at an API boundary from the open internet. Type-check them. Allowlist the permitted values. Bound the ranges. Canonicalize and constrain any path. Reject anything outside policy before the tool runs.
Skip this and the classic injection families come straight back, because the model is now the thing supplying the dangerous parameter. A tool that accepts a file path and receives a traversal sequence reads files it should never touch. A tool that accepts a fragment of a database query becomes a query-injection sink. The model did not need to be jailbroken in some exotic way; it merely passed through a malicious value, and nothing deterministic was standing at the tool boundary to catch it.
Dangerous tools need a second gate
Not every tool carries the same blast radius, and your controls should reflect that. Classify tools by what an abusive call would cost. A read against low-sensitivity data can run freely. An action that is irreversible or high-impact — sending a message to an external party, moving money, deleting records, granting access — should sit behind a second gate: an explicit human confirmation, or a stronger policy such as dual control or an out-of-band check.
The discipline is to gate the few actions that matter rather than all of them, so the confirmation stays meaningful instead of decaying into a reflex. And the gate must present the real, validated parameters — the actual recipient, the actual amount — not the model's paraphrase of its own intent. A confirmation that trusts the model's summary of what it is about to do is theatre.
A defensible tool layer
A defensible agent treats its tool layer as the security boundary it actually is. Every tool is catalogued with the authority it carries. Each one holds a scoped credential bound to the acting identity. A deterministic policy layer stands between proposal and execution and enforces what the prompt can only request. Parameters are validated at the boundary. The handful of dangerous tools pass a real gate. The system prompt is left to do what it is good at — guiding behaviour — and relieved of a security burden it was never able to carry.
When 6QURE reviews an agentic system, the tool layer is where the hours go: enumerating every tool the agent can reach, following the credential behind each one to see what it could touch if the call were hostile, and checking that authorization lives in code rather than in careful wording. The question is never whether the model can be tricked. It is what the tools let it do once it has been — and whether anything deterministic is there to say no.
Facing something like this in your own environment?