harden(mail): validate match patterns + escape prefix interpolation for regex safety#322
Conversation
…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>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tps-sherlock
left a comment
There was a problem hiding this comment.
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
left a comment
There was a problem hiding this comment.
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
left a comment
There was a problem hiding this comment.
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.
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.yamlmanifests (routing[].pattern,capabilities.mail_handler.match.bodyPattern) are evaluated against inbound mail bodies at two runtime sites (mail-handlerrouting loop andmatchesFilter). PreviouslyRegexStringSchemaonly confirmed a pattern compiles — which does not confirm it is safe to evaluate. It now also runssafe-regex, so a well-formed-but-unsafe pattern fails schema validation and the manifest is dropped before the pattern can reachnew RegExp().test(). The comments that implied "validated" meant "safe" were corrected to reflect this.Prefix interpolation (
task-result-mail)formatTaskCompleteMailBodyinterpolated itsprefixargument 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.prefixis 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/clipackage — small, pure-JS, bundles cleanly with the existing binary build.Tests
bun testsuite run; the only failures are pre-existing and environment-dependent (ssh reachability, external CLI tooling), unrelated to this change.