Skip to content

Agent guard remote policies

Agent guard remote policies let security teams change the policy applied to a guarded action without changing the tool implementation. Developers own the enforcement point and map application values into the policy contract; security teams own the policy selected by its label.

For each guarded action, security and development teams agree on:

  1. A stable label, such as email.sent.
  2. Whether the policy requires an actor.
  3. Named inputs, with a type and SERVER or LOCAL exposure.
  4. Rules over those values, each in LIVE or DRY_RUN mode.

Every Guard call includes the label so Arcjet can apply the matching published policy.

label identifies the action boundary and selects its remote policy. Use a hardcoded, past-tense action name such as email.sent or refund.issued. Labels use lowercase letters, digits, dashes, and dots, must start and end with a letter or digit, and are limited to 256 bytes.

actor is an optional opaque string asserted by trusted application code. It can represent the authenticated user, service, or tenant responsible for the action. The SDK does not derive it from a request or tool arguments and Arcjet does not authenticate the value for your application.

Every policy input is named and explicitly constructed. Plain values are rejected; the SDK does not inspect the tool schema or automatically discover arguments.

ExposureTypeJavaScript / TypeScriptPythonExample value
SERVERStringpolicyInput.server.string(value)server_input.string(value)"customer@example.com"
SERVERBooleanpolicyInput.server.boolean(value)server_input.boolean(value)true
SERVERIntegerpolicyInput.server.integer(value)server_input.integer(value)3
SERVERNumberpolicyInput.server.number(value)server_input.number(value)49.95
SERVERString listpolicyInput.server.stringList(value)server_input.string_list(value)["a@example.com", "b@example.com"]
LOCALStringpolicyInput.local.string(value)local_input.string(value)"Email body to inspect"

For example, an email policy can receive a selected recipient, the trusted allow list to compare it with, and a message body that stays local:

inputs: {
recipient: policyInput.server.string(recipient),
allowed_recipients: policyInput.server.stringList(allowedRecipients),
body: policyInput.local.string(body),
}

SERVER and LOCAL describe where policy evaluates an input and whether its raw value is sent to Arcjet.

The typed value is sent to Arcjet for server-side policy evaluation. A call containing only server inputs does not need to fetch a local policy projection. Use server inputs only for values Arcjet is allowed to receive.

The raw string remains in SDK memory. The SDK evaluates the downloaded policy projection locally and sends a domain-separated SHA-256 digest plus rule attestation. For sensitive information detection, the attestation includes denied entity types and offsets, not the matched raw values.

Agent guard remote policies currently support:

RuleExecutionWhat it evaluates
Allowed string valuesServerA string against an allow list using exact or email-domain matching
Denied string valuesServerA string against a deny list using exact or email-domain matching
String lengthServerMinimum and maximum UTF-8 byte length
String-list membershipServerWhether one string is a member of a supplied string-list input
Prompt injectionServerOne named server string
Sensitive informationLocalOne named local string with allowed or denied entity types

Each rule can be LIVE, where a denial contributes to the final decision, or DRY_RUN, where it is evaluated and reported without blocking.

Generic URL allow/deny rules, command or shell rules, remote custom rules, and remote rate limits are not currently supported. SDK rules configured in code remain available and can be submitted alongside a remote policy.

Configure two SERVER inputs—a string named recipient and a string list named allowed_recipients—then add a string-list membership rule requiring the recipient to appear in the list.

inputs: ({ recipient }) => ({
recipient: policyInput.server.string(recipient),
allowed_recipients: policyInput.server.stringList(user.allowedRecipients),
})

Block sensitive data before it leaves the tool

Section titled “Block sensitive data before it leaves the tool”

Configure a LOCAL string input named body, then add a sensitive information rule with the entity types the tool must not send. The policy evaluates the raw body locally.

inputs: ({ body }) => ({
body: policyInput.local.string(body),
})

Check the instruction that triggered an action

Section titled “Check the instruction that triggered an action”

Configure a SERVER string input named incoming_message, then add a prompt injection rule over that input. Resolve the message from the application-owned agent run rather than from a model-generated tool argument.

inputs: (toolInput) => ({
incoming_message: policyInput.server.string(incomingMessage),
})

One email.sent policy can combine all three rules above. The integration maps the current agent run and generated tool arguments into the policy before the framework executes the tool:

const sendEmail = guardTool(arcjet, sendEmailTool, {
label: "email.sent",
actor: currentUser.id,
inputs: ({ recipient, body }) => ({
recipient: policyInput.server.string(recipient),
allowed_recipients: policyInput.server.stringList(
currentUser.allowedRecipients,
),
body: policyInput.local.string(body),
incoming_message: policyInput.server.string(incomingMessage),
}),
});
const tools = { sendEmail };
const result = await generateText({
model: "openai/gpt-4o-mini",
prompt: incomingMessage,
tools,
toolsContext: aiToolsContext(createAgentContext(), tools),
});

The actor, allowed recipients, and incoming message come from application-owned context. Only recipient and body come from the model’s validated tool call. If any LIVE rule denies, the integration prevents sendEmailTool from executing.

Arcjet has two separate remote configuration systems:

Agent guard remote policiesRequest Remote rules
SDK callguard()protect()
ScopeOne action labelA site and its HTTP requests
ContextTrusted actor and explicit typed inputsRequest metadata and supported request signals
ConfigurationAgent guard policyRemote rules

Request Remote rules protect HTTP requests. Agent guard remote policies protect tool calls and other actions that use guard().

When a usable policy is available, temporary connectivity issues do not cause the SDK to discard it.

If policy evaluation is incomplete or unavailable, the direct client returns an observable failed-open decision. Framework wrappers fail closed by default. See Availability and fail behavior.