PYSEC-2026-3937

Vulnerability from pysec - Published: 2026-09-10 09:45 - Updated: 2026-09-10 11:02
VLAI
Details

Summary

When the vLLM API receives a malformed request (e.g., invalid JSON or missing required fields), FastAPI raises a Pydantic RequestValidationError. The validation_exception_handler in vllm/entrypoints/openai/server_utils.py converts this exception to a string via str(exc), which includes the internal file path and line number of the handler function. The existing sanitize_message() function in vllm/entrypoints/utils.py strips memory addresses (e.g., 0x7f...) but does not strip File "...", line X patterns. The result is a user-facing HTTP response that leaks internal system information.

Impact

An unauthenticated attacker can extract the following with a single malformed request:

  • OS username running the vLLM process (e.g., ubuntu)
  • Home directory path (e.g., /home/ubuntu/)
  • Virtual environment path (e.g., vllm-env/)
  • Python version (e.g., 3.12)
  • Internal package structure and line numbers (e.g., vllm/entrypoints/openai/chat_completion/api_router.py)
  • Handler function names per endpoint, enabling precise version fingerprinting

This information aids attackers in constructing targeted exploits: environment paths narrow the attack surface, and handler function names + line numbers enable exact version identification even when the /version endpoint is disabled.

All POST endpoints that accept JSON bodies are affected, including /v1/chat/completions, /v1/completions, /tokenize, and /detokenize.

Workarounds

Deploying vLLM behind a reverse proxy that rewrites error response bodies to strip file paths would mitigate this, though it is fragile.

Remediation Recommendation

Two possible fixes (either suffices):

Option A — Fix validation_exception_handler: Construct the error message from exc.errors() (the structured Pydantic error list) rather than str(exc). This avoids the traceback-style string entirely.

Option B — Fix sanitize_message: Add a regex to strip File "...", line \d+ patterns, similar to how memory addresses are already stripped:

import re
msg = re.sub(r'File ".*?", line \d+, in \w+', '[internal]', msg)

Option A is preferred as it addresses the root cause rather than filtering symptoms.

Environment Tested

  • vLLM 0.20.1 (pip install, latest stable as of May 2026)
  • Python 3.12
  • Ubuntu 22.04
  • Model: Qwen/Qwen2-0.5B (text-only; bug is model-independent)

This was fixed here: https://github.com/vllm-project/vllm/commit/e87521626f

