ruvnet/ruflo · error
Pattern rejected: nested quantifiers detected (potential ReD
Error message
Pattern rejected: nested quantifiers detected (potential ReDoS): ${pattern} What it means
MemoryAuthority.addPattern() compiles caller-supplied regexes into irreversibility classifications, so it screens them for catastrophic-backtracking constructs first. Nested quantifiers such as `(a+)+`, `(a*)*`, or `(\w+){2,}*` can turn an adversarial subject string into exponential CPU time (ReDoS), and because these patterns run over memory-change descriptions they are rejected before `new RegExp` ever runs. The heuristic test itself is a regex over the pattern text.
Source
Thrown at v3/@claude-flow/guidance/src/authority.ts:672
return this.costlyReversiblePatterns.map(p => p.source);
case 'reversible':
return this.reversiblePatterns.map(p => p.source);
}
}
/**
* Add a pattern to a classification.
*
* Validates the pattern against ReDoS heuristics before accepting it.
* Rejects patterns with nested quantifiers (e.g., `(a+)+`) that can
* cause catastrophic backtracking.
*
* @throws Error if the pattern is invalid regex or contains ReDoS-prone constructs
*/
addPattern(classification: IrreversibilityClass, pattern: string): void {
// ReDoS heuristic: reject nested quantifiers like (a+)+, (a*)+, (a+)*, etc.
if (/([+*]|\{[0-9]+,?\})\s*\)[\s]*[+*]|\{[0-9]+,?\}/.test(pattern)) {
throw new Error(`Pattern rejected: nested quantifiers detected (potential ReDoS): ${pattern}`);
}
// Also reject patterns longer than 500 chars as a sanity bound
if (pattern.length > 500) {
throw new Error(`Pattern rejected: exceeds maximum length of 500 characters`);
}
const regex = new RegExp(pattern, 'i');
switch (classification) {
case 'irreversible':
this.irreversiblePatterns.push(regex);
break;
case 'costly-reversible':
this.costlyReversiblePatterns.push(regex);
break;
case 'reversible':
this.reversiblePatterns.push(regex);
break;View on GitHub (pinned to fa13ee4ad6)
Solutions
- Flatten the pattern: `(a+)+` → `a+`; `(\w+)*` → `\w*`
- Use a single bounded repetition: `(?:ab){1,10}` instead of `(ab+)+`
- Validate patterns against the same heuristic in your test suite before shipping them to production
- If the construct is unavoidable, pre-filter input length so backtracking is bounded
Example fix
// before
authority.addPattern('irreversible', '(a+)+b'); // throws ReDoS rejection
// after
authority.addPattern('irreversible', 'a+b'); // no nested quantifier Defensive patterns
Strategy: validation
Validate before calling
const nestedQuantifier =
/([+*]|\{[0-9]+,?\})\s*\)[\s]*[+*]|\{[0-9]+,?\}/;
if (nestedQuantifier.test(pattern)) {
throw new Error(`pattern contains nested quantifiers: ${pattern}`);
}
authority.addPattern(classification, pattern); Prevention
- Unit-test every classification pattern against the same heuristic
- Never pass user- or LLM-authored regexes straight to addPattern()
- Prefer flattened patterns (a+ over (a+)+) when translating matchers
When it happens
Trigger: addPattern('irreversible', '(a+)+'); any pattern where a quantifier (+, *, or {n,}) immediately follows a group that itself contains a quantifier, e.g. '(\\w+)*', '(.|a)+*'; feeding unvetted patterns sourced from user input or LLM output.
Common situations: Auto-generating classification patterns from logs or model output; copy-pasting a regex from an answer site that uses nested quantifiers; converting a glob or fuzzy matcher to regex and accidentally nesting repetition.
Related errors
- Pattern rejected: exceeds maximum length of 500 characters
- Validation failed: ${result.error}
- ${toolsJson} must contain a JSON array of {name, description
- basePath contains disallowed characters
- memory path contains disallowed characters
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/4b2b4bcea2c061a1.
Report an issue: GitHub.