---
id: "GHSA-q9v9-qpjp-fc24"
page: "https://infrastack.ai/live/GHSA-q9v9-qpjp-fc24"
kind: "vulnerability"
aliases: ["GHSA-q9v9-qpjp-fc24"]
title: "Unauthenticated EngineCore crash via out-of-range prompt token id under skip_tokenizer_init (incomplete fix of GHSA-25q3-v2hm-8vpf)"
severity: "high"
cvss: 7.5
epss: null
exploited: false
status: "open"
category: "ai-tooling"
products: [{"name": "vllm", "fixed": ["0.33.0"], "affected": ">= 0.28.0, < 0.33.0", "ecosystem": "pypi"}]
ecosystems: ["pypi"]
tags: ["ai-tooling", "cwe-1284", "cwe-20", "llm-serving", "python", "self-hosted", "vllm"]
not_affected_if: ["auth-required", "tokenizer-enabled", "vllm-0.33.0-or-later", "vllm-below-0.28.0"]
published_at: "2026-11-02T19:50:12+00:00"
first_seen_at: "2026-11-09T22:53:23+00:00"
updated_at: "2026-11-09T22:54:19+00:00"
sources: [{"source": "ghsa-repo", "url": "https://github.com/vllm-project/vllm/security/advisories/GHSA-q9v9-qpjp-fc24", "first_seen_at": "2026-11-09T22:53:23+00:00"}]
exploit_sources: []
---

# Unauthenticated EngineCore crash via out-of-range prompt token id under skip_tokenizer_init (incomplete fix of GHSA-25q3-v2hm-8vpf)

Link for people: https://infrastack.ai/live/GHSA-q9v9-qpjp-fc24 (this .md is for agents)

When vLLM runs with --skip-tokenizer-init, a single unauthenticated request with a large prompt token id makes the shared EngineCore crash. The crash takes the engine and API server down for every user until the process restarts.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- pypi:vllm affected >= 0.28.0, < 0.33.0 fixed 0.33.0

## How to check

- Check the installed version with `pip show vllm`; affected range is `>= 0.28.0` and `< 0.33.0`.
- Check whether the server is started with `--skip-tokenizer-init`.

## Fix

- Move `vllm` to `0.33.0` or later (the advisory's fixed version in the product data).

## Timeline

- 2026-11-09T22:53:23+00:00 ghsa-repo https://github.com/vllm-project/vllm/security/advisories/GHSA-q9v9-qpjp-fc24

## Documents

- [advisory] Maintainer's advisory: github.com https://github.com/vllm-project/vllm/security/advisories/GHSA-q9v9-qpjp-fc24

## From the sources

### Summary

A single unauthenticated request with an out-of-range prompt token id crashes
the shared EngineCore (and the API-server process) when vLLM is served with
`--skip-tokenizer-init`, denying service to all tenants until the process is
restarted.

The vocab-range validation added for GHSA-25q3-v2hm-8vpf lives in
`InputProcessor._validate_model_input` but is gated on `tokenizer is not None`.
`--skip-tokenizer-init` is the mode where the client is expected to send raw
token ids (pre-tokenized / token-in-token-out / RL serving), and there is no
tokenizer, so the check is skipped entirely. The OpenAI `/v1/completions`
`prompt` field only constrains integer ids from below (`Field(ge=0)`), so a
large positive id passes all validation, reaches the embedding as an index, and
raises out of the model forward. EngineCore treats that as fatal and shuts down.
The same gap reopens the `/v1/embeddings` and `/pooling` paths that GHSA-25q3
originally covered, whenever the tokenizer is disabled.

Verified against `main` at HEAD `dc89fdfb0e` (2026-09-15).

### Details

`vllm/v1/engine/input_processor.py`, `_validate_model_input`:

```python
if prompt_ids and tokenizer is not None:   # <- skipped when tokenizer is None
    ...
    if min_input_id < 0: raise VLLMValidationError("... out of vocabulary")
    if max_input_id > max(tokenizer.max_token_id, model_vocab_size - 1):
        raise VLLMValidationError("... out of vocabulary")
```

Reachability (unauthenticated; the OpenAI server has no auth by default):

```
/v1/completions (prompt = list[int], Field(ge=0) only, no upper bound)
  -> InputProcessor.process_inputs -> _validate_model_inputs
  -> _validate_model_input  # tokenizer is None -> vocab check skipped
  -> model forward -> embedding index out of range -> exception
EngineCore._process_engine_step -> run_busy_loop (no per-step guard)
  -> run_engine_core: "EngineCore encountered a fatal error" -> _send_engine_dead
```

The busy loop has no per-request guard around the model step, so the exception
is fatal for the whole engine, not scoped to the offending request.

### Impact

Unauthenticated remote denial of service (availability): one request
permanently takes down the shared engine for all tenants, on any deployment run
with `--skip-tokenizer-init` (pre-tokenized / token-in-token-out / RL serving).
Same class as GHSA-25q3-v2hm-8vpf (High), whose remediation did not cover the
tokenizer-disabled path. CWE-20 / CWE-1284 / CWE-248.

### Suggested fix

Run the vocab-range check whenever prompt ids are present, not only when a
tokenizer exists. When the tokenizer is disabled, use `model_config
.get_vocab_size() - 1` as the upper bound; otherwise keep the existing
`max(tokenizer.max_token_id, model_vocab_size - 1)` bound. This validation is implemented by the merged fix.

Reported by Matteo Atkinson (matteoatkinson@gmail.com), with AI assistance.

A fix for this was introduced in https://github.com/vllm-project/vllm/pull/62911.

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
