GHSA-q97c-p368-75c4

Suggest an improvement
Source
https://github.com/advisories/GHSA-q97c-p368-75c4
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-q97c-p368-75c4/GHSA-q97c-p368-75c4.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-q97c-p368-75c4
Aliases
Downstream
CGA (6)
Published
2026-10-28T21:15:08Z
Modified
2026-10-29T11:10:41Z
Severity
  • 6.5 (Medium) CVSS_V3 - CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H CVSS Calculator
Summary
vLLM: Out-of-vocabulary prompt token id passes input validation and triggers a CUDA device-side assert (engine crash / DoS)
Details

For a model whose vocabulary size is an exact multiple of the embedding padding size (64) — e.g. any Llama-2-family model, vocab 32000 — a single request carrying a pre-tokenized prompt with token id equal to the vocab size (32000) passes vLLM's input-id validation but is one past the last embedding row. At tensor-parallel size 1 the embedding lookup does not mask indices, so the id reaches F.embedding out of range and raises a CUDA device-side assert, which poisons the engine's CUDA context and takes the engine down. Any client that can send pre-tokenized input (/v1/completions with prompt as token ids, /tokenize-fed flows, or the kv_transfer_params["prompt_token_ids"] reuse path) can trigger it.

Root cause

vllm/v1/engine/input_processor.py accepts a token id when id <= max(tokenizer.max_token_id, model_config.get_vocab_size() - 1). vllm/tokenizers/hf.py computes max_token_id = max(max(vocab.values()), tokenizer.vocab_size). For Llama-2 tokenizers max(vocab.values()) = 31999 but tokenizer.vocab_size = 32000, so max_token_id = 32000 — one greater than the largest valid id. The engine bound therefore becomes max(32000, 31999) = 32000, and id 32000 is accepted. The model's embedding has pad_vocab_size(32000, 64) = 32000 rows (no padding), valid indices 0..31999. At VocabParallelEmbedding.forward with tp_size == 1 there is no masking, so index 32000 hits F.embedding out of range.

Affected

  • tp=1 (single GPU per model — common per-copy layout). tp>1 masks via get_masked_input_and_mask, so the id is clamped, not an OOB — likely wrong output rather than a crash.
  • Models whose vocab is a multiple of 64 with tokenizer.vocab_size one past the max real id (Llama-2 family, vocab 32000, is the clear case). Qwen2.5 is NOT affected (padded headroom).

Suggested fix

max_token_id in vllm/tokenizers/hf.py now uses tokenizer.vocab_size - 1, so an id equal to the vocabulary size fails input validation instead of reaching the embedding. Fixed in MR59491, released in v0.32.0.

Reporter

Shijie Lyu (GitHub shijie-lyu lshjhf@gmail.com). Reported privately per SECURITY.

This advisory was fixed in MR59491.

Database specific
{
    "cwe_ids":  [
        "CWE-129",
        "CWE-193"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-10-28T21:15:08Z",
    "nvd_published_at":  "2026-10-26T18:17:39Z",
    "severity":  "MODERATE"
}
References

Affected packages

PyPI / vllm

Package

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
0.32.0

Affected versions

0.*
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.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.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
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.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.26.0
0.27.0
0.27.1
0.28.0
0.29.0
0.30.0
0.31.0

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-q97c-p368-75c4/GHSA-q97c-p368-75c4.json"