{"schema":"threatline.record/2","record":{"id":"GHSA-h3rc-6mm3-gc2m","aliases":["GHSA-h3rc-6mm3-gc2m"],"summary":"Request-controlled mm_processor_kwargs.code_revision allows remote code execution","details":"## Summary\r\n\r\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.\r\n\r\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.\r\n\r\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.\r\n\r\n## Affected snapshot\r\n\r\n- Repository: [`vllm-project/vllm`](https://github.com/vllm-project/vllm)\r\n- Verified commit: [`570735520942b6428ae98f1eb442c6d88adae55e`](https://github.com/vllm-project/vllm/commit/570735520942b6428ae98f1eb442c6d88adae55e)\r\n- Verified with Transformers 5.15.0 and 5.16.1\r\n- Affected release range has not been bisected\r\n\r\n## Affected configuration\r\n\r\nThe vulnerable path exists when all of the following are true:\r\n\r\n1. The served model's processor uses dynamic `auto_map.AutoProcessor` code.\r\n2. The operator enabled `trust_remote_code`.\r\n3. The server can fetch the request-selected revision, or it is already cached.\r\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.\r\n5. A multimodal request reaches the processor path.\r\n\r\nThe default `trust_remote_code=False` configuration is not affected.\r\n\r\n## Attack surface\r\n\r\n`mm_processor_kwargs` is accepted directly by public request models:\r\n\r\n- [`TokenizeChatRequest.mm_processor_kwargs`](https://github.com/vllm-project/vllm/blob/570735520942b6428ae98f1eb442c6d88adae55e/vllm/entrypoints/serve/tokenize/protocol.py#L111-L114)\r\n- [`ChatCompletionRequest.mm_processor_kwargs`](https://github.com/vllm-project/vllm/blob/570735520942b6428ae98f1eb442c6d88adae55e/vllm/entrypoints/openai/chat_completion/protocol.py#L372-L375)\r\n\r\n`/tokenize` is particularly relevant because vLLM's authentication middleware guards only `/v1`, `/v2`, `/inference`, and `/cohere` prefixes:\r\n\r\n- [`AuthenticationMiddleware`](https://github.com/vllm-project/vllm/blob/570735520942b6428ae98f1eb442c6d88adae55e/vllm/entrypoints/serve/middleware/authenticate.py#L11-L62)\r\n\r\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.\r\n\r\n## Root cause\r\n\r\nThe request value follows this path:\r\n\r\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.\r\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).\r\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.\r\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.\r\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`.\r\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)`.\r\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.\r\n\r\nRequest-time processor arguments are not separated from processor-construction arguments, and `code_revision` is not reserved.\r\n\r\n## Security impact\r\n\r\n- Confidentiality: High\r\n- Integrity: High\r\n- Availability: High\r\n- Execution context: vLLM API/renderer process\r\n\r\nSuggested CVSS v3.1: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H` = **9.8 Critical**\r\n\r\nThis Base score assumes the affected configuration described above. The [CVSS v3.1 specification](https://www.first.org/cvss/v3.1/specification-document#2-Base-Metrics) scores a vulnerability in that configuration; deployment-specific authentication or network controls belong in Environmental scoring. In an affected deployment, an unauthenticated network client can select and execute arbitrary processor Python inside the vLLM API/renderer process, compromising confidentiality, integrity, and availability. \r\n\r\n## Suggested remediation\r\n\r\n1. Separate processor-construction arguments from untrusted processor-call arguments. An allowlist of supported request-time preprocessing controls is safest.\r\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.\r\n3. Add a regression test proving a request cannot change the loaded module revision while operator pins remain effective.\r\n4. Protect `/tokenize` with the configured authentication policy as defense in depth.\r\n\r\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.\r\n\r\nA patch for this was merged here: https://github.com/vllm-project/vllm/pull/58830","categories":["Unclassified"],"product":"vllm","vendor":"","ecosystem":null,"affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/vllm-project/vllm/security/advisories/GHSA-h3rc-6mm3-gc2m","source_modified_at":"2026-10-06T07:06:53Z","fetched_at":"2026-10-25T21:40:15.971031Z","package":{"ecosystem":"pip","name":"vllm"},"range":">= 0.7.3, < 0.31.0"}],"fixed_versions":[],"cvss":8.1,"severity":"High","kev":{"listed":false},"epss":{"probability":null,"percentile":null,"score_date":null},"published_at":"2026-10-06T07:06:53Z","modified_at":"2026-10-06T07:06:53Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/vllm-project/vllm/security/advisories/GHSA-h3rc-6mm3-gc2m","fetched_at":"2026-10-25T21:40:15.971031Z","source_modified_at":"2026-10-06T07:06:53Z"}],"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:06:53Z","content_hash":"1877e579bd7e557bdad480f703a3283387e85ffc225b2a57a8e4434f26a55d31"}}
