Skip to main content
A firewall policy is an ordered list of rules, and a rule is just a small bag of fields: which tool calls it matches, on which surface, and what to do about them. When you need to read a rule someone else wrote — or reason precisely about one you’re building — you want the field list in one place. That’s this page. You author rules in the console rule editor (writes require Developer+); the editor writes the structured fields below. This page is the field-level map; the deep matching engine lives in Firewall Rules.

1. The firewall rule schema at a glance

Every rule carries the same fields. Only verdict is always required — everything else narrows what the rule matches or configures the chosen verdict, and an absent matcher is vacuously true.
FieldPurpose
priorityEvaluation order — lower runs first.
verdictThe action when the rule matches (required).
stageThe surface to scope to; empty = all.
tool_name_globGlob on the tool name.
args_match_jsonJSONPath argument predicate, as a JSON-encoded string.
egress_jsonHost / CIDR allow-deny list (egress rules), as a JSON-encoded string.
sanitize_jsonRedaction config (when verdict = sanitize), as a JSON-encoded string.
cap_cost_centsRun-cost ceiling in USD cents (when verdict = cap_cost).
sequence_jsonOrdered multi-step chain predicate (sequence rules), as a JSON-encoded string.
label / notesHuman name and rationale — shown in events, ignored by the engine.
A rule fires when all of its declared matchers hold at once — the stage matches (or is empty), the tool glob matches, the argument clauses match (or are absent), and the egress scope matches (egress rules only). The engine walks rules in priority order and the first match wins; if nothing matches, the policy’s default_verdict applies.

2. priority — evaluation order

An integer ordinal. Lower runs first; two rules with the same priority break the tie by rule id (insertion order). Put your specific carve-outs above your broad catch-alls — an allow for one trusted tool at priority 10 beats a deny * at priority 100.
Leave gaps (10, 20, 30) so you can slot a new rule between two existing ones later without renumbering the whole policy. See Rule priority for ordering strategy.

3. verdict — the action

The one required field. When a rule matches, its verdict decides what happens to the call:
VerdictEffect
allowLet the call through, logged.
auditAllow and record for review — the usual default_verdict.
denyBlock the call.
sanitizeRedact matched substrings from the tool arguments, then forward.
pending_approvalHold the call for a human reviewer.
cap_costDeny once an agent run’s accumulated spend crosses a cap.
A deny returns HTTP 400 firewall_blocked on the inbound surface, or a tool error on the mcp surface. A held call returns HTTP 400 firewall_approval_pending with an id the agent polls on. In shadow mode every enforcing verdict is downgraded to audit and the reason is prefixed [shadow] would …. See Verdicts for the full table and the block shapes.

4. stage — the enforcement surface

Pins the rule to one of the firewall’s surfaces. Leave it empty and the rule applies to all surfaces:
The tools an agent advertises to the model on the request. Block a dangerous tool before the model can even choose it.
The tool_calls the model emits in its reply.
A tools/call routed through the Firewall MCP gateway.
An outbound host / IP / CIDR a tool reaches — the SSRF and data-exfiltration surface.
Some verdict + stage pairings are rejected on save because the verdict can’t fire there: cap_cost is a pre-dispatch run-cost ceiling, inert on response and egress; pending_approval only ever holds at inbound, so an explicit response/egress pin is refused. The editor hides these combinations; the API rejects them. See Stages.

5. tool_name_glob — which tool

A small, case-sensitive glob on the tool name — shell.* for a whole family, *.delete for a verb across servers, http_fetch for one exact tool. Empty or * matches every tool. An optional skill name glob (same grammar) AND-s a second condition on the owning skill, so you can trust a tool from a built-in skill and gate it from a community one. The full grammar — prefix, suffix, infix, exact, and the edges that trip people up — is its own reference: Glob pattern syntax.

6. args_match_json — with what arguments

The glob answers which tool; args_match_json answers with what arguments — the difference between “block shell.exec” and “block shell.exec only when the command is rm -rf.” Its value is a JSON-encoded string carrying a set of JSONPath clauses, all AND-ed. Decoded, the clause object looks like:
{
  "clauses": [
    { "path": "$.command",    "op": "regex",      "value": "rm -rf|drop table" },
    { "path": "$.connection", "op": "in",         "value": ["prod", "replica"] },
    { "path": "$.ip",         "op": "cidr_match", "value": "10.0.0.0/8" }
  ]
}
In a request body the field carries that object as an escaped string, e.g. "args_match_json": "{\"clauses\":[{\"path\":\"$.command\",\"op\":\"regex\",\"value\":\"rm -rf\"}]}". Operators are eq, contains, regex, in, cidr_match, gt, and lt. An absent args_match_json is vacuously true — the rule matches on the glob alone. The full predicate language, path syntax, and the fail-closed behavior of a broken clause are in Validate arguments and the argument cookbook.

