{"schema":"threatline.record/2","record":{"id":"GHSA-4xqp-c3mv-qff7","aliases":["GHSA-4xqp-c3mv-qff7"],"summary":"An oversized min_tokens in one request hangs the vLLM engine while /health stays green","details":"## Summary\r\n\r\nAny client that can reach `/inference/v1/generate`, mounted by default in v0.29.0 and unauthenticated unless `--api-key` is set, can stop `vllm serve` from serving with one request. The body sets `sampling_params.max_tokens` to `null` and `min_tokens` to 2147483648. The EngineCore, the single scheduler process, re-validates it in its input thread, which dies; the process stays up, `/health` answers 200, every later request hangs.\r\n\r\n## Root cause\r\n\r\nThe `min_tokens <= max_tokens` check runs in [`_verify_args`](https://github.com/vllm-project/vllm/blob/c1b69aa0d49b88016b5b2156ae61649c2c2df282/vllm/sampling_params.py#L616-L620) only when `max_tokens` is set. On `/inference/v1/generate` the API process builds `SamplingParams` [directly from the JSON](https://github.com/vllm-project/vllm/blob/c1b69aa0d49b88016b5b2156ae61649c2c2df282/vllm/entrypoints/scale_out/token_in_token_out/protocol.py#L209) with `max_tokens=None`, so the check is skipped; the processor then [fills in `max_tokens`](https://github.com/vllm-project/vllm/blob/c1b69aa0d49b88016b5b2156ae61649c2c2df282/vllm/v1/engine/input_processor.py#L358-L362) (2045 here) without validating again and forwards the request.\r\n\r\nIn the EngineCore, [`process_input_sockets`](https://github.com/vllm-project/vllm/blob/c1b69aa0d49b88016b5b2156ae61649c2c2df282/vllm/v1/engine/core.py#L1757) decodes the message, which rebuilds `SamplingParams` and runs `_verify_args` a second time. Now both values are present and `VLLMValidationError` is raised on the decode line, one line above the `try` that protects request handling:\r\n\r\n```python\r\n1757                        req: EngineCoreRequest = add_request_decoder.decode(data_frames)  # <-\r\n1758                        try:\r\n1759                            request = self.preprocess_add_request(req)\r\n...\r\n1765                        except Exception:\r\n1766                            self._handle_request_preproc_error(req)\r\n1767                            continue\r\n```\r\n\r\nThe exception is not caught, so the thread exits. It was the only reader of the input socket: no request reaches the scheduler any more, but nothing reports it, because the scheduler loop just waits on an empty queue, the thread is checked [only at start-up](https://github.com/vllm-project/vllm/blob/c1b69aa0d49b88016b5b2156ae61649c2c2df282/vllm/v1/engine/core.py#L1135-L1136), and [`check_health`](https://github.com/vllm-project/vllm/blob/c1b69aa0d49b88016b5b2156ae61649c2c2df282/vllm/v1/engine/async_llm.py#L1025-L1028) only looks for a recorded error. `/health` keeps answering 200 while every generation request hangs.\r\n\r\nThe OpenAI routes resolve `max_tokens` before building `SamplingParams`, so there the check runs in the API process and returns HTTP 400.\r\n\r\n\r\n## Impact\r\n\r\n- **Who can trigger it** — Any network client, no credentials, that can reach `/inference/v1/generate`: mounted by default on a `vllm serve` of v0.29.0, and on main when `VLLM_ENABLE_SCALE_OUT_ENDPOINTS=1` or `--tokens-only` is set.\r\n- **What they get** — One 92-byte request stops the server from serving any route for every client; later requests hang until the client gives up. The process stays alive and `/health` keeps answering 200, so nothing restarts it. Recovery is a manual restart.\r\n\r\n---\r\nThe initial discovery was made by AI scanning tools in Microsoft Security FORGE Labs, and later all technical claims has been reviewed and validated by human experts.\r\n\r\nA public fix is available here: https://github.com/vllm-project/vllm/pull/57731 ","categories":["Unclassified"],"product":"vllm","vendor":"","ecosystem":null,"affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/vllm-project/vllm/security/advisories/GHSA-4xqp-c3mv-qff7","source_modified_at":"2026-10-06T07:10:58Z","fetched_at":"2026-10-24T23:06:24.700873Z","package":{"ecosystem":"pip","name":"vllm"},"range":"< 0.31.0"}],"fixed_versions":[],"cvss":6.5,"severity":"Medium","kev":{"listed":false},"epss":{"probability":null,"percentile":null,"score_date":null},"published_at":"2026-10-06T06:58:15Z","modified_at":"2026-10-06T07:10:58Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/vllm-project/vllm/security/advisories/GHSA-4xqp-c3mv-qff7","fetched_at":"2026-10-24T23:06:24.700873Z","source_modified_at":"2026-10-06T07:10:58Z"}],"sources":["GitHub Advisory Database"],"references":[],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":null,"confidence":"unknown","reviewed":false},"change_timestamp":"2026-10-06T07:10:58Z","content_hash":"a86565fd83217410d57b45d29fe3e4a14bf8d7203ce4bf4a4730cd29a07d1f2d"}}
