GHSA-87x5-vmc3-756j CVE-2026-73559 PYSEC-2026-3704
vLLM: Completion prompt lists fan out into unbounded engine requests
- Severity
- 6.5 / 10
- Medium · CVSS 3.1
- Exploit chance (EPSS)
- 0.58%
- Chance of exploitation in the next 30 days. Higher than 47.88% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Weakness
- CWE-400 Uncontrolled Resource Consumption
- Fix
0.26.0- Upgrade vllm to this version or later
Description
Summary
The /v1/completions request model accepts prompt as a list of text prompts or a list of token-id prompts without any outer prompt-count bound. The serving path turns each element into a separate engine input, creates one engine generator per element, merges all generators, and allocates a response slot per prompt. An authenticated API client can therefore turn one request into an attacker-chosen number of backend subrequests before any aggregate request-count budget is enforced.
Technical Details
CompletionRequest.prompt allows both list-shaped prompt inputs and scalar prompts:
# vllm/entrypoints/openai/completion/protocol.py
prompt: (
list[Annotated[int, Field(ge=0)]]
| list[list[Annotated[int, Field(ge=0)]]]
| str
| list[str]
| None
) = None
The validator only requires some prompt-like input to be present:
def validate_prompt_and_prompt_embeds(cls, data):
prompt = data.get("prompt")
prompt_embeds = data.get("prompt_embeds")
...
if prompt_is_empty and embeds_is_empty:
raise VLLMValidationError(...)
The renderer then expands list-shaped prompts as a sequence. prompt_to_seq() wraps a scalar string or a single token-id list, but returns a list[str] or list[list[int]] unchanged:
# vllm/renderers/inputs/preprocess.py
def prompt_to_seq(prompt_or_prompts):
if isinstance(prompt_or_prompts, (dict, str, bytes)) or (
len(prompt_or_prompts) > 0 and is_list_of(prompt_or_prompts, int)
):
return [prompt_or_prompts]
return prompt_or_prompts
OnlineRenderer.preprocess_completion() appends that whole sequence, and the renderer processes every element:
# vllm/renderers/online_renderer.py
prompts = list[SingletonPrompt | bytes]()
if prompt_input is not None:
prompts.extend(prompt_to_seq(prompt_input))
...
parsed_prompts = [
prompt if isinstance(prompt, bytes) else parse_model_prompt(model_config, prompt)
for prompt in prompts
]
return await renderer.render_cmpl_async(parsed_prompts, tok_params, ...)
Finally, completion serving creates one backend generator and one response slot per rendered prompt:
# vllm/entrypoints/openai/completion/serving.py
generators: list[AsyncGenerator[RequestOutput, None]] = []
for i, engine_input in enumerate(engine_inputs):
...
generator = self.engine_client.generate(...)
generators.append(generator)
result_generator = merge_async_iterators(*generators)
num_prompts = len(engine_inputs)
...
final_res_batch: list[RequestOutput | None] = [None] * num_prompts
The violated invariant is that one HTTP request should have a bounded backend request count. Current code enforces per-prompt token and sampling limits, but not the number of prompts in the outer completion request.
PoV
A minimal oversized request keeps normal generation parameters small but supplies a large outer prompt list:
{
"model": "served-model",
"prompt": ["x", "x", "x"],
"max_tokens": 1,
"n": 1
}
Scaling the prompt array to tens or hundreds of thousands of short entries makes the server allocate, preprocess, schedule, merge, and buffer one subrequest per entry. The same applies to token-id prompt lists:
{
"model": "served-model",
"prompt": [[1], [1], [1]],
"max_tokens": 1,
"n": 1
}
The intended negative control is a scalar prompt:
{
"model": "served-model",
"prompt": "x",
"max_tokens": 1,
"n": 1
}
The scalar string is wrapped as one prompt; the list form is not bounded and fans out by list length.
Impact
An authenticated API client can make one /v1/completions request consume CPU, memory, async task scheduling, engine request slots, and response buffering proportional to an attacker-chosen outer prompt list. This can starve or disrupt other tenants sharing the same vLLM server. The report does not claim unauthenticated access, confidentiality impact, integrity impact, code execution, or impact where /v1/completions is not reachable by untrusted or semi-trusted clients.
Suggested Fix
Reject oversized prompt lists before renderer preprocessing. Add an outer prompt-count limit to CompletionRequest.prompt when the prompt is list[str] or list[list[int]], and consider making the limit configurable in the same style as the batch-chat and sampling-list bounds. The check should run before OnlineRenderer.preprocess_completion() expands the prompt sequence, so oversized requests do not allocate parsed prompt lists, async render/tokenization tasks, engine generators, or response result slots.
Regression coverage should include a scalar prompt, a bounded prompt list, an oversized list[str], and an oversized list[list[int]]. The oversized requests should fail with a controlled validation error before any backend generator is created.
Affected Package/Versions
Package ecosystem: pip
Package name: vllm
Affected range confirmed by source proof: >=0.19.0, <=0.24.0; current main at cbe9c40f998f13975b967773ac7e7920e115387f remains affected.
Patched versions: unknown.
Latest release checked: v0.24.0, published on 2026-06-29.
GitHub Advisory Metadata
Package ecosystem: pip
Package name: vllm
Vulnerable version range: >=0.19.0, <=0.24.0
Patched versions: unknown
Advisory History
Public issue and PR searches for CompletionRequest prompt list, "prompt" "list[str]" "completion", and "CompletionRequest" "max_length" did not find an existing report or fix for this exact path.
The closest published advisory is GHSA-3mwp-wvh9-7528, "OOM Denial of Service via Unbounded n Parameter in OpenAI API Server", patched in 0.19.0. This report is distinct because it keeps n=1 and uses the /v1/completions prompt outer list to create one engine request per prompt. The fix invariant is an outer prompt-count and aggregate request budget, not only a generated-sequence-count cap.
The closest public PR is vllm-project/vllm#45390, which covers multiple DoS fixes including GHSA-83mh-6mwq-3hg9 for BatchChatCompletionRequest.messages. That PR adds an outer bound to batch chat conversations, but its diff does not touch vllm/entrypoints/openai/completion/protocol.py or vllm/entrypoints/openai/completion/serving.py.
Prior local/private report families checked included pooling/rerank batch fanout, derender token-id postprocessing, explicit truncation_side tokenizer-limit bypass, Python disaggregated generate prompt-length bypass, and priority scheduling. Those reports differ by endpoint, attacker-controlled field, sink, and fix surface.
Affected versions
PyPI
| Package | Vulnerable | Fixed in |
|---|---|---|
| vllm | >= 0.19.0, < 0.26.0 |
0.26.0 |
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
vllm PyPI → 0.26.0
- pip
pip install --upgrade "vllm>=0.26.0"- poetry
poetry add "vllm>=0.26.0"- uv
uv add "vllm>=0.26.0"
Severity breakdown
CVSS 3.1 6.5
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H
- Attack vector
- Network
- Attack complexity
- Low
- Privileges required
- Low
- User interaction
- None
- Scope
- Unchanged
- Confidentiality
- None
- Integrity
- None
- Availability
- High
Weakness
CWE-400: Uncontrolled Resource Consumption
The product does not properly control the allocation and maintenance of a limited resource.
How to prevent it
- Architecture and Design: Design throttling mechanisms into the system architecture. The best protection is to limit the amount of resources that an unauthorized user can cause to be expended. A strong authentication and access control model will help prevent such attacks from occurring in the first place. The login application should be protected against DoS attacks as much as possible. Limiting the database access, perhaps by caching result sets, can help minimize the resources expended. To further limit the potential for a DoS attack, consider tracking the rate of requests received from users and blocking requests that exceed a defined rate threshold.
- Architecture and Design: Mitigation of resource exhaustion attacks requires that the target system either: recognizes the attack and denies that user further access for a given amount of time, or uniformly throttles all requests in order to make it more difficult to consume resources more quickly than they can again be freed. The first of these solutions is an issue in itself though, since it may allow attackers to prevent the use of the system by a particular valid user. If the attacker impersonates the valid user, they may be able to prevent the user from accessing the server in question. The second solution is simply difficult to effectively institute -- and even when properly done, it does not provide a full solution. It simply makes the attack require more resources on the part of the attacker.
- Architecture and Design: Ensure that protocols have specific limits of scale placed on them.
- Implementation: Ensure that all failures in resource allocation place the system into a safe posture.
References
Advisories
Packages
Other links
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| GHSA-8397-8qf6-f2gm vLLM: Phi-4 multimodal audio encoder materializes and retains full attention matrices: a single max-length audio OOM-crashes the vLLM engine | Medium | Also affects vllm |
| GHSA-x567-49g5-p4cf vLLM: Responses API bypasses trust_request_chat_template for chat_template_kwargs | Medium | Also affects vllm |
| GHSA-vvpg-rrww-wpmh vLLM: Permissive default CORS origins allow cross-origin requests to the vLLM HTTP server | Medium | Also affects vllm |
| GHSA-q97c-p368-75c4 vLLM: Out-of-vocabulary prompt token id passes input validation and triggers a CUDA device-side assert (engine crash / DoS) | Medium | Also affects vllm |
| GHSA-h3rc-j82p-2c3h vLLM: Untrusted EPS inputs can trigger denial of service or Ghostscript RCE | High | Also affects vllm |
| GHSA-gq5q-89c7-vhvx vLLM DeepSeek-OCR image processing vulnerable to denial of service | Medium | Also affects vllm |
| GHSA-6757-hggm-hp2w vLLM: Public multimodal SHM handle forgery reaches worker-side `pickle.loads()` with insecure serialization disabled | High | Also affects vllm |
| GHSA-542m-9234-8gvf vLLM: DoS via unbounded chat_template Jinja2 rendering exhausts the renderer thread pool | Medium | Also affects vllm |
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor