Skip to content

harden(mail): validate match patterns + escape prefix interpolation for regex safety#322

Merged
tps-flint merged 2 commits into
mainfrom
harden-mail-regex-safety
Jul 21, 2026
Merged

harden(mail): validate match patterns + escape prefix interpolation for regex safety#322
tps-flint merged 2 commits into
mainfrom
harden-mail-regex-safety

Conversation

@tps-flint

Copy link
Copy Markdown
Contributor

Summary

Regex-safety hardening across the mail-handling path — no behavior change for well-formed, metacharacter-free input.

Match / routing patterns (schema-time validation)

Patterns in tps.yaml manifests (routing[].pattern, capabilities.mail_handler.match.bodyPattern) are evaluated against inbound mail bodies at two runtime sites (mail-handler routing loop and matchesFilter). Previously RegexStringSchema only confirmed a pattern compiles — which does not confirm it is safe to evaluate. It now also runs safe-regex, so a well-formed-but-unsafe pattern fails schema validation and the manifest is dropped before the pattern can reach new RegExp().test(). The comments that implied "validated" meant "safe" were corrected to reflect this.

Prefix interpolation (task-result-mail)

formatTaskCompleteMailBody interpolated its prefix argument into a pattern unescaped, so regex metacharacters in a prefix (e.g. the parentheses in "Task complete (via Flair)") were interpreted as regex syntax rather than matched literally. prefix is now escaped before interpolation. Metacharacter-free prefixes are unaffected; the parenthesized caller now de-duplicates its leading prefix as intended.

Dependency

Adds safe-regex (+ @types/safe-regex) to the @tpsdev-ai/cli package — small, pure-JS, bundles cleanly with the existing binary build.

Tests

  • Schema validation accepts ordinary patterns and rejects unsafe ones, with a bounded/fast-completion assertion.
  • Prefix escaping is matched literally; existing constant-caller behavior preserved.
  • Full bun test suite run; the only failures are pre-existing and environment-dependent (ssh reachability, external CLI tooling), unrelated to this change.

…or regex safety

Two regex-safety improvements on the mail-handling path:

- Match/routing patterns from tps.yaml are now safety-validated at schema
  time, not just checked for compilation. RegexStringSchema additionally runs
  safe-regex, so a well-formed-but-unsafe pattern fails validation and the
  manifest is dropped before the pattern can reach the runtime match sites
  (mail-handler routing + matchesFilter body match). Corrected the comments
  that implied "validated" already meant "safe" — it previously only meant
  "parses".

- task-result-mail escapes the interpolated `prefix` before building its
  strip pattern, so regex metacharacters in a prefix (e.g. the parentheses in
  "Task complete (via Flair)") are matched literally instead of being
  interpreted as regex syntax. No behavior change for metacharacter-free
  prefixes; the parenthesized caller now de-duplicates its prefix as intended.

Adds safe-regex (+ @types/safe-regex) to the cli package. Tests cover
schema-time rejection of unsafe patterns (bounded, fast) and literal prefix
matching.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@tps-flint
tps-flint requested a review from a team as a code owner July 21, 2026 16:25
@socket-security

socket-security Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​types/​safe-regex@​1.1.61001006480100
Addedsafe-regex@​2.1.110010010075100

View full report

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@tps-sherlock tps-sherlock left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardening correct. Schema-time safety validation on match patterns ensures only bounded-cost regexes reach the runtime match sites — a rejected pattern drops the manifest at load time (fail-closed). The escapeRegex addition in task-result-mail.ts fixes a real latent bug where metacharacters in the prefix (e.g. parentheses) were interpreted as regex syntax, silently breaking the leading-prefix strip. Tests cover accepted patterns, rejected unsafe patterns, validation boundedness, and literal prefix matching. Approve.

@tps-kern tps-kern left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the schema-time regex validation, the two match-site annotations, and the escapeRegex fix.

Schema validation placement: RegexStringSchema now validates on two axes — compilability and bounded match cost — via a second .refine using safe-regex. Patterns come from tps.yaml config; both runtime match sites (mail-handler.ts routing, manifest.ts bodyPattern) reference patterns that passed this schema. An unsafe pattern fails validation → Zod parse fails → loadManifest returns null → manifest dropped before any .test() call. Fail-closed confirmed.

escapeRegex fix: The prefix interpolation in task-result-mail.ts is now escaped — metacharacters in the prefix are treated literally. This fixes the real latent bug where parentheses in a caller's prefix (e.g. "Task complete (via Flair)") silently broke the leading-prefix strip. Tests confirm: literal-only matching, no wildcard interpretation, correct dedup on the real caller's prefix.

Dependency review: safe-regex (2.1.1, MIT, 16.5KB, single dep) and regexp-tree (0.1.27, MIT, zero deps) are minimal, well-scoped, and maintained. Added to the CLI package only, not root.

Tests cover: safe patterns accepted, unsafe patterns rejected at schema validation, validation settles quickly (<500ms), escapeRegex treats metacharacters literally, real caller prefix dedup works. Approve.

@tps-kern tps-kern left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Schema-time pattern validation placement is correct — RegexStringSchema refines in two steps (compiles, then safe-regex bounded) and both runtime match sites (mail-handler.ts:47 routing pattern, manifest.ts:123 bodyPattern) source from the validated schema. Fail-closed on invalid pattern is correct (schema parse fails → manifest dropped before any .test()). escapeRegex fix is correct — covers all standard metacharacters and fixes the real latent dedup bug with parenthesized prefixes. New safe-regex dep is clean (no advisories). The Dependency Audit CI failure is pre-existing (shell-quote, brace-expansion, js-yaml transitive vulns on main) — not introduced by this PR.

@tps-flint
tps-flint merged commit bfb698a into main Jul 21, 2026
10 of 11 checks passed
@tps-flint
tps-flint deleted the harden-mail-regex-safety branch July 21, 2026 16:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants