All vulnerabilities
GHSA-w2v2-5662-8v5q

vllm: Rust gRPC Generate accepts out-of-vocabulary prompt token IDs and can terminate EngineCore

vllm
CVSS
5.9Medium
ExploitationNo known exploitationNot in CISA KEV, which does not prove it is unexploitedCISA KEV
Exploit odds (EPSS)No scoreNo FIRST EPSS score in this snapshot yet
Fixed in0.24.0Fixed versionGitHub
Published9 Oct 2026Updated 27 Oct 2026GitHub

What fixes it

A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.

Description

Summary

The Rust gRPC Generate and GenerateStream service accepts pre-tokenized prompt IDs from the protobuf TokenIds field and forwards them to TextLlm/EngineCore without checking them against the served model or tokenizer vocabulary.

This is the gRPC sibling of the public Rust HTTP /inference/v1/generate issue fixed in PR #45441: a single prompt token ID such as 9000000 can reach the engine embedding lookup, trigger a fatal EngineCore failure, and leave the server unhealthy. PR #45441 adds validation for the HTTP /inference/v1/generate route, but it does not touch rust/src/server/src/grpc/*.

Technical Details

rust/proto/vllm_grpc.proto exposes pre-tokenized prompts:

oneof prompt {
  string text = 3;
  TokenIds token_ids = 4;
}

rust/src/server/src/grpc/convert.rs maps those IDs directly:

Some(pb::generate_request::Prompt::TokenIds(ids)) => Prompt::TokenIds(ids.ids),

The gRPC handlers then submit the converted TextRequest:

let text_request =
    convert::to_text_request(proto_req, false, self.state.served_model_names())?;
let stream = self.state.chat.text().generate(text_request).await;

For pre-tokenized prompts, rust/src/text/src/lib.rs intentionally bypasses tokenization:

Prompt::TokenIds(token_ids) => token_ids,

rust/src/model/src/request.rs forwards the IDs into the engine request:

prompt_token_ids: Some(prompt_token_ids),

There is no gRPC-side equivalent of the token-id range validators used by the Rust OpenAI routes.

The Rust OpenAI validation layer already treats out-of-vocabulary token IDs as invalid client input. rust/src/server/src/routes/openai/utils/token_ids.rs rejects prompt token IDs, allowed_token_ids, and logit_bias keys outside the relevant vocabulary bounds.

PR #44680 added that validator family to /v1/completions and /v1/chat/completions. PR #45441 extends the same validator family to the Rust HTTP /inference/v1/generate route after demonstrating that an OOV token_ids prompt kills EngineCore. The gRPC service still lacks the same pre-submit guard.

Impact

An attacker who can reach a vLLM Rust gRPC endpoint can submit a Generate or GenerateStream request with an out-of-vocabulary prompt.token_ids value. The request is accepted by the gRPC frontend and submitted to the shared text generation path. The same invalid token-id sink is documented publicly in PR #45441 as aborting EngineCore for the Rust HTTP sibling route.

Expected impact is a single-request denial of service for deployments exposing the Rust gRPC service. Fixed behavior should be an INVALID_ARGUMENT gRPC status before the request is submitted to the engine.

Suggested severity: High if the gRPC endpoint is network-reachable without an additional deployment-layer credential requirement.

Suggested CVSS v3.1:

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H = 7.5

If maintainers model the gRPC surface as reachable only to already-authorized clients, the same issue becomes:

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H = 6.5

Suggested CWEs:

  • CWE-20: Improper Input Validation
  • CWE-400: Uncontrolled Resource Consumption

Suggested Fix

Apply the same token-id range validation used by the Rust OpenAI and HTTP generate routes before either gRPC handler calls state.chat.text().generate().

The gRPC fix should validate:

  • GenerateRequest.prompt.token_ids against the same prompt bound used by PR #45441, namely the union of tokenizer and model vocabulary bounds.
  • DecodingParameters.allowed_token_ids against tokenizer vocabulary.
  • DecodingParameters.logit_bias keys against model vocabulary.
  • ResponseOptions.prompt_candidates.token_ids and ResponseOptions.output_candidates.token_ids, if they are lowered into logprob_token_ids, against the same model/tokenizer bounds used by the corresponding HTTP route.

Add tests for both unary Generate and streaming GenerateStream that assert OOV token IDs return INVALID_ARGUMENT before any engine request is submitted.

Appendix: Duplicate Research

I checked:

  • Public PR #44680: validates Rust /v1/completions and /v1/chat/completions; changed files do not touch gRPC.
  • Public PR #45441: validates Rust HTTP /inference/v1/generate; changed files do not touch gRPC.
  • GitHub issue/PR searches for grpc token_ids out-of-vocab, grpc Generate token_ids EngineCore, and grpc token_ids validation: no public gRPC duplicate found.
  • vLLM security advisories matching grpc, token_ids, out-of-vocab, EngineCore, or Generate: no gRPC duplicate found.
  • Local prior vLLM submissions: none cover Rust gRPC prompt token-id range validation.

Affected versions

  • Package: vllm (PyPI).
  • Affected versions: >= 0.22.0, < 0.24.0.
  • First stable patched version: 0.24.0.

Advisory fixed in #45685.

Text from GitHub Advisory Database

Affected versions 1

  • vllm, pip>= 0.22.0, < 0.24.0GitHub