An untrusted multimodal request can set mm_processor_kwargs.code_revision. When vLLM serves a model whose Hugging Face processor uses dynamic auto_map code and the operator enabled --trust-remote-code, this request value reaches AutoProcessor.from_pretrained and selects the Python revision imported by Transformers.
This lets a client replace the operator-reviewed processor module with code from another revision of the same model repository. The operator-selected model/data revision remains pinned; only the executed processor code changes.
Importing a Python module is arbitrary code execution in the vLLM API/renderer process. The PoC below demonstrates this with an import-time filesystem write. It is fully offline and does not require a GPU, model weights, or changes to a real Hub repository.
vllm-project/vllm570735520942b6428ae98f1eb442c6d88adae55eThe vulnerable path exists when all of the following are true:
auto_map.AutoProcessor code.trust_remote_code.The default trust_remote_code=False configuration is not affected.
mm_processor_kwargs is accepted directly by public request models:
/tokenize is particularly relevant because vLLM's authentication middleware guards only /v1, /v2, /inference, and /cohere prefixes:
Consequently, /tokenize remains unauthenticated even when --api-key is configured, unless an external proxy protects it. The vLLM Security Guide documents /tokenize as an unprotected endpoint.
The request value follows this path:
OnlineRenderer.preprocess_chat places request mm_processor_kwargs in prompt extras.MMProcessorInputs and _process_multimodal_async.MultiModalConfig.merge_mm_processor_kwargs overlays inference values on startup values, so the request wins.cached_get_processor_without_dynamic_kwargs filters only recognized processor-call keys. code_revision is retained as a processor-construction kwarg.cached_processor_from_config pins revision and trust_remote_code, but forwards the remaining kwargs without reserving code_revision.get_processor calls AutoProcessor.from_pretrained(..., revision=revision, trust_remote_code=trust_remote_code, **kwargs).AutoProcessor.from_pretrained uses code_revision to retrieve and import the dynamic module through get_class_from_dynamic_module, then removes it before loading processor data. This is why code comes from the attacker revision while configuration/data remain operator-pinned.Request-time processor arguments are not separated from processor-construction arguments, and code_revision is not reserved.
code_revision and other loader/source controls in request mm_processor_kwargs, and pass model_config.code_revision explicitly as the only permitted processor-code revision./tokenize with the configured authentication policy as defense in depth.Expected safe behavior is either a 4xx response for reserved request keys or silently ignoring them before processor construction. Rejection is preferable because it makes attempted misuse visible.
A patch for this was merged here: https://github.com/vllm-project/vllm/pull/58830
{
"cwe_ids": [
"CWE-829",
"CWE-94"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-27T15:36:17Z",
"nvd_published_at": null,
"severity": "HIGH"
}