# vLLM: Request-controlled mm_processor_kwargs.code_revision allows remote code execution

Unauthenticated /tokenize request sets mm_processor_kwargs.code_revision, making vLLM import attacker-revision processor code from the model repo under trust_remote_code.

- Payout: Research
- Severity: high
- Program: vLLM
- Found by (vendor credit): adithyan-ak, DarkLight1337
- Found by: adithyan-ak
- Disclosed: 2026-10-27
- CVE: CVE-2026-114053
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-h3rc-6mm3-gc2m
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-h3rc-6mm3-gc2m
- Tags: area:ai domain:ai domain:api impact:rce kind:research platform:ghsa sev:high tech:llm tech:python technique:chained technique:source-review vuln:rce

**Target:** vLLM OpenAI-compatible server /tokenize and chat completion endpoints
**Root cause:** Request-supplied mm_processor_kwargs are merged over startup processor kwargs and forwarded to AutoProcessor.from_pretrained without reserving code_revision, so the client picks which dynamic auto_map module revision Transformers imports.
**Steps:**
1. Serve a model whose processor uses auto_map.AutoProcessor dynamic code with --trust-remote-code enabled.
2. Ensure the model repo permits community PR refs (or otherwise control a revision) so an attacker revision exists.
3. Send an unauthenticated request to `/tokenize` (or chat completions) with `mm_processor_kwargs` containing `code_revision` pointing at the attacker revision.
4. vLLM merges the request kwargs over startup values and passes them to `AutoProcessor.from_pretrained(..., revision=<pinned>, trust_remote_code=True, code_revision=<attacker>)`.
5. Transformers fetches and imports the dynamic module from the attacker revision via `get_class_from_dynamic_module`, executing import-time code in the API/renderer process.
**How found:** Code review of the request-to-processor path: noticed mm_processor_kwargs from public request models flows into processor construction, that merge_mm_processor_kwargs lets request values win, and that cached_processor_from_config pins revision and trust_remote_code but does not reserve code_revision before forwarding to AutoProcessor.from_pretrained.
**Exploitation:** Attacker needs a controllable revision in the served model repo (e.g. a Hugging Face community PR ref) and a multimodal request path. The request's code_revision overrides only the processor code revision while model/data revision stays operator-pinned; importing the module runs arbitrary code (PoC uses an import-time filesystem write). /tokenize is unauthenticated even with --api-key, so no credentials are required.
**Escalation:** Unauthenticated /tokenize endpoint bypasses the API-key middleware (which only guards /v1, /v2, /inference, /cohere), turning a request-parameter flaw into unauthenticated RCE in the serving process.
**Insight:** When a framework forwards user kwargs into a loader like from_pretrained, enumerate the loader's own control parameters (revision, code_revision, trust_remote_code, subfolder, token) and check which are reserved; any unreserved one is a source-selection primitive. Also check auth middleware prefix lists for endpoints outside the guarded set.

