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.)

Looking for every field?

This page is the how-to. For an exhaustive, field-by-field reference of the rule editor — every tab, every option, and exactly how conditions combine when you fill in more than one — see Rule reference (every field).

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.

The default policy shipped to new tenants

New tenants start with default_action: allow and this rule set — visibility-first, so nothing legitimate breaks on day one while the risky patterns are caught:

yaml
- name: prod_db_needs_approval
  match: { destination: { host: production-db.internal }, action: [tool_call, sql_execute] }
  action: require_approval
  reason: writes to production-db require human approval

- name: redact_secrets_on_egress
  match: { contains_secret: true }
  action: redact
  reason: credential detected in outbound payload — masking before send

- name: redact_pii_on_egress
  match: { contains_pii: true }
  action: redact
  reason: PII detected in outbound payload — masking before send

- name: allow_approved_llms
  match: { destination: { model: [claude-sonnet-4-6, claude-opus-4-6, gpt-4o] }, action: llm_prompt }
  action: allow

- name: log_all_ai_chat
  match: { destination: { host: [chatgpt.com, claude.ai, gemini.google.com, perplexity.ai] } }
  action: log

Tune it to your posture: keep it visibility-first, or switch to default_action: deny and add explicit allow rules for a locked-down setup. The two redact_* rules mask secrets and PII at the wire out of the box; swap either to deny for a hard block.

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.