vllm: Rust gRPC Generate accepts out-of-vocabulary prompt token IDs and can terminate EngineCore
What fixes it
- 0.24.0vllm, pipGitHub
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 ValidationCWE-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_idsagainst the same prompt bound used by PR#45441, namely the union of tokenizer and model vocabulary bounds.DecodingParameters.allowed_token_idsagainst tokenizer vocabulary.DecodingParameters.logit_biaskeys against model vocabulary.ResponseOptions.prompt_candidates.token_idsandResponseOptions.output_candidates.token_ids, if they are lowered intologprob_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/completionsand/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, andgrpc token_ids validation: no public gRPC duplicate found. - vLLM security advisories matching
grpc,token_ids,out-of-vocab,EngineCore, orGenerate: 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