Skip to content

Writing policy rules

A kilasec policy is an ordered list of rules. For each incoming AI request, the engine evaluates rules top-to-bottom and applies the first one that matches. (Iptables / Squid ACL semantics — first match wins, default action at the bottom catches anything not matched above.)

The shape of a rule

In YAML — what you see if you open the Editor on Policy Rules:

yaml
- name: redact_pii_on_egress
  description: "Strip PII from outbound HTTP."
  enabled: true
  match:
    action: http_request
    destination: "*.external.com"
    contains_pii: true
  action: redact
  reason: "PII detected in egress payload"
  redact_fields:
    - body.card_number
    - body.ssn

Fields:

FieldRequiredMeaning
nameyesUnique identifier; shown in audit rows under decision.matched_rule.
enablednoDefault true. Disabled rules are skipped (kept for reference).
descriptionnoPlain English. Render in the Editor / audit details.
matchyesThe predicate. See match conditions below.
actionyesOne of allow / log / redact / require_approval / deny.
reasonnoFree-text shown to the admin and to the agent on deny.
redact_fieldsnoDotted paths into the request body for redact.

Match conditions

All conditions in a match block are AND-ed. A rule matches only when every listed condition matches.

ConditionTypeExample
agentstring or listagent: research_bot  or  agent: [a, b, c]
actionone of tool_call / http_request / llm_promptaction: http_request
destinationglob (host / tool / model)destination: "*.openai.com"
arg_regexmap of field → regexarg_regex: { cmd: "rm\\s+-rf" }
contains_piiboolcontains_pii: true
contains_secretboolcontains_secret: true

Globs in destination use shell-style * (one or more chars within a label) and ** (multiple labels). *.openai.com matches api.openai.com and chat.openai.com but not openai.com itself.

The five verdicts

VerdictEffect on the requestWhen to use
allowpasses through unchangednormal approved traffic
logpasses through, audit row writtenobservability without enforcement
redactrequest body rewritten with masks before egresssanitise PII / secrets / credentials
require_approvalrequest blocked, queued on the Approvals page; resumes when human clicks Allowexternal writes, expensive operations
denyrequest blocked, agent gets the reason stringunapproved providers, destructive commands

→ See Concepts: Decisions & verdicts for what each does internally.

A complete, sensible default policy

What we ship for new tenants:

yaml
- name: log_all_llm_calls
  description: "Observability — record every LLM prompt for audit."
  match: { action: llm_prompt }
  action: log

- name: redact_pii_on_egress
  description: "Card numbers, SSNs, emails — masked before they leave."
  match: { contains_pii: true }
  action: redact

- name: deny_secret_egress
  description: "API keys, tokens, AWS creds — never leave."
  match: { contains_secret: true }
  action: deny
  reason: "secret detected in payload"

- name: deny_shell_destructive
  description: "Tool calls to shell.exec with destructive shell patterns."
  match:
    action: tool_call
    destination: shell.exec
    arg_regex: { cmd: "rm\\s+-rf|dd\\s+if=|mkfs" }
  action: deny

- name: approve_external_writes
  description: "POST/PUT/DELETE to anywhere external — human review."
  match:
    action: http_request
    arg_regex: { method: "POST|PUT|DELETE" }
  action: require_approval

- name: deny_unknown_host
  description: "Default-deny for anything not allowlisted above."
  match: { action: http_request }
  action: deny
  reason: "host not in allowlist"

Order matters. The deny_unknown_host at the bottom catches everything an earlier rule didn't approve.

Editing in the UI

The Editor page (/app/editor) gives you a form view alongside the YAML view:

Screenshot: Editor — form + YAML side by sidedocs/public/screenshots/editor.png
  • Form is the right surface for most edits. It enforces shape and shows plain-English summaries of complex conditions.
  • YAML is the right surface for hand-crafted regex, copy-paste into a PR review, or reading what's actually about to be saved.
  • The Save button is disabled until the draft differs from the saved rule.
  • Simulate → sends the draft to /api/simulate with the last decision the engine evaluated — you see the verdict your draft would have produced without deploying it.

Reordering & disabling

  • Drag a rule on Policy Rules to change priority; the engine re-reads the new order immediately.
  • Toggle Enabled on any rule to switch it off without deleting. Useful for incident response — disable a rule that's misfiring, fix it, re-enable.

Audit trail

Every rule edit goes through PUT /v1/policy/rules/{name} (or POST for new, DELETE for remove). Every edit writes an audit row visible on Audit Log with who / what / when. Old YAML is preserved (git-style history) — restore a previous version with one click.

→ Once you've written a rule, Simulate it against last 24h of traffic before activating.

Documentation for kilasec — the AI Agent Firewall.