Skip to content

Agent guards

Arcjet is a runtime security platform for AI agents. Agent guards check each action your agent or application takes against your policies before the action runs, and they record every decision so that you can see what happened and why.

An agent turns model output into real actions: it sends email, issues refunds, queries databases, fetches URLs, and calls MCP servers. Those actions often run inside a tool handler, a queue consumer, or a workflow step, with no HTTP request for a firewall to inspect. The same applies to Arcjet’s own protect() function, which checks each HTTP request in your route handlers.

Agent guards cover those actions instead. Add a call to the Arcjet SDK’s guard() function immediately before the action, and pass it the values that matter, such as the recipient, the amount, or the user. Arcjet evaluates the Guard policy for that action and returns ALLOW or DENY. A Guard policy is the set of rules for one action, which your security team publishes and changes in the Arcjet Console without a deployment.

Agent guards add the following controls to your own agents and applications:

  • Deny an action based on application state that only your code knows, such as a refund over the user’s approval limit, an email to an external domain, a run that would exceed its spend budget, or a production change that nobody reviewed.
  • Act on findings from Arcjet’s detectors, which screen a value for threats, such as prompt injection in the message that triggered the action or sensitive information in a body that’s about to leave.
  • Screen sensitive information in your own process, so that the raw value never reaches Arcjet.
  • Score the hosts that a tool would contact with Arcjet IP threat intelligence, and deny high-risk destinations.
  • Rate limit actions per user, per tool, or per tenant, including actions that never arrive over HTTP.
  • Change a policy without redeploying the application, and run each rule in dry run, which records what it would deny without denying it, before you set it live.
  • Record each decision with the policy revision and the inputs it read, and record what an allowed action did afterward with capture events.

Each use case in the following table links to a worked policy that you can adapt.

Use caseExample policy
Let an email tool send only to approved domainsRestrict an email tool to approved domains
Stop customer data leaving in an external emailKeep sensitive data from leaving on an external send
Require approval for refunds over a limitKeep a refund inside an approval limit
Refuse a destructive tool when the prompt shows injectionAct on a prompt injection finding in context
Restrict a web fetch tool to trusted hostsRestrict a web fetch tool to trusted hosts
Deny requests to high-risk destinationsDeny a high-risk destination
Block DROP and DELETE statements from a database toolDeny a destructive database statement
Keep a file tool inside the workspaceConfine a file tool to the workspace
Allow only approved MCP serversRestrict which MCP servers a tool can reach
Require a role before a privileged actionRequire a role before a privileged action
Cap the spend of an agent runEnforce a spend budget
Require review before a production changeRequire review before a production change
┌──────────┐ guard() ┌──────────────┐ ALLOW ┌───────────────┐
│ Agent or │──────────▶│ Guard policy │────────▶│ Action runs │
│ workflow │ └──────┬───────┘ └───────────────┘
└──────────┘ │
│ DENY
▼
┌──────────────┐
│ Action stops │
└──────────────┘
  1. You call guard() immediately before the action, or wrap a tool with a framework integration, an Arcjet adapter for your agent framework that makes the call for you. The call names the action with a label, such as email.sent. It carries the actor, which is the user or service responsible, and the typed values that the policy reads, called inputs.
  2. Arcjet selects the published policy for that label and evaluates it at the edge, in the Arcjet region closest to your application. An input that you mark LOCAL never leaves your process, so the SDK evaluates it there.
  3. Arcjet returns one ALLOW or DENY decision. Your code, or the framework integration, runs the action only on ALLOW. A denied tool call returns a result the model can read.
  4. Arcjet records the decision with the policy revision and the inputs it read. It appears in the Console on the Activity page of your site, the Arcjet project that your ARCJET_KEY belongs to.

For the full call, the decision fields, and fail behavior, see Agent guards testing and reference.

A label is a stable, past-tense name for the action, such as email.sent or refund.issued. It selects the policy, so one policy owns each action.