Impacted products
Name purl
vllm pkg:pypi/vllm

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "vllm",
        "purl": "pkg:pypi/vllm"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.26.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ],
      "versions": [
        "0.0.1",
        "0.1.0",
        "0.1.1",
        "0.1.2",
        "0.1.3",
        "0.1.4",
        "0.1.5",
        "0.1.6",
        "0.1.7",
        "0.10.0",
        "0.10.1",
        "0.10.1.1",
        "0.10.2",
        "0.11.0",
        "0.11.1",
        "0.11.2",
        "0.12.0",
        "0.13.0",
        "0.14.0",
        "0.14.1",
        "0.15.0",
        "0.15.1",
        "0.16.0",
        "0.17.0",
        "0.17.1",
        "0.18.0",
        "0.18.1",
        "0.19.0",
        "0.19.1",
        "0.2.0",
        "0.2.1",
        "0.2.1.post1",
        "0.2.2",
        "0.2.3",
        "0.2.4",
        "0.2.5",
        "0.2.6",
        "0.2.7",
        "0.20.0",
        "0.20.1",
        "0.20.2",
        "0.21.0",
        "0.22.0",
        "0.22.1",
        "0.23.0",
        "0.24.0",
        "0.25.0",
        "0.25.1",
        "0.3.0",
        "0.3.1",
        "0.3.2",
        "0.3.3",
        "0.4.0",
        "0.4.0.post1",
        "0.4.1",
        "0.4.2",
        "0.4.3",
        "0.5.0",
        "0.5.0.post1",
        "0.5.1",
        "0.5.2",
        "0.5.3",
        "0.5.3.post1",
        "0.5.4",
        "0.5.5",
        "0.6.0",
        "0.6.1",
        "0.6.1.post1",
        "0.6.1.post2",
        "0.6.2",
        "0.6.3",
        "0.6.3.post1",
        "0.6.4",
        "0.6.4.post1",
        "0.6.5",
        "0.6.6",
        "0.6.6.post1",
        "0.7.0",
        "0.7.1",
        "0.7.2",
        "0.7.3",
        "0.8.0",
        "0.8.1",
        "0.8.2",
        "0.8.3",
        "0.8.4",
        "0.8.5",
        "0.8.5.post1",
        "0.9.0",
        "0.9.0.1",
        "0.9.1",
        "0.9.2"
      ]
    }
  ],
  "aliases": [
    "CVE-2026-73555",
    "GHSA-hwrm-c4cx-rf4j"
  ],
  "details": "## Summary\n\nWhen the vLLM API receives a malformed request (e.g., invalid JSON or missing required fields), FastAPI raises a Pydantic `RequestValidationError`. The `validation_exception_handler` in `vllm/entrypoints/openai/server_utils.py` converts this exception to a string via `str(exc)`, which includes the internal file path and line number of the handler function. The existing `sanitize_message()` function in `vllm/entrypoints/utils.py` strips memory addresses (e.g., `0x7f...`) but does not strip `File \"...\", line X` patterns. The result is a user-facing HTTP response that leaks internal system information.\n\n## Impact\n\nAn unauthenticated attacker can extract the following with a single malformed request:\n\n- **OS username** running the vLLM process (e.g., `ubuntu`)\n- **Home directory path** (e.g., `/home/ubuntu/`)\n- **Virtual environment path** (e.g., `vllm-env/`)\n- **Python version** (e.g., `3.12`)\n- **Internal package structure and line numbers** (e.g., `vllm/entrypoints/openai/chat_completion/api_router.py`)\n- **Handler function names per endpoint**, enabling precise version fingerprinting\n\nThis information aids attackers in constructing targeted exploits: environment paths narrow the attack surface, and handler function names + line numbers enable exact version identification even when the `/version` endpoint is disabled.\n\nAll POST endpoints that accept JSON bodies are affected, including `/v1/chat/completions`, `/v1/completions`, `/tokenize`, and `/detokenize`.\n\n## Workarounds\n\nDeploying vLLM behind a reverse proxy that rewrites error response bodies to strip file paths would mitigate this, though it is fragile.\n\n## Remediation Recommendation\n\nTwo possible fixes (either suffices):\n\n**Option A \u2014 Fix `validation_exception_handler`:** Construct the error message from `exc.errors()` (the structured Pydantic error list) rather than `str(exc)`. This avoids the traceback-style string entirely.\n\n**Option B \u2014 Fix `sanitize_message`:** Add a regex to strip `File \"...\", line \\d+` patterns, similar to how memory addresses are already stripped:\n\n```python\nimport re\nmsg = re.sub(r\u0027File \".*?\", line \\d+, in \\w+\u0027, \u0027[internal]\u0027, msg)\n```\n\nOption A is preferred as it addresses the root cause rather than filtering symptoms.\n\n## Environment Tested\n\n- vLLM 0.20.1 (pip install, latest stable as of May 2026)\n- Python 3.12\n- Ubuntu 22.04\n- Model: Qwen/Qwen2-0.5B (text-only; bug is model-independent)\n\nThis was fixed here: https://github.com/vllm-project/vllm/commit/e87521626f",
  "id": "PYSEC-2026-3937",
  "modified": "2026-09-10T11:02:35.773647Z",
  "published": "2026-09-10T09:45:00.131177Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/vllm-project/vllm/security/advisories/GHSA-hwrm-c4cx-rf4j"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-73555"
    },
    {
      "type": "WEB",
      "url": "https://github.com/vllm-project/vllm/pull/46415"
    },
    {
      "type": "WEB",
      "url": "https://github.com/vllm-project/vllm/commit/e87521626febe2763f997691d1599de4175f4324"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/vllm-project/vllm"
    },
    {
      "type": "WEB",
      "url": "https://github.com/vllm-project/vllm/releases/tag/v0.26.0"
    },
    {
      "type": "PACKAGE",
      "url": "https://pypi.org/project/vllm"
    },
    {
      "type": "ADVISORY",
      "url": "https://github.com/advisories/GHSA-hwrm-c4cx-rf4j"
    }
  ],
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "vLLM: Unauthenticated Internal Path and Username Disclosure via Validation Error Messages"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…