GHSA-H3RC-6MM3-GC2M
Vulnerability from github – Published: 2026-10-27 15:36 – Updated: 2026-10-27 15:36Summary
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.
Affected snapshot
- Repository:
vllm-project/vllm - Verified commit:
570735520942b6428ae98f1eb442c6d88adae55e - Verified with Transformers 5.15.0 and 5.16.1
- Affected release range has not been bisected
Affected configuration
The vulnerable path exists when all of the following are true:
- The served model's processor uses dynamic
auto_map.AutoProcessorcode. - The operator enabled
trust_remote_code. - The server can fetch the request-selected revision, or it is already cached.
- The attacker can create or otherwise control a revision in the served model repository. An example is a Hugging Face community pull-request ref when that repository permits them.
- A multimodal request reaches the processor path.
The default trust_remote_code=False configuration is not affected.
Attack surface
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.
Root cause
The request value follows this path:
OnlineRenderer.preprocess_chatplaces requestmm_processor_kwargsin prompt extras.- Multimodal rendering forwards those kwargs into processor construction through
MMProcessorInputsand_process_multimodal_async. MultiModalConfig.merge_mm_processor_kwargsoverlays inference values on startup values, so the request wins.cached_get_processor_without_dynamic_kwargsfilters only recognized processor-call keys.code_revisionis retained as a processor-construction kwarg.cached_processor_from_configpinsrevisionandtrust_remote_code, but forwards the remaining kwargs without reservingcode_revision.get_processorcallsAutoProcessor.from_pretrained(..., revision=revision, trust_remote_code=trust_remote_code, **kwargs).- Transformers
AutoProcessor.from_pretrainedusescode_revisionto retrieve and import the dynamic module throughget_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.
Suggested remediation
- Separate processor-construction arguments from untrusted processor-call arguments. An allowlist of supported request-time preprocessing controls is safest.
- Reject
code_revisionand other loader/source controls in requestmm_processor_kwargs, and passmodel_config.code_revisionexplicitly as the only permitted processor-code revision. - Add a regression test proving a request cannot change the loaded module revision while operator pins remain effective.
- Protect
/tokenizewith 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
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "vllm"
},
"ranges": [
{
"events": [
{
"introduced": "0.7.3"
},
{
"fixed": "0.31.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-114053"
],
"database_specific": {
"cwe_ids": [
"CWE-829",
"CWE-94"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-27T15:36:17Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Summary\n\nAn 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.\n\nThis 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.\n\nImporting 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.\n\n## Affected snapshot\n\n- Repository: [`vllm-project/vllm`](https://github.com/vllm-project/vllm)\n- Verified commit: [`570735520942b6428ae98f1eb442c6d88adae55e`](https://github.com/vllm-project/vllm/commit/570735520942b6428ae98f1eb442c6d88adae55e)\n- Verified with Transformers 5.15.0 and 5.16.1\n- Affected release range has not been bisected\n\n## Affected configuration\n\nThe vulnerable path exists when all of the following are true:\n\n1. The served model\u0027s processor uses dynamic `auto_map.AutoProcessor` code.\n2. The operator enabled `trust_remote_code`.\n3. The server can fetch the request-selected revision, or it is already cached.\n4. The attacker can create or otherwise control a revision in the served model repository. An example is a [Hugging Face community pull-request ref](https://huggingface.co/docs/hub/en/repositories-pull-requests-discussions#where-in-the-git-repo-are-changes-stored) when that repository permits them.\n5. A multimodal request reaches the processor path.\n\nThe default `trust_remote_code=False` configuration is not affected.\n\n## Attack surface\n\n`mm_processor_kwargs` is accepted directly by public request models:\n\n- [`TokenizeChatRequest.mm_processor_kwargs`](https://github.com/vllm-project/vllm/blob/570735520942b6428ae98f1eb442c6d88adae55e/vllm/entrypoints/serve/tokenize/protocol.py#L111-L114)\n- [`ChatCompletionRequest.mm_processor_kwargs`](https://github.com/vllm-project/vllm/blob/570735520942b6428ae98f1eb442c6d88adae55e/vllm/entrypoints/openai/chat_completion/protocol.py#L372-L375)\n\n`/tokenize` is particularly relevant because vLLM\u0027s authentication middleware guards only `/v1`, `/v2`, `/inference`, and `/cohere` prefixes:\n\n- [`AuthenticationMiddleware`](https://github.com/vllm-project/vllm/blob/570735520942b6428ae98f1eb442c6d88adae55e/vllm/entrypoints/serve/middleware/authenticate.py#L11-L62)\n\nConsequently, `/tokenize` remains unauthenticated even when `--api-key` is configured, unless an external proxy protects it. The vLLM [Security Guide](https://docs.vllm.ai/en/latest/usage/security/#unprotected-endpoints-no-api-key-required) documents `/tokenize` as an unprotected endpoint.\n\n## Root cause\n\nThe request value follows this path:\n\n1. [`OnlineRenderer.preprocess_chat`](https://github.com/vllm-project/vllm/blob/570735520942b6428ae98f1eb442c6d88adae55e/vllm/renderers/online_renderer.py#L406-L435) places request `mm_processor_kwargs` in prompt extras.\n2. Multimodal rendering forwards those kwargs into processor construction through [`MMProcessorInputs`](https://github.com/vllm-project/vllm/blob/570735520942b6428ae98f1eb442c6d88adae55e/vllm/renderers/base.py#L751-L760) and [`_process_multimodal_async`](https://github.com/vllm-project/vllm/blob/570735520942b6428ae98f1eb442c6d88adae55e/vllm/renderers/base.py#L831-L847).\n3. [`MultiModalConfig.merge_mm_processor_kwargs`](https://github.com/vllm-project/vllm/blob/570735520942b6428ae98f1eb442c6d88adae55e/vllm/config/multimodal.py#L506-L518) overlays inference values on startup values, so the request wins.\n4. [`cached_get_processor_without_dynamic_kwargs`](https://github.com/vllm-project/vllm/blob/570735520942b6428ae98f1eb442c6d88adae55e/vllm/transformers_utils/processor.py#L344-L375) filters only recognized processor-call keys. `code_revision` is retained as a processor-construction kwarg.\n5. [`cached_processor_from_config`](https://github.com/vllm-project/vllm/blob/570735520942b6428ae98f1eb442c6d88adae55e/vllm/transformers_utils/processor.py#L380-L390) pins `revision` and `trust_remote_code`, but forwards the remaining kwargs without reserving `code_revision`.\n6. [`get_processor`](https://github.com/vllm-project/vllm/blob/570735520942b6428ae98f1eb442c6d88adae55e/vllm/transformers_utils/processor.py#L205-L245) calls `AutoProcessor.from_pretrained(..., revision=revision, trust_remote_code=trust_remote_code, **kwargs)`.\n7. Transformers [`AutoProcessor.from_pretrained`](https://github.com/huggingface/transformers/blob/v5.15.0/src/transformers/models/auto/processing_auto.py#L294-L302) uses `code_revision` to retrieve and import the dynamic module through [`get_class_from_dynamic_module`](https://github.com/huggingface/transformers/blob/v5.15.0/src/transformers/dynamic_module_utils.py#L474-L575), then removes it before loading processor data. This is why code comes from the attacker revision while configuration/data remain operator-pinned.\n\nRequest-time processor arguments are not separated from processor-construction arguments, and `code_revision` is not reserved.\n\n## Suggested remediation\n\n1. Separate processor-construction arguments from untrusted processor-call arguments. An allowlist of supported request-time preprocessing controls is safest.\n2. Reject `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.\n3. Add a regression test proving a request cannot change the loaded module revision while operator pins remain effective.\n4. Protect `/tokenize` with the configured authentication policy as defense in depth.\n\nExpected 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.\n\nA patch for this was merged here: https://github.com/vllm-project/vllm/pull/58830",
"id": "GHSA-h3rc-6mm3-gc2m",
"modified": "2026-10-27T15:36:18Z",
"published": "2026-10-27T15:36:17Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/vllm-project/vllm/security/advisories/GHSA-h3rc-6mm3-gc2m"
},
{
"type": "WEB",
"url": "https://github.com/vllm-project/vllm/pull/58830"
},
{
"type": "WEB",
"url": "https://github.com/vllm-project/vllm/commit/31f2e70cd3e403aaa471fb7fe3d33a7207aaf3cc"
},
{
"type": "PACKAGE",
"url": "https://github.com/vllm-project/vllm"
},
{
"type": "WEB",
"url": "https://github.com/vllm-project/vllm/releases/tag/v0.31.0"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/cve-2026-114053"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/vllm-0.7.3-before-0.31.0-rce-via-mm-processor-kwargs-code-revision"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "vLLM: Request-controlled mm_processor_kwargs.code_revision allows remote code execution"
}
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
Loading timeline…
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.