AxioRankDocs

Policies

Turn a risk score into an enforceable verdict per agent, tool, and request attribute.

Content inspection produces a risk score and signals; a policy turns that into a verdict (allow, deny, or require_approval) for a given tool, agent, and set of request attributes. Policies are authored in the dashboard (Outbound → Policies) or over the workspace API.

Not part of the public gateway contract

Policy CRUD is a workspace-authenticated control-plane API (session or an API key with policies:read / policies:write), not part of the versioned gateway contract. The shapes below are the source of truth.

Anatomy of a policy

FieldTypeNotes
namestring1–120 chars.
toolPatternstring (glob)Matches the tool name; * matches one or more characters (github.*, aws.delete_*, exact gmail.send).
actionallow · deny · require_approval · redactThe verdict when the rule fires. redact masks matched PII/secrets in a model completion and passes it through; it is the weakest enforcement action, overridden by both deny and require_approval.
riskThresholdint 0–100 · nullFallback rule: deny when the call's risk ≥ threshold. null for a non-threshold rule.
signalCategorysecret · pii · destructive · injection · egress · malware · financial · nullFire only when a detector flagged that category.
contextobject · nullAttribute conditions (ABAC). See below.
priorityintLower is evaluated first. Default 100.
enabledbooleanDefault true.
enforcementModemonitor · enforceenforce (the default for hand-authored rules) acts on the verdict immediately; monitor records the would-be decision without blocking, for safe rollout. AI-proposed rules are minted as monitor.

How a verdict is reached

Enabled rules whose toolPattern and context match the call are evaluated in priority order (lowest number first) under deny-overrides:

  1. A matching deny wins: the call is blocked.
  2. Otherwise a matching require_approval holds the call for a human (the SDK waits the hold out and resolves to the final allow / deny).
  3. Otherwise a matching allow passes the call.
  4. If no rule sets a verdict, the highest-priority riskThreshold rule denies when the call's risk ≥ its threshold.
  5. Otherwise, allow.

Explicit rules (no signalCategory) take precedence over signal-aware ones, so a blanket deny can't be undercut by a narrower signal rule.

Attribute conditions (ABAC)

A policy's optional context fires the rule only when the request satisfies every constraint present (AND). Each set constraint supports negate.

ConstraintShapeMatches
ip{ anyOf: string[], negate? }Source IP in a CIDR list (or exact IPv4).
geo{ anyOf: ["US","DE"…], negate? }Caller country (ISO-3166 alpha-2), resolved at the edge. Deny-on-unknown, like ip.
time{ windows: [{ days?, start, end }], tz?, negate? }Time-of-day windows in an IANA tz (default UTC); a window wraps past midnight when end ≤ start.
resource.environment{ anyOf: ["production"…], negate? }The target's environment, from the MCP server registry.
resource.type{ anyOf: ["database","http_api","filesystem","messaging","other"], negate? }The target's resource type.
resource.host{ anyOf: string[], negate? }Destination host; *.corp.com matches that suffix or below.
agent.labels{ anyOf: string[], negate? }The governing agent's identity labels (case-insensitive).
mlThreatClass{ anyOf: ["prompt_injection","jailbreak","data_exfiltration","malware","social_engineering","policy_violation"] }The agent's most recent ML threat assessment. Fail-open when no assessment exists.
args[{ path, …operators, negate? }]Argument-value least-privilege on the call's inputs. See Argument-value constraints below.
chain{ anyOf?, valueConfirmed?, minSeverity? }This call would complete a multi-step kill chain. See Kill-chain constraints below.
ifc{ propagation?, sinkTypes?, destinations?, sourceTags? }Untrusted-tainted data reached a guarded sink. Read by the engine's information-flow tiers rather than matched like the constraints above, so a * tool pattern does not become a global rule. See Detection intelligence.
commerce{ onViolation?: boolean }A recognized purchase falls outside the agent's active mandate. Fail-open when no purchase is recognized.

A combined example that holds any production-database write outside business hours:

{
  "name": "Approve prod DB writes off-hours",
  "toolPattern": "db.*",
  "action": "require_approval",
  "context": {
    "resource": {
      "environment": { "anyOf": ["production"] },
      "type": { "anyOf": ["database"] }
    },
    "time": {
      "windows": [{ "days": [1, 2, 3, 4, 5], "start": "09:00", "end": "18:00" }],
      "tz": "America/New_York",
      "negate": true
    }
  },
  "priority": 50,
  "enabled": true
}

Argument-value constraints

args narrows a rule to the tool's inputs, not just which tool. Each entry selects a value by dot-path into the call's arguments and constrains it; all entries are ANDed. This holds any s3.put_object writing outside the public- prefix:

{
  "name": "Approve non-public S3 writes",
  "toolPattern": "s3.put_object",
  "action": "require_approval",
  "context": {
    "args": [{ "path": "params.bucket", "glob": "public-*", "negate": true }]
  }
}

Each entry supports set membership (anyOf), glob, regex, contains, numeric bounds (gte / lte / gt / lt), and exists, with an optional negate. A set guard is deny-on-unknown (an absent argument leaves the allowlist unmet); the numeric, glob, regex, and contains operators fail open on a missing or non-coercible value, so a malformed call never denies by accident.

Information-flow constraints

ifc fires when data that entered the run from an untrusted source reaches a guarded sink. It is the guard for indirect prompt injection: the payload arrives in a fetched page or an inbound email, so no content rule on the outbound call would flag it.

{
  "name": "Hold untrusted data reaching egress",
  "toolPattern": "*",
  "action": "require_approval",
  "enforcementMode": "monitor",
  "context": { "ifc": { "propagation": "coarse", "sinkTypes": ["egress"] } }
}
FacetShapeMeaning
propagationexplicit · coarseexplicit needs a specific value to provably reappear at the sink. coarse fires when any untrusted data was seen earlier in the run: full recall on injection, and correspondingly more false positives. Defaults to explicit.
sinkTypes["egress","destructive","state_change"]Which sinks are guarded. Omitted means all of them.
destinationshost globsNarrow to specific destinations, matched like resource.host. Omitted means any.
sourceTags["web_fetch","inbound_email",…]Narrow to specific provenance. Omitted means any.

Two behaviors differ from every other predicate:

  • A * tool pattern is safe. ifc is not matched the way the constraints in the table above are; the engine reads it in its own evaluation tiers, so the rule fires only on an untrusted-to-sink flow rather than on every call.
  • An allow rule is an endorsement. It releases flows a hold rule would otherwise stop, which is how an approved flow stops being re-held. It can never override a deny. Scope it with sourceTags and destinations so it endorses only the flow you meant.

Like kill-chain rules, ifc rules cannot be backtested: replay scores each logged call alone and history has no record of what was tainted at the time. Use enforcementMode: "monitor" and the shadow-impact panel.

Kill-chain constraints

Every other predicate looks at one call. chain looks at the run: it fires when the call in hand would complete a dangerous ordered sequence, such as a sensitive read followed by an egress. That makes it the only way to stop an attack whose individual steps each look unremarkable, which is the usual shape of agent exfiltration.

{
  "name": "Hold proven exfiltration chains",
  "toolPattern": "*",
  "action": "require_approval",
  "enforcementMode": "monitor",
  "context": { "chain": { "anyOf": ["exfiltration"], "valueConfirmed": true } }
}
FacetShapeMeaning
anyOf["exfiltration","recon_then_destroy","injection_then_action"]Which patterns satisfy the rule. Omitted means any.
valueConfirmedbooleanRequire the value-level proof: a specific value read at an earlier step provably reappears in this call. Near-zero false positives, and only reachable with information-flow control enabled.
minSeveritylow · medium · high · criticalSeverity floor. Defaults to high, which is every pattern the detector emits today, so critical is the meaningful tightening.

Three things are worth knowing before you enable one:

  • A * tool pattern is safe here. The constraint is evaluated like any other, so a chain rule simply does not apply to a call that completes no chain. It is the narrowest rule in your list, not the broadest.
  • It holds the finale, not the sequence. The earlier steps have already run. A chain rule stops the call that would complete the attack; it cannot undo what came before. For that reason an approval on a chain hold releases only that one call and never mints a blanket grant.
  • It can't be backtested. Replay scores each logged call on its own, and history carries no record of what a run's earlier steps had done, so a chain draft reports zero matches even when it will fire in production. Use enforcementMode: "monitor" and the shadow-impact panel instead.

Every workspace is seeded with a disabled chain-hold-proven-exfiltration template in monitor mode, which is the recommended starting point.

More predicates

A policy context also carries the spend and behavior predicates documented on their own pages: budget and model / callCostUsd (see Budgets and Spend governance), plus agent identity (ids, labels, attributes), agentRisk, agentDaysOld, and novelty. Every predicate present is ANDed, and any one absent leaves the rule behaving exactly as before.

Test before you ship

  • POST /api/policies/simulate: dry-run a tool call against your live policy set; returns the decision, reason, risk, signals, and which policy matched.
  • POST /api/policies/backtest: replay a draft rule over recent audit logs and report how many decisions would flip, before you enable it.
  • POST /api/policy-suggestions/generate: mine recent traffic for candidate rules; accept or dismiss each via PATCH /api/policy-suggestions/{id}.

Next steps

On this page