Skip to content

[Security] Fix ReDoS in validation error path sanitizer - #52120

Open
jperezdealgaba wants to merge 1 commit into
vllm-project:mainfrom
jperezdealgaba:triage/GHSA-f2g9-sanitize-regex-dos
Open

[Security] Fix ReDoS in validation error path sanitizer#52120
jperezdealgaba wants to merge 1 commit into
vllm-project:mainfrom
jperezdealgaba:triage/GHSA-f2g9-sanitize-regex-dos

Conversation

@jperezdealgaba

Copy link
Copy Markdown
Contributor

Summary

  • Fix CWE-1333 regex denial-of-service in sanitize_message() where a 100KB slash-delimited input ("/a" * 50000) could keep an API worker busy for 3+ seconds per rejected request.
  • Add a dot-character pre-check to skip the generic path regex entirely when no filename extension is possible, and use an atomic group (?>...) to prevent backtracking within repeated slash-segments for messages that do contain dots.
  • Addresses GHSA-f2g9-pmwr-xwc7.

Test plan

  • pytest tests/entrypoints/serve/utils/test_api_utils.py -v — 22 tests pass (4 new ReDoS regression tests)
  • pytest tests/entrypoints/serve/utils/test_error_sanitization.py -v — 9 tests pass
  • pre-commit run --files <changed files> — all hooks pass
  • Reproduced advisory PoC shape ("/a" * 50000): completes in <0.1ms after fix (was 3+ second hang)
  • Verified legitimate path redaction still works (/app/server.py, /usr/lib/... etc.)

Made with Cursor

The generic file-path regex in sanitize_message used a pattern with
nested repetition that caused catastrophic backtracking on long
slash-delimited strings without a filename extension. A 100KB
malformed request field could keep the sanitizer busy for 3+ seconds,
allowing a remote client to degrade API worker availability.

Fix: skip the generic path regex entirely when the message contains no
dot character (the required extension anchor), and use an atomic group
(?>...) to prevent backtracking within the repeated slash-segments on
messages that do contain dots. Both changes ensure near-linear-time
sanitization regardless of input shape.

Addresses GHSA-f2g9-pmwr-xwc7 (CWE-1333).

Signed-off-by: Juan Pérez de Algaba <jperezde@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

Signed-off-by: jperezde <jperezde@redhat.com>

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@mergify mergify Bot added the frontend label Aug 13, 2026
@DarkLight1337
DarkLight1337 enabled auto-merge (squash) August 13, 2026 07:54
@github-actions github-actions Bot added the ready ONLY add when PR is ready to merge/full CI is needed label Aug 13, 2026
@DarkLight1337

Copy link
Copy Markdown
Member

/ci run

@github-actions

Copy link
Copy Markdown

✅ Triggered Buildkite CI #83696 for commit 83752a87abd7.

Comment on lines +319 to +320
if "." in message:
message = re.sub(r"(?>/[\w\-]+)+/[\w\-]+\.\w+", "<path>", message)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Severity: MEDIUM

The atomic group (?>...) prevents exponential backtracking but still exhibits O(n²) behavior: re.sub retries the pattern at every /-position, each time the atomic group scans the remaining input. Input like "/a" * 5000 + " error.txt" (dot bypasses the pre-check) takes ~9 seconds; at 50k segments it would block a worker for minutes. The original advisory PoC shape is only partially mitigated.
Helpful? Add 👍 / 👎

💡 Fix Suggestion

Suggestion: Add a message length guard to the if condition on line 319 to bound the O(n²) behavior. The re.sub retries the atomic-group pattern at every /-position, each scanning forward through the remaining input, creating quadratic time complexity. By capping the message length for this specific regex (e.g., len(message) <= 2048), the worst-case time is bounded to ~30ms. Legitimate error messages with file paths are well under 2KB, and the preceding known-root-directory regex on lines 316-318 already handles common paths (/home/..., /usr/..., etc.) without this quadratic issue. Alternatively, for a more comprehensive fix, consider truncating the message at the top of sanitize_message() (e.g., message = message[:4096]) to protect all regexes in the function, or replace the regex with a linear-time token-based approach.

⚠️ Experimental Feature: This code suggestion is automatically generated. Please review carefully.

Suggested change
if "." in message:
message = re.sub(r"(?>/[\w\-]+)+/[\w\-]+\.\w+", "<path>", message)
if "." in message and len(message) <= 2048:
message = re.sub(r"(?>/[\w\-]+)+/[\w\-]+\.\w+", "<path>", message)

@mergify

mergify Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts that must be resolved before it can be
merged. Please rebase the PR, @jperezdealgaba.

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase label Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

frontend needs-rebase ready ONLY add when PR is ready to merge/full CI is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants