packages/engine/src/blueprint/validator.ts:98 does new RegExp(v.pattern).test(strVal) where pattern comes from admin-editable BlueprintField. A catastrophic-backtracking pattern (^(a+)+$) plus crafted input freezes the event loop. Relevant if MANAGE_BLUEPRINTS is ever delegated or if an admin-account is compromised.
Evidence
packages/engine/src/blueprint/validator.ts:98 — new RegExp(v.pattern).test(strVal)
Impact
DoS: single request to create/update resource with crafted value + malicious pattern → full process freeze for multiple seconds per request.
Proposed Fix
Replace RegExp with re2 (linear-time regex). Also reject unsafe patterns at blueprint save-time via safe-regex. Fallback: wrap test in setTimeout-cancel pattern with Worker.
## Problem
`packages/engine/src/blueprint/validator.ts:98` does `new RegExp(v.pattern).test(strVal)` where pattern comes from admin-editable BlueprintField. A catastrophic-backtracking pattern (`^(a+)+$`) plus crafted input freezes the event loop. Relevant if MANAGE_BLUEPRINTS is ever delegated or if an admin-account is compromised.
## Evidence
- `packages/engine/src/blueprint/validator.ts:98 — new RegExp(v.pattern).test(strVal)`
## Impact
DoS: single request to create/update resource with crafted value + malicious pattern → full process freeze for multiple seconds per request.
## Proposed Fix
Replace `RegExp` with `re2` (linear-time regex). Also reject unsafe patterns at blueprint save-time via `safe-regex`. Fallback: wrap test in `setTimeout`-cancel pattern with Worker.
## Acceptance Criteria
- [ ] re2 or safe-regex integrated
- [ ] Unit test: ReDoS pattern completes in < 50 ms
- [ ] Blueprint save rejects unsafe patterns
---
Parent Epic: #1
Source: Full-Codebase Security Audit 2026-04-16 (B-8)
Resolved in commit 019702c (security: ReDoS hardening on blueprint field validator).
Three-layer defence:
Save-time (packages/shared/src/schemas/blueprint.schema.ts:33-54) — FieldValidationSchema.pattern now has .max(200) and a .refine() that rejects grouped nested-quantifier shapes ((x+)+, (?:x*)+, (x{n,})* …). Admin UI will show a clear validation error at blueprint save time instead of silently storing the ReDoS pattern.
isSuspectRegexPattern() re-runs the same heuristic before invoking new RegExp(). If it fires, the field fails validation OUTRIGHT; the regex is never compiled or run.
Input strings are sliced to 4096 chars before .test() (belt-and-suspenders) so even a benign pattern against a 10 MB payload returns in < 50 ms.
new RegExp() compile failures are caught → validation error instead of 500.
Tests — packages/engine/src/__tests__/blueprint-validator-redos.test.ts (10 cases) pins all three behaviours:
^(a+)+$ + 30-'a' attack input → errors in < 50 ms
All canonical nested-quantifier shapes flagged
Safe patterns (^[a-z]+$, ^\d{3}-\d{4}$, email-style) pass through
Huge (12 kB) benign input still validates in < 50 ms
Resolved in commit 019702c (`security: ReDoS hardening on blueprint field validator`).
**Three-layer defence:**
1. **Save-time (`packages/shared/src/schemas/blueprint.schema.ts:33-54`)** — `FieldValidationSchema.pattern` now has `.max(200)` and a `.refine()` that rejects grouped nested-quantifier shapes (`(x+)+`, `(?:x*)+`, `(x{n,})*` …). Admin UI will show a clear validation error at blueprint save time instead of silently storing the ReDoS pattern.
2. **Runtime (`packages/engine/src/blueprint/validator.ts:26-33, 142-171`)** —
- `isSuspectRegexPattern()` re-runs the same heuristic before invoking `new RegExp()`. If it fires, the field fails validation OUTRIGHT; the regex is never compiled or run.
- Input strings are sliced to 4096 chars before `.test()` (belt-and-suspenders) so even a benign pattern against a 10 MB payload returns in < 50 ms.
- `new RegExp()` compile failures are caught → validation error instead of 500.
3. **Tests** — `packages/engine/src/__tests__/blueprint-validator-redos.test.ts` (10 cases) pins all three behaviours:
- `^(a+)+$` + 30-'a' attack input → errors in < 50 ms
- All canonical nested-quantifier shapes flagged
- Safe patterns (`^[a-z]+$`, `^\d{3}-\d{4}$`, email-style) pass through
- Huge (12 kB) benign input still validates in < 50 ms
Acceptance-criteria:
- [x] Safe-regex heuristic integrated (in-house, avoided re2 native-module install cost)
- [x] Unit test: ReDoS pattern completes in < 50 ms
- [x] Blueprint save rejects unsafe patterns
Closing.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
packages/engine/src/blueprint/validator.ts:98doesnew RegExp(v.pattern).test(strVal)where pattern comes from admin-editable BlueprintField. A catastrophic-backtracking pattern (^(a+)+$) plus crafted input freezes the event loop. Relevant if MANAGE_BLUEPRINTS is ever delegated or if an admin-account is compromised.Evidence
packages/engine/src/blueprint/validator.ts:98 — new RegExp(v.pattern).test(strVal)Impact
DoS: single request to create/update resource with crafted value + malicious pattern → full process freeze for multiple seconds per request.
Proposed Fix
Replace
RegExpwithre2(linear-time regex). Also reject unsafe patterns at blueprint save-time viasafe-regex. Fallback: wrap test insetTimeout-cancel pattern with Worker.Acceptance Criteria
Parent Epic: #1
Source: Full-Codebase Security Audit 2026-04-16 (B-8)
Resolved in commit
019702c(security: ReDoS hardening on blueprint field validator).Three-layer defence:
Save-time (
packages/shared/src/schemas/blueprint.schema.ts:33-54) —FieldValidationSchema.patternnow has.max(200)and a.refine()that rejects grouped nested-quantifier shapes ((x+)+,(?:x*)+,(x{n,})*…). Admin UI will show a clear validation error at blueprint save time instead of silently storing the ReDoS pattern.Runtime (
packages/engine/src/blueprint/validator.ts:26-33, 142-171) —isSuspectRegexPattern()re-runs the same heuristic before invokingnew RegExp(). If it fires, the field fails validation OUTRIGHT; the regex is never compiled or run..test()(belt-and-suspenders) so even a benign pattern against a 10 MB payload returns in < 50 ms.new RegExp()compile failures are caught → validation error instead of 500.Tests —
packages/engine/src/__tests__/blueprint-validator-redos.test.ts(10 cases) pins all three behaviours:^(a+)+$+ 30-'a' attack input → errors in < 50 ms^[a-z]+$,^\d{3}-\d{4}$, email-style) pass throughAcceptance-criteria:
Closing.