Policies

Regex cookbook

Battle-tested regex patterns for DefenseClaw guardrails — secrets, command injection, exfiltration markers, prompt injection — with explanations and counterexamples.

DefenseClaw compiles every guardrail pattern with Go's standard regexp package, which is RE2-based. The wizard's regex tester catches incompatible features before you commit; this page is the deeper reference for the patterns that ship in the strict pack.

RE2 in 30 seconds

RE2 trades a few features for predictable, polynomial-time matching. Patterns you know from PCRE that do not work in RE2:

  • Lookarounds: (?=…), (?!…), (?<=…), (?<!…)
  • Backreferences: \1, \2, \k<name>
  • Atomic groups: (?>…)
  • Possessive quantifiers: *+, ++, ?+

If your pattern needs any of those, the wizard turns the input field red and tells you which feature failed. Re-author with a non-capturing group and tighter quantifiers.

Anatomy of a good rule

- id: SEC-OPENAI-V2
  title: OpenAI API key (current format)
  pattern: 'sk-[A-Za-z0-9]{48}'
  severity: CRITICAL
  confidence: 0.95
  tags: [secret, openai]

What makes this work:

  • Anchored prefix. sk- is the OpenAI marker. Without it the pattern would match every ~48-character base62 string.
  • Bounded quantifier. {48} instead of {20,} keeps the false positive rate low.
  • Conservative confidence. Even at 0.95, the LLM judge can downgrade in context.
  • Self-describing tags. Useful when you triage thousands of findings in dashboards.

Patterns by category

Secrets

IDPattern shapeCatchesAvoids
SEC-AWS-KEY\b(AKIA|ASIA)[A-Z0-9]{16}\bIAM, STS keysRandom base62 of similar length
SEC-GITHUB-TOKEN\bgh[posr]_[A-Za-z0-9]{36,}New GitHub token formatsPlain gh- strings
SEC-PRIVKEY-----BEGIN [A-Z ]+PRIVATE KEY-----RSA, ED25519, OPENSSHPublic certs, certificate signing requests
SEC-OPENAI-V2sk-[A-Za-z0-9]{48}OpenAI keyssk-test- Stripe keys
SEC-SLACK-WEBHOOKhttps://hooks\.slack\.com/services/[A-Z0-9]+/[A-Z0-9]+/[A-Za-z0-9]+Slack incoming webhooksOther Slack URLs (channels, files)

Prompt / tool injection

These rely on the natural-language signal more than character classes. Always pair with an LLM judge for confirmation — the regex is the cheap pre-filter.

- id: INJ-OVERRIDE-INSTRUCTION
  pattern: '(?i)\b(ignore|disregard)\s+(all\s+)?(previous|prior|above)\s+(instructions|prompts|rules)\b'
  severity: HIGH
- id: INJ-SHELL-EXEC
  pattern: '(?i)\b(rm\s+-rf|dd\s+if=|mkfs|truncate\s+-s|format\s+c:)\b'
  severity: CRITICAL

Unicode obfuscation (ZWSP / RTL / homoglyph)

Attackers slip zero-width characters and bidi controls inside otherwise-benign strings to defeat keyword matchers (i​gnore previous reads identically to the eye but i\u200Bgnore slips past (?i)ignore). Two layers cover this:

- id: OBFUSC-UNICODE-ZWSP
  title: Zero-width whitespace inside text
  pattern: '[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{206F}\x{FEFF}]'
  severity: MEDIUM
  signal_strength: high
  tags: [obfuscation, unicode]
- id: OBFUSC-CYRILLIC-LATIN-MIX
  title: Cyrillic letter inside an otherwise-ASCII word
  pattern: '\b[a-zA-Z]*[\x{0430}-\x{044F}][a-zA-Z]+\b'
  severity: MEDIUM
  signal_strength: medium
  tags: [obfuscation, homoglyph]

Why MEDIUM and not HIGH

A single ZWSP isn't proof of malice — copy-pasting from Word or PDF leaks them all the time. But the same finding inside the same session as a sensitive-access or injection finding is what the Layer-5 correlator promotes to CRITICAL via the signal_strength: high axis. Keep the base severity at MEDIUM so you don't drown in false positives, and let the correlator do the work. See Layer 5 — Session correlator.

Exfiltration markers

When a model surfaces a base64 blob, an out-of-band webhook URL, or a tar pipe, you usually want to alert before allowing the output downstream:

- id: EXFIL-CURL-PIPE-SH
  pattern: '\bcurl\s+[^\s]+\s*\|\s*(bash|sh|zsh)\b'
  severity: CRITICAL
- id: EXFIL-WEBHOOK-DOMAIN
  pattern: '(?i)\b(webhook\.site|requestbin\.com|ngrok\.io|interactsh\.com)\b'
  severity: HIGH

Enterprise data shape

Numeric-only patterns are the easiest to false-positive. Always pair them with a condition in your finding suppressions (see the suppression cookbook).

- id: PII-SSN
  pattern: '\b\d{3}-\d{2}-\d{4}\b'
  severity: HIGH
- id: PII-CREDIT-CARD
  pattern: '\b(?:4\d{3}|5[1-5]\d{2}|3[47]\d{2}|6(?:011|5\d{2}))[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b'
  severity: CRITICAL

Patterns to avoid

  • .* anywhere unanchored. It almost always matches, slowly. Pair with at least one bounded segment ([A-Z0-9]{8,}) and an anchor.
  • Greedy quantifiers under groups under quantifiers. (\w+)+ is the classic catastrophic backtracking shape. The wizard's REGEX_REDOS heuristic flags this on the way in.
  • Case-insensitive without (?i). Use the inline flag so the engine and your tester agree.

Workflow

In the Policy creator Rule pack section:

  1. Pick a recipe from the catalog or click "+ Rule" on the appropriate file.
  2. Paste your pattern in. The wizard runs every keystroke through V8, the RE2 lint, and the ReDoS heuristic, plus your should match and should NOT match examples.
  3. Once the pill colors line up (green for pass, amber for mismatch, red for compile error), review the verdict in the Live Test pane on the right — it'll show how the pattern interacts with the severity matrix and admission policy.