Policy Syntax
AxonFlow policies are defined as JSON objects and managed through the Static Policy API (/api/v1/static-policies). This page documents the policy field structure and validation rules.
Policy Structure
All AxonFlow static policies use this JSON format:
{
"name": "Block UNION SQL Injection",
"description": "Detect UNION-based SQL injection in prompts",
"category": "security",
"pattern": "(?i)union\\s+select",
"action": "block",
"severity": "critical",
"enabled": true,
"message": "Potential SQL injection detected."
}
Policy Fields Reference
| Field | Type | Required | Description | Validation |
|---|---|---|---|---|
name | string | Yes | Human-readable policy name | 1-255 characters, must be unique within a tier |
description | string | No | Explanation of what the policy detects | Max 1000 characters |
category | string | Yes | Policy category (see categories below) | Must be a valid category |
pattern | string | Yes | Regex pattern to match against input | Must be a valid Go-compatible regex |
action | string | Yes | Action taken when pattern matches | block, warn, or log |
severity | string | Yes | Severity level of the policy | critical, high, medium, or low |
enabled | boolean | No | Whether the policy is active | Defaults to true |
message | string | No | Message returned when policy triggers | Max 500 characters |
Read-Only Fields (returned in responses)
| Field | Type | Description |
|---|---|---|
id | string | Auto-generated unique identifier |
tier | string | Policy tier: system, organization, or tenant |
has_override | boolean | Whether an Enterprise override exists |
created_at | string | ISO 8601 creation timestamp |
updated_at | string | ISO 8601 last update timestamp |
Categories
The category field determines how the policy is classified. Use the category that best describes your policy's purpose:
| Category | Description | Example Use Case |
|---|---|---|
security | Security threat detection | SQL injection, command injection |
compliance | Regulatory compliance rules | GDPR, HIPAA, EU AI Act |
sensitive-data | PII and sensitive data detection | SSN, credit cards, PAN |
custom | Business-specific rules | Internal IP detection, competitor mentions |
System policies use more specific sub-categories like security-sqli, security-admin, pii-global, pii-us, pii-eu, and pii-india. Custom tenant policies can use any of the four top-level categories above.
Actions
The action field determines what happens when a policy pattern matches:
| Action | Description | Effect on Request |
|---|---|---|
block | Immediately reject the request | Request returns an error with the policy message |
warn | Allow request but log a warning | Request proceeds; warning appears in policy evaluations |
log | Allow request and record a log entry | Request proceeds; match recorded for audit |
Action Hierarchy
Actions have a restrictiveness hierarchy: block > warn > log
When overriding system policies (Enterprise only), you can only make policies more restrictive or disable them. You cannot downgrade a block policy to warn or log.
Severities
The severity field indicates the importance of a policy match:
| Severity | Description | Typical Use |
|---|---|---|
critical | Highest severity, immediate attention required | SQL injection, credit card exposure, SSN detection |
high | Important security or compliance issue | Admin access patterns, sensitive table access |
medium | Moderate concern, should be reviewed | Email detection, IP address exposure |
low | Informational, for audit purposes | Booking references, general logging |
Pattern Syntax
The pattern field accepts Go-compatible regular expressions (RE2 syntax). Patterns are evaluated against query input text.
Pattern Examples
| Pattern | Description | Matches |
|---|---|---|
(?i)union\s+select | Case-insensitive UNION SELECT | UNION SELECT, union select |
\b\d{3}-\d{2}-\d{4}\b | SSN with dashes | 123-45-6789 |
\b[A-Z]{3}[PCHABGJLFT][A-Z]\d{4}[A-Z]\b | Indian PAN | ABCPD1234E |
(?i)\b(drop|truncate)\s+table\b | Destructive SQL | DROP TABLE, truncate table |
Pattern Tips
- Use
(?i)at the start for case-insensitive matching - Use
\bfor word boundaries to reduce false positives - Use non-capturing groups
(?:...)when you don't need capture groups - Avoid catastrophic backtracking (nested quantifiers like
(a+)+) - Test patterns with the SDK's
testPattern()method before deploying
Evaluation Order
Policies are evaluated in tier order, with system policies evaluated first:
- System policies (Agent, pattern-based) -- evaluated first, sub-5ms
- Organization policies (Enterprise only) -- merged next
- Tenant policies -- evaluated last
Within each tier, policies are evaluated by priority. The first matching block policy stops evaluation and rejects the request. warn and log policies are always evaluated and recorded.
Request → Agent evaluates system policies (pattern-based)
↓ (if not blocked)
→ Orchestrator evaluates tenant policies (condition-based)
↓ (if not blocked)
→ Request forwarded to LLM
Creating Policies
REST API
curl -X POST http://localhost:8080/api/v1/static-policies \
-H "Content-Type: application/json" \
-H "X-Org-ID: my-tenant" \
-d '{
"name": "Block Internal IPs",
"description": "Prevent exposure of internal IP addresses",
"category": "security",
"pattern": "\\b10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b",
"action": "block",
"severity": "medium",
"enabled": true,
"message": "Internal IP address detected."
}'
Successful Response (201):
{
"id": "pol_abc123",
"name": "Block Internal IPs",
"description": "Prevent exposure of internal IP addresses",
"tier": "tenant",
"category": "security",
"pattern": "\\b10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b",
"action": "block",
"severity": "medium",
"enabled": true,
"message": "Internal IP address detected.",
"created_at": "2026-02-07T12:00:00Z",
"updated_at": "2026-02-07T12:00:00Z"
}
Validation Error Response (400):
{
"error": "validation_error",
"details": [
"pattern: invalid regex syntax",
"action: must be one of block, warn, log"
]
}
SDK
const policy = await client.createStaticPolicy({
name: 'Block Internal IPs',
description: 'Prevent exposure of internal IP addresses',
category: 'security',
pattern: '\\b10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b',
action: 'block',
severity: 'medium',
enabled: true,
});
Testing Patterns
Validate a regex pattern against test inputs before creating a policy:
curl -X POST http://localhost:8080/api/v1/static-policies/test-pattern \
-H "Content-Type: application/json" \
-H "X-Org-ID: my-tenant" \
-d '{
"pattern": "\\b10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b",
"inputs": [
"Server at 10.0.1.5 is down",
"No internal IPs here",
"Multiple: 10.1.2.3 and 10.4.5.6"
]
}'
{
"pattern": "\\b10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b",
"matches": [
{ "input": "Server at 10.0.1.5 is down", "matched": true, "matchedText": "10.0.1.5" },
{ "input": "No internal IPs here", "matched": false },
{ "input": "Multiple: 10.1.2.3 and 10.4.5.6", "matched": true, "matchedText": "10.1.2.3" }
]
}
Best Practices
- Use descriptive names --
Block UNION SQL InjectionnotPolicy 1 - Add descriptions -- Explain why the policy exists and what it protects against
- Test patterns first -- Use
testPattern()or the test-pattern API before creating policies - Start with warn/log -- Deploy new policies as
warnorlog, then promote toblockafter monitoring - Use word boundaries --
\bprevents partial matches (e.g.,\bDROP\bwon't matchDROPDOWN) - Use case-insensitive flag --
(?i)at the start of patterns for SQL keywords and other case-varying inputs - One pattern per policy -- Simpler policies are easier to test, monitor, and disable independently
- Review regularly -- Audit custom policies quarterly for relevance and false positive rates
Related
- Policy Examples - Ready-to-use policy templates
- Policy Testing - Test and validate policies
- SDK Methods - Full API reference for policy CRUD
- System Policies - Complete list of 63 system policies
