Documents
policy-spec-v0.1
policy-spec-v0.1
Type
External
Status
Published
Created
Mar 25, 2026
Updated
Mar 25, 2026

Agent Firewall Policy Specification v0.1#

Status: Draft
Version: 0.1.0
Authors: Pipelock maintainers

This specification defines a minimal, portable policy format for agent firewalls. The goal is to standardize how egress rules, DLP actions, audit events, and MCP scan hooks are expressed, so policies can be shared across tools and organizations.

Pipelock implements this spec natively. Other agent firewall implementations can adopt it to enable policy portability.

Design Principles#

  1. Minimal. Only fields that affect security decisions. No UI preferences, no deployment config, no vendor-specific extensions in the core spec.
  2. Declarative. Policies describe what to allow/deny, not how to implement it. Enforcement is up to the runtime.
  3. Composable. Multiple policies can be merged. Later rules override earlier ones by name.
  4. Auditable. Every policy decision should produce a structured log entry that references the rule that triggered it.

Policy Document#

A policy document is a YAML file with these top-level keys:

policy_version: "0.1.0"
name: "production-agents"
description: "Policy for production AI agent fleet"

egress: { ... }
dlp: { ... }
response: { ... }
mcp: { ... }
audit: { ... }

All sections are optional. Missing sections mean "no opinion" (defer to runtime defaults).

Egress Rules#

Control which domains and IP ranges the agent can reach.

egress:
  default: deny # deny or allow
  rules:
    - name: "LLM providers"
      domains:
        - "*.anthropic.com"
        - "*.openai.com"
        - "api.together.xyz"
      action: allow

    - name: "Known exfiltration targets"
      domains:
        - "*.pastebin.com"
        - "*.transfer.sh"
        - "file.io"
        - "requestbin.net"
      action: deny

    - name: "Internal networks"
      cidrs:
        - "10.0.0.0/8"
        - "172.16.0.0/12"
        - "192.168.0.0/16"
        - "169.254.0.0/16"
      action: deny

Egress Rule Fields#

FieldTypeRequiredDescription
namestringyesHuman-readable rule identifier
domainsstring[]noDomain patterns (supports * wildcard prefix)
cidrsstring[]noCIDR ranges (IPv4 and IPv6)
actionstringyesallow or deny

Rules are evaluated top-to-bottom. First match wins. If no rule matches, default applies.

Domain matching is case-insensitive. *.example.com matches api.example.com but not example.com itself. Use both example.com and *.example.com to cover both.

DLP Rules#

Define patterns for detecting secrets and sensitive data in URLs, request bodies, and tool arguments.

dlp:
  scan_environment: true # Check env vars for leaked values
  min_env_length: 16 # Min env var value length to flag
  patterns:
    - name: "Anthropic API Key"
      regex: 'sk-ant-[a-zA-Z0-9\-_]{10,}'
      severity: critical
      action: block

    - name: "AWS Access Key"
      regex: '(AKIA|ASIA)[A-Z0-9]{16,}'
      severity: critical
      action: block

    - name: "Credential in URL"
      regex: '(password|token|secret|api_?key)=[^\s&]{8,}'
      severity: high
      action: warn

DLP Pattern Fields#

FieldTypeRequiredDescription
namestringyesPattern identifier (used in audit events)
regexstringyesCase-insensitive regex
severitystringyescritical, high, medium, low
actionstringnoblock or warn (overrides global DLP action)

Regexes are always applied case-insensitive. Implementations should support at minimum: PCRE-compatible syntax, character classes, alternation, and quantifiers.

Encoding Handling#

Implementations MUST attempt to decode content before pattern matching:

  • Base64 (standard and URL-safe, with and without padding)
  • Hex encoding
  • URL encoding (iterative, handling multi-layer encoding)

This is not optional. Without encoding-aware matching, DLP is trivially bypassed.

Response Scanning#

Detect prompt injection in fetched content and MCP tool results.

response:
  action: warn # block, strip, warn, or ask
  patterns:
    - name: "Prompt Injection"
      regex: '(?i)(ignore|disregard)\s+(all\s+)?(previous|prior)\s+(instructions|prompts)'

    - name: "System Override"
      regex: '(?i)(you\s+are|act\s+as)\s+(now\s+)?(a|an|my)\s+'

    - name: "Jailbreak Attempt"
      regex: '(?i)(DAN|developer)\s+mode'

Response Actions#

ActionBehavior
blockReject the response entirely
stripRemove matched text, return the rest
warnLog the finding, return content unchanged
askPause for human approval (requires interactive terminal)

Normalization Requirements#

Implementations SHOULD apply these normalizations before pattern matching (in order):

  1. Strip zero-width and invisible Unicode characters
  2. Apply NFKC Unicode normalization
  3. Map confusable characters to ASCII equivalents
  4. Strip combining marks

Without normalization, injection detection is trivially bypassed with Unicode tricks.

MCP Hooks#

Rules for MCP tool call scanning, tool description validation, and chain detection.

