T09 · Insecure Skill Coding Practices
- Location
scripts/regex_tester.py:4- Finding
Regular Expression Denial of Service Through Unbounded User-Controlled Patterns
- Content
View full analysis
Vulnerability Details
File Location:
scripts/regex_tester.py, lines 4–10
Vulnerability Type: Regular Expression Denial of Service (ReDoS)
Risk Level: MediumVulnerable Code
python def test_regex(pattern, text, mode='match'): try: if mode == 'match': matches = re.findall(pattern, text) return {'matches': matches, 'count': len(matches)} elif mode == 'replace': result = re.sub(pattern, '', text) return {'result': result}Technical Analysis
The function passes a user-controlled regular expression and user-controlled input text directly to Python's backtracking
reengine. Neitherre.findall()norre.sub()is subject to an execution timeout, input-length limit, memory limit, or pattern-complexity restriction.An attacker can therefore submit a pattern containing nested or ambiguous quantifiers and pair it with a long, near-matching string. For certain patterns, the engine explores an exponentially growing number of matching states before concluding that no match exists. The exception handler does not mitigate this issue because excessive backtracking does not normally raise an exception; it occupies the executing process until evaluation completes or the process is terminated externally.
Attack Path
- The attacker invokes the Skill with an expensive pattern, such as
(a+)+$. - The attacker supplies a sufficiently long near-matching input, such as a sequence of
acharacters followed byX. - The CLI forwards both values to
test_regex(). re.findall()attempts the match and performs catastrophic backtracking after encountering the final nonmatching character.- The worker consumes excessive CPU and may remain unavailable for an extended period. The same underlying issue applies to
re.sub()if replacement mode is exposed programmatically.
Impact Assessment
Successful exploitation does ...[truncated 518 chars]
- The attacker invokes the Skill with an expensive pattern, such as
- Remediation
View remediation
Remediation Suggestions
- Evaluate untrusted regular expressions in an isolated subprocess with a strict wall-clock timeout. Terminate the subprocess if the deadline is exceeded.
- Apply operating-system CPU and memory limits to the isolated worker so one expression cannot exhaust host resources.
- Enforce conservative maximum lengths for both the pattern and input text before attempting evaluation.
- Reject or restrict patterns containing constructs associated with catastrophic backtracking, such as nested quantifiers. Treat static pattern checks only as defense in depth because they cannot reliably identify every expensive expression.
- Where compatibility permits, replace Python's backtracking engine with a linear-time regular-expression engine suitable for untrusted patterns.
- Add rate limiting and concurrency limits at the calling boundary.
- Return a generic timeout or complexity error rather than allowing the request to occupy a worker indefinitely.
- Add regression tests using adversarial patterns and near-matching inputs to verify that execution is terminated within the configured resource budget.