7. egress_json — which destinations

Used on the egress surface: a JSON-encoded string holding a host / CIDR allow-and-deny list matched against an outbound destination a tool reaches. Decoded, the object looks like:
{
  "deny":  ["169.254.169.254", "10.0.0.0/8"],
  "allow": ["api.openai.com"]
}
Entries match as a CIDR, an IP literal, or a case-insensitive hostname. The polarity follows the verdict — with an enforcing verdict the deny list defines what’s blocked and allow carves exceptions out of it.
The Baseline firewall template ships an egress deny rule with a ready-made SSRF / cloud-metadata denylist (the metadata IP 169.254.169.254, RFC-1918 ranges, loopback, link-local, and metadata.google.internal), so you don’t have to hand-author those. Add your own destinations on top for anything else you want to gate. See Egress control for the full recipe and Data exfiltration for why it matters.

8. sanitize_json — redact arguments

Used when verdict = sanitize: a JSON-encoded string naming which presets / custom regexes redact matched substrings from the tool arguments before the cleaned call is forwarded — useful for stripping a secret or a PII value an agent dropped into an argument without blocking the whole action. Decoded, the object looks like:
{ "presets": ["email", "ssn_us"], "custom": ["foo-\\d+"] }
Sanitize redacts arguments only — never the content a tool returns. A sanitize rule must name at least one preset or custom pattern (an empty sanitizer is rejected). On the inbound surface there are no call-time arguments to redact, so a sanitize verdict there escalates to a deny.
See Sanitize responses for the preset library and redaction shapes.

9. cap_cost_cents — a spend ceiling

Used when verdict = cap_cost: a per-rule run-cost ceiling, an integer in USD cents. When the rule matches, the call is denied once the agent run’s accumulated spend crosses the cap — a circuit-breaker for a runaway loop, resolving to allow or deny in events. The cap must be explicit and non-negative, and the rule can’t be pinned to response or egress (where the verdict is inert). Full behavior in Cap cost.

10. One complete rule

Putting the fields together — deny shell.exec, but only when the command looks destructive, scoped to the model’s emitted tool calls:
{
  "priority": 10,
  "label": "block destructive shell",
  "stage": "response",
  "tool_name_glob": "shell.exec",
  "args_match_json": "{\"clauses\":[{\"path\":\"$.command\",\"op\":\"regex\",\"value\":\"rm -rf|mkfs|:\\\\(\\\\)\\\\{\"}]}",
  "verdict": "deny",
  "notes": "fork bombs and recursive deletes only — plain shell.exec audits"
}
The stage matches the response surface, the glob picks shell.exec, the single clause narrows to a destructive command, and the verdict denies. Any shell.exec whose command doesn’t match the regex falls through to the next rule or the policy default. Attach a key to the policy (firewall_policy_id on the key) and it’s live on the next call — no redeploy.
Confirm a rule fires on exactly what you expect before you depend on it: Test rules dry-runs a policy against a sample tool call and returns the verdict, the matched rule, and the reason without dispatching anything.

11. How the fields combine

A verdict. Everything else is optional: an empty stage matches all surfaces, an empty tool_name_glob (or *) matches every tool, and an absent args_match_json matches any arguments. A bare { "verdict": "audit" } is a valid catch-all.
They AND. A rule fires only when its stage, tool glob, skill glob, argument clauses, and egress scope all hold. To express OR, write separate rules.
sanitize_json is read only for the sanitize verdict; cap_cost_cents only for cap_cost; egress_json only on the egress surface. The console validates these pairings on save, so a rule that displays one behavior but can never enforce it can’t be persisted.
The lower priority wins (ties broken by rule id) — first match wins, and evaluation stops there. See Rule priority.

Create a policy

Author your first policy and attach a key.

Glob syntax

The full tool name glob grammar.

Verdicts

Every verdict and what a block looks like.

Validate arguments

JSONPath argument clauses in depth.

Manage policies

Edit, version, and revert policies.

Firewall Rules

The complete matching engine reference.
New to the action plane? Start at the Firewall overview, or see how it pairs with text screening in Guardrails vs Firewall.