1. The firewall rule schema at a glance
Every rule carries the same fields. Onlyverdict is always required —
everything else narrows what the rule matches or configures the chosen
verdict, and an absent matcher is vacuously true.
| Field | Purpose |
|---|---|
priority | Evaluation order — lower runs first. |
verdict | The action when the rule matches (required). |
stage | The surface to scope to; empty = all. |
tool_name_glob | Glob on the tool name. |
args_match_json | JSONPath argument predicate, as a JSON-encoded string. |
egress_json | Host / CIDR allow-deny list (egress rules), as a JSON-encoded string. |
sanitize_json | Redaction config (when verdict = sanitize), as a JSON-encoded string. |
cap_cost_cents | Run-cost ceiling in USD cents (when verdict = cap_cost). |
sequence_json | Ordered multi-step chain predicate (sequence rules), as a JSON-encoded string. |
label / notes | Human name and rationale — shown in events, ignored by the engine. |
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.
3. verdict — the action
The one required field. When a rule matches, its verdict decides what
happens to the call:
| Verdict | Effect |
|---|---|
allow | Let the call through, logged. |
audit | Allow and record for review — the usual default_verdict. |
deny | Block the call. |
sanitize | Redact matched substrings from the tool arguments, then forward. |
pending_approval | Hold the call for a human reviewer. |
cap_cost | Deny once an agent run’s accumulated spend crosses a cap. |
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:
inbound — advertised tool definitions
inbound — advertised tool definitions
The tools an agent advertises to the model on the request. Block a
dangerous tool before the model can even choose it.
response — model-emitted tool_calls
response — model-emitted tool_calls
The
tool_calls the model emits in its reply.mcp — tools/call dispatch
mcp — tools/call dispatch
A
tools/call routed through the
Firewall MCP gateway.egress — outbound destination
egress — outbound destination
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:
"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 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:
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 — denyshell.exec, but only when the command
looks destructive, scoped to the model’s emitted tool calls:
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.
11. How the fields combine
What's the minimum a valid rule needs?
What's the minimum a valid rule needs?
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.Do the matchers AND or OR?
Do the matchers AND or OR?
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.
Which fields pair with which verdict?
Which fields pair with which verdict?
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.What if two rules both match?
What if two rules both match?
The lower
priority wins (ties broken by rule id) — first match wins,
and evaluation stops there. See
Rule priority.Related
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.
