Repository navigation
Conversation
…euse Fixes vllm-project#62307. kv_transfer_params["prompt_token_ids"] is the disaggregated-serving reuse path: the decode stage skips templating and tokenization because the prefill stage's ids arrive with the transfer coordination. But the renderer honored the key on every server, so on a plain server a client could supply ids that silently replace the rendered messages, skipping the chat template, truncate_prompt_tokens, and tokenization. The reuse gate now rejects the key with a 400 unless the server runs a KV transfer connector (--kv-transfer-config), which is the capability the contract already assumes. echo and non-text-content requests still ignore the ids and render messages as before. The shape and vocabulary checks added in vllm-project#55771/vllm-project#59555 keep their behavior once the gate passes. The two existing render-side shape tests now give their mock engine a connector sentinel, since the gate runs first; a new pair pins the gate (no connector -> 400 even for well-formed ids; connector -> ids skip templating and tokenization). Signed-off-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>
he-yufeng
requested review from
DarkLight1337,
chaunceyjiang and
njhill
as code owners
October 18, 2026 18:15
This was referenced Oct 28, 2026
hickeyma
reviewed
Nov 3, 2026
Contributor
There was a problem hiding this comment.
I agree with the bug in #62307 but I don't think kv_transfer_config is the right approach. llm-d-router#3706 forwards prompt_token_ids from the EPP on aggregated deployments too. Those have no KV connector which means every forwarded request would get a 400.
Two changes would cover both cases:
- Without a connector, ignore the IDs and render
messagesinstead of returning a 400. This is similar that what we do forechoand non-text content. That closes the hole and router requests still work. - Add an opt-in flag for deployments that want the IDs honored without a connector.
--enable-prompt-token-idswas already suggested on #55770.
#64721 sends prompt_features through this same helper, so whatever we pick needs to cover that as well.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #62307.
Why
kv_transfer_params["prompt_token_ids"]is the disaggregated-serving reuse path: the decode stage skips templating and tokenization because the prefill stage's ids arrive alongside the transfer coordination (do_remote_prefill/do_remote_decode). The reuse funnel_reused_prompt_token_idschecked the ids' shape (#55771) and vocabulary (#59555), but never checked that the server actually runs a KV transfer connector. On a plain server, any client could send harmless-lookingmessagesplus attacker-chosen ids and have the model run on the ids instead, with the chat template (and any system prompt it carries) silently dropped. First affected release: 0.27.0 (#48145).What changed
One gate in
vllm/renderers/online_renderer.py::_reused_prompt_token_ids: after the existingecho/ non-text-content bail-outs (which neutralize the ids and still rendermessages), the ids are now rejected with a 400 unlessrenderer.config.kv_transfer_configis set. The connector is the capability boundary the reuse contract already assumes, and both entry funnels (preprocess_chatand the Harmony branch) pass through this helper, so chat completions and responses are covered by the same check.Not done deliberately: restricting reuse to
/v1/chat/completionsonly. The docs example uses chat completions, but disaggregated deployments front the same engine with the responses API too, and the connector gate is what removes the deceptive surface; an endpoint ban would break those deployments without adding safety. Happy to add it if maintainers want the stricter reading.Tests
test_chat_kv_transfer_prompt_token_ids_rejected_without_kv_connector: well-formed ids on a connector-less server now raiseVLLMValidationErrornaming--kv-transfer-config; goes red if the gate is removed (mutation-checked).test_chat_kv_transfer_prompt_token_ids_reused_with_kv_connector: with a connector present, well-formed ids skip templating and tokenization (conversation == [], engine input carries the ids, remainingkv_transfer_paramspreserved).MagicMockrenderer whose config satisfies the gate unchanged.tests/entrypoints/openai/chat_completion/test_serving_chat.py: 208 passed; the 10 errors areTestGPTOSS*fixture setup failures that reproduce identically on pristine upstream/main on this machine (missing harmony deps), unrelated to this change.ruff checkandruff formatclean on both touched files.