mcp:
  input_scanning:
    enabled: true
    action: warn
    on_parse_error: block # What to do with malformed JSON-RPC

  tool_scanning:
    enabled: true
    action: warn
    detect_drift: true # Alert on tool description changes

  tool_policy:
    action: warn
    rules:
      - name: "Block shell execution"
        tool_pattern: "execute_command|run_terminal|bash"
        action: block

      - name: "Warn on file writes"
        tool_pattern: "write_file|create_file"
        arg_pattern: '/etc/.*|/usr/.*|~/.ssh/.*'
        action: warn

  session_binding:
    enabled: true
    unknown_tool_action: warn

  chain_detection:
    enabled: true
    action: warn
    window_size: 20
    window_seconds: 300
    max_gap: 3

Tool Policy Rule Fields#

FieldTypeRequiredDescription
namestringyesRule identifier
tool_patternstringyesRegex matching tool name
arg_patternstringnoRegex matching argument values
arg_keystringnoRegex scoping arg_pattern to top-level argument keys. Requires arg_pattern; specifying arg_key without arg_pattern is a validation error.
actionstringnoblock or warn

Audit Event Format#

Every policy decision produces a structured audit event. This is the canonical format:

{
  "timestamp": "2026-02-28T15:04:05.000Z",
  "level": "warn",
  "event": "blocked",
  "scanner": "dlp",
  "rule": "Anthropic API Key",
  "severity": "critical",
  "method": "GET",
  "url": "https://example.com/?key=sk-ant-...",
  "agent": "my-bot",
  "client_ip": "127.0.0.1",
  "request_id": "abc123",
  "mitre_technique": "T1048",
  "instance_id": "prod-agent-1"
}

Required Audit Fields#

FieldTypeDescription
timestampISO 8601When the event occurred
levelstringinfo, warn, or critical
eventstringEvent type: allowed, blocked, anomaly, etc.
scannerstringWhich scanner triggered the event
rulestringPattern/rule name that matched

Optional Audit Fields#

FieldTypeDescription
severitystringFinding severity (from DLP/response pattern)
methodstringHTTP method
urlstringTarget URL (may be truncated)
agentstringAgent identifier
client_ipstringSource IP (HTTP transports only, omitted for stdio MCP)
request_idstringUnique request identifier (HTTP transports only, omitted for stdio MCP)
mitre_techniquestringMITRE ATT&CK technique ID
instance_idstringPipelock instance identifier
scorenumberThreat score (if adaptive enforcement is enabled)

MITRE ATT&CK Mapping#

Implementations SHOULD include MITRE technique IDs in audit events where applicable:

DetectionTechnique IDName
DLP / secret exfiltrationT1048Exfiltration Over Alternative Protocol
SSRF / private IP accessT1046Network Service Discovery
Prompt injectionT1059Command and Scripting Interpreter
Tool poisoningT1195.002Supply Chain: Software Supply Chain
Session anomalyT1078Valid Accounts
Domain blocklist violationT1071.001Application Layer Protocol: Web
Rate limit / data budgetT1030Data Transfer Size Limits

Policy Merging#

When multiple policies are combined (org-wide + team + project), merge rules:

  1. Later policies override earlier ones by section
  2. Within egress.rules, dlp.patterns, etc., rules merge by name
  3. If two rules share a name, the later one wins entirely (no field-level merge)
  4. egress.default is overridden by the last policy that sets it

This allows organizations to set a baseline policy and teams to customize it.

Validation#

Implementations MUST validate policies at load time:

  • All regex patterns compile without error
  • All action values are recognized
  • All severity values are recognized
  • Strict mode (egress.default: deny) has at least one allow rule
  • CIDR values parse correctly

Invalid policies MUST be rejected entirely (fail-closed). Partial application of a broken policy is a security risk.

Versioning#

The policy_version field uses semver. Implementations MUST reject policies with a major version they don't support. Minor version bumps add optional fields. Patch version bumps are documentation-only.

Example: Minimal Production Policy#

policy_version: "0.1.0"
name: "minimal-production"

egress:
  default: deny
  rules:
    - name: "LLM APIs"
      domains: ["*.anthropic.com", "*.openai.com"]
      action: allow
    - name: "Package registries"
      domains: ["registry.npmjs.org", "pypi.org", "pkg.go.dev"]
      action: allow

dlp:
  scan_environment: true
  patterns:
    - name: "API Keys"
      regex: 'sk-[a-zA-Z0-9\-_]{20,}'
      severity: critical

response:
  action: block

mcp:
  input_scanning:
    enabled: true
    action: block
  tool_policy:
    action: warn
    rules:
      - name: "No shell"
        tool_pattern: "execute_command|bash|shell"
        action: block

audit: {}

Relationship to Pipelock Config#

Pipelock's YAML config (pipelock.yaml) is a superset of this spec. It includes deployment fields (listen, timeout_seconds, etc.) alongside policy fields. The policy fields map directly:

Policy SpecPipelock Config
egress.defaultmode: strict + api_allowlist
egress.rules[].domainsapi_allowlist + monitoring.blocklist
dlp.patternsdlp.patterns
response.actionresponse_scanning.action
mcp.*mcp_input_scanning, mcp_tool_scanning, etc.
auditlogging + emit

See Configuration Reference for the full pipelock config documentation.