---
id: "GHSA-w2v2-5662-8v5q"
page: "https://infrastack.ai/live/GHSA-w2v2-5662-8v5q"
kind: "vulnerability"
aliases: ["GHSA-w2v2-5662-8v5q"]
title: "Rust gRPC Generate accepts out-of-vocabulary prompt token IDs and can terminate EngineCore"
severity: "medium"
cvss: 5.9
epss: null
exploited: false
status: "open"
category: "ai-tooling"
products: [{"name": "vllm", "fixed": ["0.24.0"], "affected": ">= 0.22.0, < 0.24.0", "ecosystem": "pypi"}]
ecosystems: ["pypi"]
tags: ["ai-tooling", "cwe-20", "cwe-400", "grpc", "python", "self-hosted", "vllm"]
not_affected_if: ["auth-required-in-front", "grpc-not-exposed", "version-outside-range"]
published_at: "2026-10-09T07:49:41+00:00"
first_seen_at: "2026-11-09T22:53:23+00:00"
updated_at: "2026-11-09T23:01:02+00:00"
sources: [{"source": "ghsa-repo", "url": "https://github.com/vllm-project/vllm/security/advisories/GHSA-w2v2-5662-8v5q", "first_seen_at": "2026-11-09T22:53:23+00:00"}]
exploit_sources: []
---

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

Link for people: https://infrastack.ai/live/GHSA-w2v2-5662-8v5q (this .md is for agents)

The Rust gRPC Generate and GenerateStream endpoints in vLLM pass pre-tokenized prompt token IDs to the engine without checking them against the vocabulary. A single out-of-range token ID can crash EngineCore and leave the server unhealthy, a denial of service.

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

## Affected

- pypi:vllm affected >= 0.22.0, < 0.24.0 fixed 0.24.0

## How to check

- Check the installed vLLM version with `pip show vllm`; versions `>= 0.22.0, < 0.24.0` are affected.
- Check whether the Rust gRPC service is enabled and reachable from untrusted networks; the advisory describes it as a network-reachable surface.

## Fix

- `vllm` (PyPI): upgrade to `0.24.0`.

## Timeline

- 2026-11-09T22:53:23+00:00 ghsa-repo https://github.com/vllm-project/vllm/security/advisories/GHSA-w2v2-5662-8v5q

## Documents

- [advisory] Vendor advisory: github.com https://github.com/vllm-project/vllm/security/advisories/GHSA-w2v2-5662-8v5q

## From the sources

## 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:

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

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

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

The gRPC handlers then submit the converted `TextRequest`:

```rust
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:

```rust
Prompt::TokenIds(token_ids) => token_ids,
```

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

```rust
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](https://github.com/vllm-project/vllm/pull/45685).

---

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