AI agent security
Your AI agents hold real tools. Guard the run, not the request.
AI agents change the risk model: loops of many requests, tool calls that touch real systems, cost and permissions accruing across a whole run. A per-request content filter cannot see any of that – the dangerous pattern is spread across steps. The proxy tracks and enforces the run.
The run graph: what your agent actually did.
Because every loop iteration resends the full context, the proxy assembles a near-complete trace of the run as it unfolds – every step, every tool call with its risk tier, every violation, the cost burn-down. Most teams have never seen this picture of their own agent, and the gap between it and what they believed is where the incidents live.
The same graph is the enforcement substrate: budgets read the run’s totals, the loop guard reads its call history, sequence policies replay over it, and the audit trail is simply the graph, kept.
- #1 openai/gpt-4o okread search_orders {"order_id":"4471"} ↻2
- #2 openai/gpt-4o okinjection
- #3 openai/gpt-4o oknetwork send_email {"to":"<EMAIL_ADDRESS_1>"}taint
- #4 checkpoint blockedpayment pay_via_bank {"iban":"DE89…"}ungrounded
- injection
poisoned tool result, step 2 - taint
screened email leaving via send_email - ungrounded
IBAN absent from the run’s sources - ↻ repeat
same call fingerprint as step 1
Most of the value needs no diagram of your workflow. These properties hold in any agent, the way a firewall does not need your business logic to be useful:
Tool policy & schemas
Per-API-key allow/deny lists (glob patterns) and validation of every tool call’s arguments against the declared JSON schema. No policy configured = allow everything – nothing gets stricter until you say so.
Permission tiers
Tools are risk-tiered read < network < write < exec < delete < payment. Calls above the key’s ceiling are flagged or blocked; payment and delete tiers can require human approval before they run.
Tool-result injection scan
A tool result – an order note, a web page, an email – is untrusted input. It is injection-scanned before it re-enters the model’s context and steers the next iteration.
Action grounding
A payment’s IBAN, a recipient’s email, an amount, an ID – must appear in the run’s sources. An argument the agent never legitimately read is fabricated or injected, and it does not execute.
Taint tracking
Screened PII, detected secrets, and the system-prompt canary must not leave through tool arguments. A per-key map says exactly which entity types each tool may receive.
Loop guard & run budgets
Identical calls repeating past a threshold are caught as runaway loops, and hard per-run cost / step / tool-call caps are checked before the next model call spends anything.
“Payment only after vendor lookup” needs intent. There are three ways to get it, in ascending integration effort – and they stack:
In-band plan (judge)
The rules are usually already in the system prompt – “verify inventory before confirming”. A cheap judge checks each tool call against the stated instructions. Zero integration.
Declared sequence policies
A small grammar – pay requires lookup_vendor, send_email max 3 calls – enforced as a state machine over the run’s tool history. Authored in the dashboard, or compiled automatically from your n8n workflow export.
Learned baselines
After enough observed runs, the proxy fingerprints normal behavior – typical tools, sequences, cost envelope – and flags deviation. Catches the drift declared policies miss. Shadow-only: it never blocks.
Four gates, one action.
Pick a proposed agent action and watch the outbound stages evaluate it under PREVENT and FIX. An injected payee, a tainted email, a poisoned refund – each fails a different, independent check.
The posture is observe-first: run in FIX, read what would have been caught, then flip the checks that matter to PREVENT.
- allowtool_policypassed
- denypermission_checkpayment tier – over authorized ceiling
- denyaction_groundingIBAN appears nowhere in the run’s sources
- allowtaintpassed
Prevent blocks the offending action and returns a 422 the caller can’t ignore.
How can a per-request proxy secure a multi-step agent?
Agent loops are stateless: every iteration resends the entire accumulated context – prior turns, tool calls, results. Correlated by a session id, the proxy reconstructs the whole run as it unfolds and enforces run-level rules: budgets, loops, ordering, and per-run audit.
What stops a prompt-injected agent from acting?
Defense in depth. The injected text is scanned at the boundary; if it still steers the model, the resulting tool call has to pass policy, permission tiers, action grounding (the payee must exist in the run’s sources), and taint checks. One successful injection still has to beat four independent gates to become an action.
Do I have to describe my workflow up front?
No. The invariant checks hold in any workflow with zero knowledge of intent. When you want ordering enforced, state it as a sequence policy or upload your n8n export and it compiles into one – and learned baselines cover the drift nobody declared.
What about steps that never touch the LLM?
The checkpoint API is a policy decision point for exactly those: your workflow asks “may I proceed?” with the proposed action and gets allow, deny, or require-approval from the same policy engine – via an n8n community node, a LangChain callback, or a plain SDK call. It lands in the same run graph.
Will this break existing non-agent traffic?
No. Every agent check is observe-by-default: it flags in FIX, blocks in PREVENT, and skips entirely when unconfigured. Ordinary chat completions pass through unchanged.
See your agent’s run graph.
Point your agent at the proxy in observe mode – the first run graph usually settles the argument.