Skip to content

[SECURITY][SONAR][MEDIUM]: ReDoS vulnerability in SSTI validation patterns in validators.py #2366

@crivetimihai

Description

@crivetimihai

Severity: MEDIUM
File: mcpgateway/common/validators.py
Lines: 95-103
Rule: Security - ReDoS

Description

The Server-Side Template Injection (SSTI) prevention patterns use .* which is vulnerable to catastrophic backtracking (ReDoS - Regular Expression Denial of Service).

Vulnerable Code

_SSTI_PATTERNS: List[Pattern[str]] = [
    re.compile(r"\{\{.*(__|\.|config|self|request|application|globals|builtins|import).*\}\}", re.IGNORECASE),
    re.compile(r"\{%.*(__|\.|config|self|request|application|globals|builtins|import).*%\}", re.IGNORECASE),
    re.compile(r"\$\{.*\}", re.IGNORECASE),
    re.compile(r"#\{.*\}", re.IGNORECASE),
    re.compile(r"%\{.*\}", re.IGNORECASE),
    re.compile(r"\{\{.*\*.*\}\}", re.IGNORECASE),
    re.compile(r"\{\{.*\/.*\}\}", re.IGNORECASE),
    re.compile(r"\{\{.*\+.*\}\}", re.IGNORECASE),
    re.compile(r"\{\{.*\-.*\}\}", re.IGNORECASE),
]

Technical Analysis

The pattern \{\{.*keyword.*\}\} is vulnerable because:

  1. When given input like {{aaaa...aaaa (no closing }}), the regex engine will:

    • Try matching .* greedily to the end
    • Fail to find }}
    • Backtrack one character at a time
    • Try again at each position
  2. For input of length n, this results in O(n²) or worse time complexity.

  3. Input limit is 64KB (MAX_TEMPLATE_LENGTH = 65536), which is large enough to cause noticeable delays.

Impact

An attacker could submit crafted input to validation endpoints, causing:

  • High CPU usage
  • Request timeouts
  • Potential denial of service

Suggested Fix

Replace .* with negated character classes that cannot backtrack:

_SSTI_PATTERNS: List[Pattern[str]] = [
    # Use [^}]* instead of .* to prevent backtracking
    re.compile(r"\{\{[^}]*(__|\.|config|self|request|application|globals|builtins|import)[^}]*\}\}", re.IGNORECASE),
    re.compile(r"\{%[^%]*(__|\.|config|self|request|application|globals|builtins|import)[^%]*%\}", re.IGNORECASE),
    re.compile(r"\$\{[^}]*\}", re.IGNORECASE),
    re.compile(r"#\{[^}]*\}", re.IGNORECASE),
    re.compile(r"%\{[^}]*\}", re.IGNORECASE),
    re.compile(r"\{\{[^}]*\*[^}]*\}\}", re.IGNORECASE),
    re.compile(r"\{\{[^}]*\/[^}]*\}\}", re.IGNORECASE),
    re.compile(r"\{\{[^}]*\+[^}]*\}\}", re.IGNORECASE),
    re.compile(r"\{\{[^}]*\-[^}]*\}\}", re.IGNORECASE),
]

Metadata

Metadata

Assignees

Labels

MUSTP1: Non-negotiable, critical requirements without which the product is non-functional or unsafebugSomething isn't workingpythonPython / backend development (FastAPI)securityImproves securitysonarSonarQube code quality findings

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions