CVE-2026-54234
vLLM: Remote DoS in vLLM via Invalid Recovered Token Reinjection
vLLM is a high-throughput and memory-efficient inference and serving engine for LLMs. Prior to 0.24.0, a frontend-legal multi-request speculative decoding workload can cause the rejection sampler to produce a recovered token equal to the model vocabulary size boundary value, which is then converted to negative one when the engine selects the next live token for a request and is written back into the drafter's input ids; that out-of-vocabulary value is later consumed by the model's embedding and attention path and crashes the engine worker with a GPU device-side assertion. The same triggering request sequence is reachable through the public gRPC Generate and Abort endpoints, so a remote client that can send generation requests can crash the shared engine worker, aborting concurrent requests and causing a service-wide denial of service for other clients of the deployment until the worker is restarted. This issue is fixed in version 0.24.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- None
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
7.5
vLLM: Remote DoS in vLLM via Invalid Recovered Token Reinjection
vLLM is a high-throughput and memory-efficient inference and serving engine for LLMs. Prior to 0.24.0, a frontend-legal multi-request speculative decoding workload can cause the rejection sampler to produce a recovered token equal to the model vocabulary size boundary value, which is then converted to negative one when the engine selects the next live token for a request and is written back into the drafter's input ids; that out-of-vocabulary value is later consumed by the model's embedding and attention path and crashes the engine worker with a GPU device-side assertion. The same triggering request sequence is reachable through the public gRPC Generate and Abort endpoints, so a remote client that can send generation requests can crash the shared engine worker, aborting concurrent requests and causing a service-wide denial of service for other clients of the deployment until the worker is restarted. This issue is fixed in version 0.24.0.
- Record
CVE-2026-54234- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-20, CWE-1284
- Updated
- 2026-11-02
EUVDEUVD-2026-41921
7.5
vLLM is a high-throughput and memory-efficient inference and serving engine for LLMs. Prior to 0.24.0, a frontend-legal multi-request speculative decoding workload can cause the rejection sampler to produce a recovered token equal to the model vocabulary size boundary value, which is then converted to negative one when the engine selects the next live token for a request and is written back into the drafter's input ids; that out-of-vocabulary value is later consumed by the model's embedding and attention path and crashes the engine worker with a GPU device-side assertion. The same triggering request sequence is reachable through the public gRPC Generate and Abort endpoints, so a remote client that can send generation requests can crash the shared engine worker, aborting concurrent requests and causing a service-wide denial of service for other clients of the deployment until the worker is restarted. This issue is fixed in version 0.24.0.
- Record
EUVD-2026-41921- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-8wr5-jm2h-8r4f
7.5
vLLM has Remote DoS via Invalid Recovered Token Reinjection
Summary
A frontend-legal multi-request speculative workload can make vLLM produce an out-of-vocabulary recovered token equal to vocab_size, convert that value to -1 when choosing the next live token for a request, and then feed that -1 back into the next drafter input ids. On Qwen3 GPTQ this reaches the worker-side drafting / attention path and crashes the engine with a GPU device-side assert.
The same issue is reachable through the public gRPC request surface by sending a specific overlapping Generate / Abort sequence.
Impact
- A remote client that can send public gRPC generation requests can crash the shared vLLM engine worker
- The triggering request sequence aborts concurrent requests and prevents later requests from completing until the worker is restarted
- In shared deployments, this is a service-wide denial of service for other clients, not just a failure isolated to the attacking requests
- The failure is reproducible, so repeated request sequences can sustain the outage
Affected version
- Confirmed on vLLM
0.17.1 - Earlier and later versions have not been checked yet in this report
Repro model
- Official Hugging Face repo:
- Anyone wants to reproduce the bug with my PoC scripts should download
Qwen3-0.6B-GPTQ-Int8first
Trigger chain
- A legal multi-request speculative workload keeps structured-output state, speculative decoding, overlap, and request cancellation active in the same live engine.
- During rejection sampling, vLLM produces a recovered token equal to the
model
vocab_sizeboundary value. - That recovered token appears in position 0 of the sampled speculative row
for a live request. The same row also contains trailing padding entries
equal to
-1, but those padding entries are not the key fault by themselves. - The next-token preparation step treats the position-0 recovered token as the
real next token for that request and converts that out-of-vocabulary value
to
-1. - The drafter writes that converted
-1back into the live next-step input-id row for the request. - The drafting / embedding / attention path later consumes that live invalid token and the worker crashes on GPU.
Details
Simple example
The important distinction is:
- trailing
-1values in a speculative row can be ordinary padding - the bug appears when the first live token for a request becomes
151936 == vocab_size, and that live token is then converted into-1
In simplified form, the bad transition looks like this:
sampled speculative row:
[151936, -1, -1, -1, ...]
At this point, the trailing -1 values are only padding. The critical problem
is that the first position holds 151936, which is out of vocabulary and is
being treated as the request's real next token.
Then vLLM prepares the next-token buffer:
next_token_ids:
[-1, ...]
Finally, that converted -1 is written back into the live model input ids:
input_ids_after:
[-1, 0, 0, 0, ...]
The crash happens because the live next token became -1 and was later consumed by the drafting / embedding / attention path, not merely because the speculative row contained padded -1 entries.
Trigger path in code
- The workload is frontend-legal. The requests use normal
SamplingParamsfeatures such as structured outputs,stop,bad_words,min_tokens, and streaming overlap. No malformed token-id list is required at the request boundary. - In speculative decoding, the rejection sampler can generate recovered tokens
when drafted tokens are rejected.
On the verified Qwen3 run,…# vllm/v1/sample/rejection_sampler.py def sample_recovered_tokens(...): recovered_token_ids = torch.empty_like(draft_token_ids) sample_recovered_tokens_kernel[(batch_size, max_spec_len)](...) return recovered_token_ids
- Record
GHSA-8wr5-jm2h-8r4f- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-20
- Updated
- 2026-11-02
NVD
7.5
vLLM is a high-throughput and memory-efficient inference and serving engine for LLMs. Prior to 0.24.0, a frontend-legal multi-request speculative decoding workload can cause the rejection sampler to produce a recovered token equal to the model vocabulary size boundary value, which is then converted to negative one when the engine selects the next live token for a request and is written back into the drafter's input ids; that out-of-vocabulary value is later consumed by the model's embedding and attention path and crashes the engine worker with a GPU device-side assertion. The same triggering request sequence is reachable through the public gRPC Generate and Abort endpoints, so a remote client that can send generation requests can crash the shared engine worker, aborting concurrent requests and causing a service-wide denial of service for other clients of the deployment until the worker is restarted. This issue is fixed in version 0.24.0.
- Record
CVE-2026-54234- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-20, CWE-1284
- Updated
- 2026-11-02
OSV
7.5
vLLM: Remote DoS in vLLM via Invalid Recovered Token Reinjection
vLLM is a high-throughput and memory-efficient inference and serving engine for LLMs. Prior to 0.24.0, a frontend-legal multi-request speculative decoding workload can cause the rejection sampler to produce a recovered token equal to the model vocabulary size boundary value, which is then converted to negative one when the engine selects the next live token for a request and is written back into the drafter's input ids; that out-of-vocabulary value is later consumed by the model's embedding and attention path and crashes the engine worker with a GPU device-side assertion. The same triggering request sequence is reachable through the public gRPC Generate and Abort endpoints, so a remote client that can send generation requests can crash the shared engine worker, aborting concurrent requests and causing a service-wide denial of service for other clients of the deployment until the worker is restarted. This issue is fixed in version 0.24.0.
- Record
CVE-2026-54234- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-1284, CWE-20
- Updated
- 2026-11-10
OSVGHSA-8wr5-jm2h-8r4f
7.5
vLLM has Remote DoS via Invalid Recovered Token Reinjection
Summary
A frontend-legal multi-request speculative workload can make vLLM produce an out-of-vocabulary recovered token equal to vocab_size, convert that value to -1 when choosing the next live token for a request, and then feed that -1 back into the next drafter input ids. On Qwen3 GPTQ this reaches the worker-side drafting / attention path and crashes the engine with a GPU device-side assert.
The same issue is reachable through the public gRPC request surface by sending a specific overlapping Generate / Abort sequence.
Impact
- A remote client that can send public gRPC generation requests can crash the shared vLLM engine worker
- The triggering request sequence aborts concurrent requests and prevents later requests from completing until the worker is restarted
- In shared deployments, this is a service-wide denial of service for other clients, not just a failure isolated to the attacking requests
- The failure is reproducible, so repeated request sequences can sustain the outage
Affected version
- Confirmed on vLLM
0.17.1 - Earlier and later versions have not been checked yet in this report
Repro model
- Official Hugging Face repo:
- Anyone wants to reproduce the bug with my PoC scripts should download
Qwen3-0.6B-GPTQ-Int8first
Trigger chain
- A legal multi-request speculative workload keeps structured-output state, speculative decoding, overlap, and request cancellation active in the same live engine.
- During rejection sampling, vLLM produces a recovered token equal to the
model
vocab_sizeboundary value. - That recovered token appears in position 0 of the sampled speculative row
for a live request. The same row also contains trailing padding entries
equal to
-1, but those padding entries are not the key fault by themselves. - The next-token preparation step treats the position-0 recovered token as the
real next token for that request and converts that out-of-vocabulary value
to
-1. - The drafter writes that converted
-1back into the live next-step input-id row for the request. - The drafting / embedding / attention path later consumes that live invalid token and the worker crashes on GPU.
Details
Simple example
The important distinction is:
- trailing
-1values in a speculative row can be ordinary padding - the bug appears when the first live token for a request becomes
151936 == vocab_size, and that live token is then converted into-1
In simplified form, the bad transition looks like this:
sampled speculative row:
[151936, -1, -1, -1, ...]
At this point, the trailing -1 values are only padding. The critical problem
is that the first position holds 151936, which is out of vocabulary and is
being treated as the request's real next token.
Then vLLM prepares the next-token buffer:
next_token_ids:
[-1, ...]
Finally, that converted -1 is written back into the live model input ids:
input_ids_after:
[-1, 0, 0, 0, ...]
The crash happens because the live next token became -1 and was later consumed by the drafting / embedding / attention path, not merely because the speculative row contained padded -1 entries.
Trigger path in code
- The workload is frontend-legal. The requests use normal
SamplingParamsfeatures such as structured outputs,stop,bad_words,min_tokens, and streaming overlap. No malformed token-id list is required at the request boundary. - In speculative decoding, the rejection sampler can generate recovered tokens
when drafted tokens are rejected.
On the verified Qwen3 run,…# vllm/v1/sample/rejection_sampler.py def sample_recovered_tokens(...): recovered_token_ids = torch.empty_like(draft_token_ids) sample_recovered_tokens_kernel[(batch_size, max_spec_len)](...) return recovered_token_ids
- Record
GHSA-8wr5-jm2h-8r4f- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-20
- Updated
- 2026-11-02
OSVPYSEC-2026-3542
7.5
vLLM has Remote DoS via Invalid Recovered Token Reinjection
Summary
A frontend-legal multi-request speculative workload can make vLLM produce an out-of-vocabulary recovered token equal to vocab_size, convert that value to -1 when choosing the next live token for a request, and then feed that -1 back into the next drafter input ids. On Qwen3 GPTQ this reaches the worker-side drafting / attention path and crashes the engine with a GPU device-side assert.
The same issue is reachable through the public gRPC request surface by sending a specific overlapping Generate / Abort sequence.
Impact
- A remote client that can send public gRPC generation requests can crash the shared vLLM engine worker
- The triggering request sequence aborts concurrent requests and prevents later requests from completing until the worker is restarted
- In shared deployments, this is a service-wide denial of service for other clients, not just a failure isolated to the attacking requests
- The failure is reproducible, so repeated request sequences can sustain the outage
Affected version
- Confirmed on vLLM
0.17.1 - Earlier and later versions have not been checked yet in this report
Repro model
- Official Hugging Face repo:
- Anyone wants to reproduce the bug with my PoC scripts should download
Qwen3-0.6B-GPTQ-Int8first
Trigger chain
- A legal multi-request speculative workload keeps structured-output state, speculative decoding, overlap, and request cancellation active in the same live engine.
- During rejection sampling, vLLM produces a recovered token equal to the
model
vocab_sizeboundary value. - That recovered token appears in position 0 of the sampled speculative row
for a live request. The same row also contains trailing padding entries
equal to
-1, but those padding entries are not the key fault by themselves. - The next-token preparation step treats the position-0 recovered token as the
real next token for that request and converts that out-of-vocabulary value
to
-1. - The drafter writes that converted
-1back into the live next-step input-id row for the request. - The drafting / embedding / attention path later consumes that live invalid token and the worker crashes on GPU.
Details
Simple example
The important distinction is:
- trailing
-1values in a speculative row can be ordinary padding - the bug appears when the first live token for a request becomes
151936 == vocab_size, and that live token is then converted into-1
In simplified form, the bad transition looks like this:
sampled speculative row:
[151936, -1, -1, -1, ...]
At this point, the trailing -1 values are only padding. The critical problem
is that the first position holds 151936, which is out of vocabulary and is
being treated as the request's real next token.
Then vLLM prepares the next-token buffer:
next_token_ids:
[-1, ...]
Finally, that converted -1 is written back into the live model input ids:
input_ids_after:
[-1, 0, 0, 0, ...]
The crash happens because the live next token became -1 and was later consumed by the drafting / embedding / attention path, not merely because the speculative row contained padded -1 entries.
Trigger path in code
- The workload is frontend-legal. The requests use normal
SamplingParamsfeatures such as structured outputs,stop,bad_words,min_tokens, and streaming overlap. No malformed token-id list is required at the request boundary. - In speculative decoding, the rejection sampler can generate recovered tokens
when drafted tokens are rejected.
On the verified Qwen3 run,…# vllm/v1/sample/rejection_sampler.py def sample_recovered_tokens(...): recovered_token_ids = torch.empty_like(draft_token_ids) sample_recovered_tokens_kernel[(batch_size, max_spec_len)](...) return recovered_token_ids
- Record
PYSEC-2026-3542- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
Affected products
Affected packages
History
| Recorded | Changed | Sources |
|---|---|---|
| facts | OSV | |
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-54234 is a high vulnerability (CVSS 7.5) in Vllm, published July 6, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.62%, the 49th percentile. Fixed in vllm 0.24.0.
References
github.com/vllm-project/vllm/security/advisories/GHSA-8wr5-jm2h-8r4f
github.com/vllm-project/vllm/pull/44744
github.com/vllm-project/vllm/commit/8a5cf1ccd65e8ac7635c402c1ec0b08988bc26ca
nvd.nist.gov/vuln/detail/CVE-2026-54234
github.com/advisories/GHSA-8wr5-jm2h-8r4f
github.com/CVEProject/cvelistV5/tree/main/cves/2026/54xxx/CVE-2026-54234.json
github.com/vllm-project/vllm
pypi.org/project/vllm
Left out here: the rest of 3 source descriptions. The JSON record has them.