Skip to content

[Security][Rust Frontend] Add input validation to gRPC and HTTP stop_token_ids - #45569

Open
jperezdealgaba wants to merge 2 commits into
vllm-project:mainfrom
jperezdealgaba:fix/rust-grpc-input-validation
Open

jperezdealgaba wants to merge 2 commits into
vllm-project:mainfrom
jperezdealgaba:fix/rust-grpc-input-validation

Conversation

@jperezdealgaba

@jperezdealgaba jperezdealgaba commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add missing input validation to the Rust gRPC Generate/GenerateStream frontend to reject malformed requests before they reach EngineCore
  • Add stop_token_ids vocab-range validation to the Rust HTTP completions and chat completions paths
  • Thread max_logprobs (default 20) through TextBackend -> TextLlm -> ChatLlm -> AppState for logprobs count enforcement

Motivation

The Rust gRPC converter (convert.rs) forwarded user-controlled fields into SamplingParams without the bounds checking that the Python path enforces in SamplingParams.verify() and the GPU sampler's fixed-size buffers. A caller could submit a single request with out-of-range token IDs, oversized field lists, or uncapped logprob counts, causing EngineCore to hit a fatal assertion or OOM and requiring a full service restart.
The Rust HTTP path also lacked stop_token_ids vocab-range validation, allowing the same class of crash through the OpenAI-compatible API.

Security Advisories Fixed

Advisory Severity Field Issue
GHSA-rwfw-xvg3-3937 Medium CandidateTokens.top_n Bypasses max_logprobs cap; u32->i32 cast can overflow
GHSA-6pgw-f3pv-4h8q Medium output_candidates.token_ids Bypasses MAX_LOGPROB_TOKEN_IDS (128) and vocab range
GHSA-w2v2-5662-8v5q Medium prompt.token_ids No vocab-range check on gRPC path
GHSA-qff2-492f-9fm4 Medium stop_token_ids No vocab-range check on gRPC or HTTP paths
GHSA-mmrv-74wf-6pxm Medium allowed_token_ids, logit_bias, stop_token_ids No size caps matching GPU sampler buffers

Changes

gRPC validation (rust/src/server/src/grpc/convert.rs):

  • Introduced ValidationBounds struct populated from AppState vocab sizes and max_logprobs
  • Added validation for prompt token_ids (vocab range), stop_token_ids (count <= 128, vocab range), allowed_token_ids (count <= 1024, vocab range), logit_bias (count <= 1024, vocab range), logprobs count (top_n <= max_logprobs, overflow guard), and logprob_token_ids (count <= 128, vocab range)
  • All invalid requests return INVALID_ARGUMENT before reaching the engine
    HTTP stop_token_ids validation (rust/src/server/src/routes/openai/):
  • Added validate_stop_token_ids() in utils/token_ids.rs
  • Called from both completions/validate.rs and chat_completions/validate.rs
    max_logprobs plumbing (rust/src/text/, rust/src/chat/, rust/src/server/src/state.rs):
  • Added max_logprobs() method to TextBackend trait (default 20), threaded through TextLlm, ChatLlm, and AppState

Validation constants (matching Python/GPU sampler caps)

Constant Value Python equivalent
MAX_LOGPROB_TOKEN_IDS 128 sampling_params.MAX_LOGPROB_TOKEN_IDS
MAX_NUM_ALLOWED_TOKEN_IDS 1024 logit_bias.MAX_NUM_ALLOWED_TOKEN_IDS
MAX_NUM_LOGIT_BIAS_TOKENS 1024 logit_bias.MAX_NUM_LOGIT_BIAS_TOKENS
MAX_NUM_STOP_TOKEN_IDS 128 logit_bias.MAX_NUM_STOP_TOKEN_IDS

Test plan

  • 16 new unit tests in grpc/convert.rs covering all rejection cases (out-of-vocab, oversized, overflow) and valid pass-through
  • All 28 grpc::convert tests pass
  • All 22 HTTP validation tests pass (existing + new stop_token_ids coverage)
  • All 49 vllm-text and vllm-chat crate tests pass
  • cargo clippy clean (0 warnings)
  • cargo fmt clean
  • Pre-commit hooks pass

…token_ids

Add missing input validation to the Rust gRPC Generate frontend and
HTTP stop_token_ids to prevent denial-of-service via EngineCore
termination from malformed requests.
- Validate prompt token_ids, stop_token_ids, allowed_token_ids,
  logit_bias, logprobs count, and logprob_token_ids against vocab
  size and GPU sampler buffer caps in the gRPC converter
- Guard CandidateTokens.top_n u32->i32 cast overflow and cap at
  max_logprobs (default 20)
- Add validate_stop_token_ids to HTTP completions and chat
  completions paths
- Thread max_logprobs through TextBackend -> TextLlm -> ChatLlm ->
  AppState
Signed-off-by: Juan Pérez de Algaba <jperezde@redhat.com>

Signed-off-by: jperezde <jperezde@redhat.com>

@BugenZhao BugenZhao left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the work. The newly added validations are valuable; however, I personally think we're mixing too many orthogonal things in a single PR, while each of them only covers basic validation rather than semantic parity with the Python frontend.

For example, in this PR we hardcode max_logprobs to DEFAULT_MAX_LOGPROBS instead of respecting the CLI option --max-logprobs. I've opened a PR for a more thorough implementation: #45674

@BugenZhao

Copy link
Copy Markdown
Member

Also, I think we may need some refactoring of the validation first: it is currently done within the handlers for different endpoints, so it can be very easy to miss some of them (just like that we missed it in gRPC, which this PR is going to address). Ideally we should push the validation down to a common/shared layer to avoid such duplication and make it more future-proof.

@mergify

mergify Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts that must be resolved before it can be
merged. Please rebase the PR, @jperezdealgaba.

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@jperezdealgaba

Copy link
Copy Markdown
Collaborator Author

Closing this MR as it was included here: #45685

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants