Documentation

Guardrails

Content rules applied to every request the firewall proxies — block secrets, redact PII, cap runaway agent loops. Three rule types, three actions, evaluated in priority order.

A guardrail is a content rule applied to every request the firewall proxies, on every surface, from every client. A rule you write once covers a curl, a Codex turn, and a Claude Code tool result alike.

The model: three rule types × three actions

That is the whole system. It is small on purpose — everything below is built out of these nine combinations.

Rule typeWhat pattern means
blocked_patternAn RE2 regular expression, matched against the request’s text
pii_redactAn optional regex. Leave it empty to use the four built-in detectors (email, credit-card-like number, US SSN, phone number)
max_messagesAn integer — the maximum number of messages in a conversation
ActionWhat happens
flagThe request proceeds. The match is recorded. Nothing is blocked.
redactMatched spans are rewritten to the literal [REDACTED] and the request proceeds.
blockThe request is rejected with a 403, naming the rule that fired.
Tip Start every new rule at flag. You get the signal without the risk, you find out what it actually matches in your traffic, and only then do you decide whether it should redact or block. This ladder is the single most useful habit with this feature — see rollout.

How rules are evaluated

  • Only enabled rules run.
  • They run in ascending priority — lowest number first.
  • A block short-circuits: evaluation stops there and nothing after it runs.
  • redact mutates the request in place, and later rules see the already-redacted text.

Priority is therefore how you order a redaction before a block that would otherwise have fired on the same text.

When a request is blocked

HTTP 403, naming the rule, in the dialect of whatever client asked:

{
  "error": {
    "message": "request blocked by AI firewall policy: content matched pattern for policy \"no-connection-strings\"",
    "type": "policy_violation",
    "code": "request_blocked",
    "blocked_by": "no-connection-strings",
    "violations": [
      {
        "policy_name": "no-connection-strings",
        "rule_type": "blocked_pattern",
        "action": "block",
        "detail": "content matched pattern for policy \"no-connection-strings\""
      }
    ]
  }
}

The violations array names the rules that fired and why. It never contains the content that triggered them — not the matched substring, not the surrounding text. That holds even for flag, which records only that a rule matched.

What gets inspected

Everything you send: the system prompt, every message, multi-modal text parts, and — this is the one that matters for coding agents — tool results. When an agent reads a file, runs a command, or pastes a diff back into the conversation, that content is a tool result, and it goes through your guardrails.

Two things are not inspected, and you should know both:

  • Responses are never inspected. Guardrails run on the request. What the model says back is relayed untouched.
  • The arguments a model generates for a tool call are not scanned.

Both are covered honestly in limitations.

Writing rules

Every rule can be created three ways, and they are equivalent:

CLI
vulnetix ai-firewall policy guardrail no-connection-strings \
  --rule-type blocked_pattern \
  --action block \
  --pattern '(?i)postgres://\S+' \
  --priority 10 \
  --enable
Policy file
# .vulnetix/ai-firewall.yaml
apiVersion: vulnetix.com/v1
kind: AiFirewallPolicy
spec:
  guardrails:
    - name: no-connection-strings
      ruleType: blocked_pattern
      action: block
      pattern: '(?i)postgres://\S+'
      priority: 10
      enabled: true
vulnetix ai-firewall apply --dry-run   # review
vulnetix ai-firewall apply             # commit

See policy as code.

Dashboard
The Guardrails tab of the AI Firewall dashboard.

The pages

Fail-open or fail-closed

If the guardrail backend is unreachable, the gateway fails closed by default: the request is refused with a 503 rather than forwarded unscreened. This is the right default for a firewall and you should leave it alone.

Note that this switch applies only to guardrails. Authentication and provider/model policy are always fail-closed and cannot be configured otherwise — a backend outage can never turn into an unauthenticated request reaching a provider.

Block secrets
Stop credentials, keys, and connection strings leaving in a prompt. A blocked_pattern rule with a block action, and a pattern library to start from.
Redact PII
Rewrite personal data out of a prompt in flight and let the request through. The four built-in detectors, exactly what they match, and where they fall short.
Custom PII filters
The built-in detectors only know email, card, SSN, and phone. Your employee IDs, account numbers, and ticket references need a regex of your own.
Prompt injection
There is no machine-learning injection detector. There is a regex engine and a pattern library — which is a real defence with real limits, and this page is honest about both.
Conversation limits
max_messages caps how long a conversation can get. It exists because agents get stuck in loops, and a stuck agent is an invoice.
Regex reference
Patterns are RE2. No lookahead, no lookbehind, no backreferences — and that restriction is the reason the firewall cannot be hung by a crafted prompt.
Rolling out a rule
flag → redact → block. The ladder that lets you deploy a guardrail without breaking the people who depend on it.
Tuning false positives
There is no allowlist and no exception list. Here are the three mechanisms that actually exist, and how to use them.
Policy as code
Your whole firewall policy in one YAML file — reviewed in a pull request, applied from CI, with drift reported rather than silently overwritten.
Limitations
What guardrails do not catch. Read this before you rely on them, and before you tell an auditor what they do.