The application sends each value the policy reads as a named, typed input: string, boolean, integer, number, or string list. A SERVER input is sent to Arcjet for evaluation. A LOCAL input stays in the SDK, and only a digest and the detector result leave your process. The actor is an identity your code asserts from authenticated server-side state, never from the model. For the full contract, see Policy contract.

A policy can declare Arcjet detectors and read their results as facts:

  • Prompt injection, over a SERVER string.
  • Sensitive information, either in the SDK over a LOCAL string or on Arcjet over a SERVER string.
  • IP threat intelligence, over the hosts that a call would contact. For more information, see Threat detection.

A rule can deny on a finding alone, or combine it with application state, such as denying a destructive tool only when the triggering message shows prompt injection.

You write a policy’s conditions in Rego, assemble them in the Console’s visual builder, or describe them in English and let Arcjet generate the builder rules. Arcjet runs a restricted Rego profile with no network calls, clock, or randomness, so the same inputs always produce the same answer. For the language, see Write policies in Rego.

Publication compiles the policy, runs its stored tests, and checks that the edge evaluator agrees with the Open Policy Agent evaluator before the policy goes out. For the authoring modes, tests, and revisions, see Author and publish policies.

You can also call SDK rules in code, such as rate limits, prompt injection detection, and sensitive information detection, in the same guard() call. The decision covers both.

You don’t need to start from an empty policy. The policy examples cover common agent actions with complete Rego. In the Console, you can describe what an action must refuse, or take a suggestion that Arcjet derives from the input names and types your application already sends. Coding agent policies have their own one-click starters; for more information, see Coding agent policies.

Each rule runs in LIVE or DRY_RUN mode. A dry run rule is evaluated and recorded but never denies, and new rules default to dry run. Publish a rule in dry run, review what it would have denied in the Console, and then set it live. A live expression rule needs at least one stored test before it can be published.

Arcjet has two entry points, and they protect different boundaries:

Agent guardsRequest protection
SDK callguard()protect()
ProtectsTool calls, agent actions, queue jobs, and workflow stepsHTTP routes and API requests
Selected byThe action’s labelEvery protect() call on the site
ReadsThe actor and the typed inputs you send, plus detector resultsThe request: IP, headers, path, and request signals
Remote configurationGuard policiesRemote rules

Most applications use both: request protection on their API routes, and agent guards inside the tool handlers, queue workers, and MCP tools behind them.

Every SDK offers the direct guard() call and framework integrations that place the same check around a tool for you.

SDKPackageFramework integrations
JavaScript/TypeScript@arcjet/guardVercel AI SDK, LangChain, LangGraph, Genkit, Google ADK, Cloudflare Think, OpenAI Agents, Strands Agents, TanStack AI, Vercel Eve, Mastra, Claude Agent SDK, and Claude Managed Agents
Pythonarcjet (arcjet.guard)LangChain, CrewAI, Google ADK, OpenAI Agents, Strands Agents, Claude Agent SDK, and Claude Managed Agents
Gogithub.com/arcjet/arcjet-goMicrosoft Agent Framework

To pick an adapter and see how each SDK reports a denial, see Agent guard framework integrations.

  • The direct guard() call fails open. If Arcjet can’t complete the check, it returns ALLOW marked as failed open, so check for that before a sensitive action. Framework integrations fail closed by default.
  • A policy reads only what the call sends. A label that matches no published policy evaluates no policy. A missing required input fails a live rule closed, and an input the policy doesn’t declare is dropped with a warning. To avoid typos, generate the call from the policy in the Console.
  • Arcjet doesn’t authenticate the actor. Derive it from your own authenticated session.
  • A LOCAL input’s digest is correlation data, not anonymization. A low-entropy value can be guessed and hashed.

For every fail behavior, see Availability and fail behavior.

To start, guard one tool call end to end, and then publish your first policy in dry run.