| Описание | Credit / Discovered by:
Jiapeng Li, Mingkai Yu, Junkong, Xuanhao Liu, Jiajia Liu
(School of Cybersecurity, Northwestern Polytechnical University)
A vulnerability was found in vLLM 0.26.0 and later versions containing the vulnerable thinking-budget marker-search implementation. The vulnerability affects reasoning-enabled deployments that accept the thinking_token_budget parameter through the OpenAI-compatible Completion API. It has been classified as an inefficient algorithmic complexity vulnerability resulting in remote CPU resource consumption and cross-request partial denial of service.
The primary vulnerability exists in the thinking-budget state tracking implemented in:
vllm/v1/sample/thinking_budget_state.py
ThinkingBudgetStateHolder._update_think_state() locates the configured reasoning start and end markers while output tokens are appended during decoding.
An earlier implementation maintained independent incremental search cursors for the reasoning start and end markers. These cursors prevented token-history regions that had already been examined from being searched again, while retaining the small overlap required to detect markers split across consecutive decoding steps.
The change introduced by commit ed908cf0a08af20839b82dc0638dae91b1ad630b, merged through PR #45984 and included in vLLM 0.26.0, removed the incremental search cursors while fixing the handling of natural </think> termination and reasoning-block re-entry.
The affected implementation performs the equivalent of:
if state["start_thinking"] == -1:
output_slice = output_tok_ids[scan_offset:]
start_thinking = self._find_last_sequence_index(
output_slice, self.think_start_token_ids
)
if state["end_thinking"] == -1:
output_slice = output_tok_ids[scan_offset:]
end_thinking = self._find_last_sequence_index(
output_slice, self.think_end_token_ids
)
output_tok_ids[scan_offset:] creates a new list containing the growing output-token history. ThinkingBudgetStateHolder._find_last_sequence_index() then performs a backward linear search over that list.
If the generated output contains neither the reasoning start marker nor the reasoning end marker, both marker positions remain unresolved. At decoding step k, the implementation copies and scans approximately k output tokens for each marker.
For a request generating L output tokens, the cumulative processing cost is therefore:
W(L) = sum(k=1..L) O(k) = O(L^2)
The repeated list slicing also performs linear copying and temporary-list allocation during every decoding step. The regression therefore introduces both quadratic search work and repeated memory-allocation overhead.
The vulnerable request-processing path is reachable through the normal OpenAI-compatible API:
POST /v1/completions
-> CompletionRequest.thinking_token_budget
-> SamplingParams.thinking_token_budget
-> ThinkingBudgetStateHolder.sync_batch()
-> ThinkingBudgetStateHolder.update_state()
-> ThinkingBudgetStateHolder._update_think_state()
-> repeated full-history slicing and marker scanning
A remote client can trigger the vulnerable path using valid request parameters. The client supplies a non-None thinking_token_budget, a large max_tokens value, ignore_eos=true, and an allowed_token_ids value that cannot form either the configured reasoning start marker or the reasoning end marker.
For example, the following request was accepted with HTTP 200 in the tested environment:
{
"model": "f29-model",
"prompt": [13],
"max_tokens": 16384,
"temperature": 0,
"allowed_token_ids": [13],
"ignore_eos": true,
"thinking_token_budget": 1,
"stream": true,
"return_token_ids": true
}
In the tested Qwen3.5-4B configuration, token ID 13 was a non-marker token, while <think> and </think> used different token IDs. Consequently, neither marker was found, and the growing output-token history was copied and searched again during every decoding step.
The attack uses a valid Completion request and does not require malformed input, access to an internal Python interface, or exploitation of memory-unsafe behavior.
If the vLLM service exposes /v1/completions without API-key authentication or equivalent upstream access control, an unauthenticated remote client can reach the vulnerable path. If API-key protection is enabled, the attacker requires valid authentication.
Component-level measurements using the affected search implementation demonstrated the following candidate-position counts:
Generated length v0.25.0 checks v0.26.0 checks
256 512 65,792
512 1,024 262,656
1,024 2,048 1,049,600
2,048 4,096 4,196,352
4,096 8,192 16,781,312
The independently calculated log-log slope was 1.0000 for the incremental implementation used by vLLM 0.25.0 and approximately 1.998 for the affected vLLM 0.26.0 implementation. This establishes a linear-to-quadratic complexity regression without relying on GPU timing.
Concurrent long-running trigger requests cause the shared sampling path to spend increasing amounts of CPU time processing attacker-controlled output histories. This delays unrelated ordinary requests, including requests that do not contain thinking_token_budget.
In the tested NVIDIA A100 environment, 300 ordinary 32-token victim requests were submitted at one request per second. The following results were observed:
Condition Median victim E2E p95 victim E2E
v0.26.0 baseline 1,410 ms 1,491 ms
v0.26.0 with 32 triggers 3,727 ms 4,071 ms
v0.26.0 with 64 triggers 5,958 ms 6,277 ms
Cursor-restored baseline 1,437 ms 1,542 ms
Cursor-restored with 64 triggers 1,488 ms 1,563 ms
During the 64-trigger measurement, approximately 35 to 43 long-history trigger requests were active, with a median active concurrency of 39. The maximum observed victim latency was approximately 6.46 seconds.
All 300 victim requests still completed successfully within 30 seconds. No process crash, persistent outage, confidentiality impact, or integrity impact was observed. Service latency returned to its normal level after the trigger workload ended.
A remote attacker may exploit this vulnerability to cause disproportionate CPU consumption in the shared sampling path, increase inference latency for unrelated users, reduce effective inference throughput, and cause recoverable partial availability degradation.
The severity depends on the maximum permitted generation length, request concurrency, model throughput, reasoning configuration, API authentication, and any external request-rate or concurrency limits.
The correctness goal of PR #45984 is valid. A fix should preserve natural reasoning-block exit and re-entry behavior while restoring independent incremental cursors for the start and end markers. It should retain only the overlap required to detect markers split across decoding steps and avoid constructing output_tok_ids[scan_offset:] during every decoding step.
The vulnerability was introduced in vLLM 0.26.0. The vulnerable quadratic behavior is not present in vLLM 0.25.0, which retains incremental marker-search cursors.
This vulnerability was privately reported to the vLLM maintainers and acknowledged by the upstream project. In response, an upstream maintainer opened vLLM PR #51133 to restore incremental marker scanning and address the quadratic-complexity resource-consumption issue:
https://github.com/vllm-project/vllm/pull/51133
Affected product: vLLM
Affected versions: 0.26.0 and later versions containing the vulnerable implementation
Affected configuration: Reasoning-enabled deployments with configured reasoning start and end markers
Affected endpoint: /v1/completions
Unauthenticated attack condition:
The endpoint is externally reachable and the service is deployed without API-key authentication or equivalent upstream access control.
Primary affected file:
vllm/v1/sample/thinking_budget_state.py
Affected functions:
ThinkingBudgetStateHolder.update_state()
ThinkingBudgetStateHolder._update_think_state()
ThinkingBudgetStateHolder._find_last_sequence_index()
Vulnerability class:
Inefficient algorithmic complexity
Quadratic output-history processing
Remote CPU resource consumption
Cross-request partial availability degradation
Suggested CWE:
CWE-407: Inefficient Algorithmic Complexity
Impact:
Remote partial denial of service through disproportionate CPU consumption, increased inference latency, and reduced throughput for unrelated requests.
Upstream remediation:
vLLM PR #51133
https://github.com/vllm-project/vllm/pull/51133
Fixe |
|---|