Custom PII filters
The built-in detectors cover four shapes: email, card-like number, US SSN, and phone. Everything specific to your organisation — employee IDs, customer account numbers, internal ticket references, case numbers — needs a pattern you write.
A pii_redact rule with a --pattern uses your regex instead of the
built-ins.
vulnetix ai-firewall policy guardrail redact-employee-ids \
--rule-type pii_redact \
--action redact \
--pattern '\bEMP-[0-9]{6}\b' \
--priority 25 \
--enable
# Rule 1 — the built-ins (no --pattern)
vulnetix ai-firewall policy guardrail redact-pii \
--rule-type pii_redact --action redact --priority 20 --enable
# Rule 2 — your own identifiers
vulnetix ai-firewall policy guardrail redact-employee-ids \
--rule-type pii_redact --action redact \
--pattern '\bEMP-[0-9]{6}\b' --priority 25 --enable
Both run. Both redact to [REDACTED].
Patterns worth writing
Adapt the shapes; the point is the anchoring.
Internal identifiers
\bEMP-[0-9]{6}\b
An employee ID. Note the \b word boundaries — without them this matches inside
longer strings and will fire on things you did not intend.
\bACCT-[0-9]{4}-[0-9]{4}-[0-9]{4}\b
A customer account number.
\b(INC|CHG|PRB)[0-9]{7}\b
ServiceNow-style ticket references. Whether this is sensitive depends on your
organisation — often it is a flag, not a redact, because leaking the existence
of an incident number is different from leaking its contents.
National identifiers other than US SSN
The built-in SSN detector is US-only. If you operate elsewhere you need your own:
\b[0-9]{3}-[0-9]{3}-[0-9]{3}\b
Canadian SIN, hyphenated form.
\b[A-CEGHJ-PR-TW-Z]{2}[0-9]{6}[A-D]\b
UK National Insurance number.
\b[0-9]{9}\b will match
an enormous amount of ordinary text — port numbers, timestamps, row counts — and
your developers will notice. Anchor on a prefix, a separator, or a checksum-bearing
shape wherever you can.Internal URLs and hostnames
https?://[\w.\-]+\.(internal|corp)(/[^\s]*)?
Usually a flag — you want to know it is happening — or a redact if the URL
itself reveals customer identifiers in its path.
Match what you mean
Two habits that prevent most false positives:
Anchor on structure, not on length. \bEMP-[0-9]{6}\b is safe.
[0-9]{6} is not — it matches inside a phone number, a timestamp, and a git SHA
that happens to be numeric.
Use word boundaries. \b on both ends of an identifier stops it matching
inside a longer token. Without it, ACCT-1234 matches inside MY-ACCT-12345678,
and the redaction cuts the string in half.
Regex constraints
Patterns are RE2:
- No lookahead or lookbehind. You cannot write
(?<!prefix). - No backreferences. You cannot write
(\w+)-\1. - Everything else you are used to — character classes, quantifiers, alternation,
anchors, named groups,
(?i)— works.
This is not an oversight. RE2 guarantees linear-time matching, which means no pattern you write, and no input an attacker sends, can make the firewall hang. A regex engine that can be made to hang on a crafted input is a denial-of-service vector sitting in the request path of every LLM call your organisation makes.
An uncompilable pattern is silently skipped — the rule looks enabled and enforces nothing. Always run:
vulnetix ai-firewall status
after a rule change. It compiles every pattern locally and reports
guardrail_pattern_invalid with a hint. See the
regex reference.
Testing a pattern
The engine uses Go’s RE2. The most reliable way to test a pattern before you deploy it is a Go regex playground, or:
# Adopt it at flag first, then look at what it actually caught
vulnetix ai-firewall policy guardrail redact-employee-ids \
--rule-type pii_redact --action flag \
--pattern '\bEMP-[0-9]{6}\b' --priority 25 --enable
flag records the match and forwards the request untouched, so you get the signal
with no risk of rewriting traffic you did not mean to. See rollout.
Related
- Redact PII — the built-in detectors and the silent-redaction caveat.
- Regex reference — the full RE2 subset.
- Tuning false positives — when a pattern is too eager.