Skip to main content
Runlayer evaluates every administrator-supplied regular expression with Google RE2. RE2 matches in guaranteed linear time, so a pattern can never cause a ReDoS slowdown — but in exchange it accepts a slightly narrower syntax than Python’s re or PCRE. This page lists what is supported so your patterns compile on the first save.
This applies everywhere you can enter a regex as an administrator: policy condition operators (regex, not_regex, list_regex, list_not_regex, list_any_not_regex — see Policies) and custom PII rules (see Runlayer ToolGuard). A literal pattern RE2 cannot compile is rejected when you save, with the reason shown inline. A dynamic policy pattern (a reference like $payload.pattern, resolved per request) can only be checked at evaluation time: if the resolved value fails to compile, the condition evaluates as no-match — so a deny rule built on it does not block that request. Prefer literal patterns for enforcement.

Matching semantics

The two surfaces apply a pattern differently, and it changes how you anchor:
  • Policy conditions match the entire field value (RE2 fullmatch, case-sensitive). A prefix like ^https?:// never matches a full URL on its own — write the whole shape, e.g. https?://[^/]*\.example\.com(/.*)?. Leading ^ and trailing $ are redundant (but harmless) here.
  • Custom PII rules search within the scanned text (case-insensitive), so a pattern matches anywhere unless you anchor it; \b, ^, and $ behave as position assertions inside the text.

Supported

Not supported

RE2 rejects these; a pattern using them fails to save:

Differences from Python re

Even when a pattern compiles, a few behaviors differ from Python’s re. These matter most for non-ASCII input:
\d, \w, \s, and \b are ASCII-only in RE2, whereas Python’s re is Unicode-aware by default. \w+ matches cafe but not café, and \d+ matches 123 but not the Arabic-Indic digits ١٢٣. If a rule must catch Unicode letters or digits, use the property classes instead:
  • Unicode “word” character: [\p{L}\p{N}_] instead of \w
  • Unicode digit: \p{Nd} instead of \d
  • Unicode whitespace: [\t-\r \x1c-\x1f\x85\p{Z}] instead of \s\p{Z} alone covers only separator characters, so it would stop matching tabs, newlines, and other control whitespace that Python’s \s includes
  • $ matches end-of-text only — not the position just before a trailing newline (Python’s default $ does). Add (?m) if you want $ to match at the end of each line.
  • Custom PII rules always ignore case — case-insensitive matching is applied unconditionally, not opted into: a lowercase pattern like secret also masks SECRET and Secret. Case-insensitive matching uses Unicode simple case-folding, and Runlayer additionally folds the Python-specific dotted/dotless Turkish İ/ı to i in both the scanned text and the rule pattern, so obfuscation with those characters is still caught. Policy conditions are matched case-sensitively as written; a condition using an inline (?i) gets RE2’s own case-folding only, with no extra preprocessing.

Quick conversions

Converting a lookahead deny

A negative lookahead has no RE2 equivalent inside the pattern — the fix is to move the negation into the operator and keep the pattern positive. Example: a deny rule that fires when the recipient is outside the corporate domain (remember policy conditions match the entire field value): The deny now fires when the recipient does not end with @corp.example.com. For a list-valued field, use list_any_not_regex with the same pattern — it fires when at least one entry doesn’t match. See Policies for the full operator reference. For the complete grammar, see the official RE2 syntax reference.