Skip to content

vLLM Will Import Your Attacker’s Processor If You Ask Nicely (CVE-2026-114053)

CVE-2026-114053: vLLM code_revision RCE via /tokenize

vLLM Will Import Your Attacker’s Processor If You Ask Nicely (CVE-2026-114053)

you told the model to trust remote code. so it did. then a multimodal request whispered mm_processor_kwargs.code_revision, and the unauthenticated /tokenize endpoint fetched a different Python revision of the same Hugging Face repo and imported it. operator-pinned weights stayed put. the code that runs did not. CVE-2026-114053. GHSA-h3rc-6mm3-gc2m. fixed in vLLM 0.31.0. the joke writes itself, but we will anyway.

Lab only. screenshots below are an offline recreation of the vulnerable loader path from the advisory. no GPU, no Hub push, no real production vLLM. do not spray code_revision probes at random inference endpoints. authorized lab and detection engineering only.

what landed

  • CVE-2026-114053 / GHSA-h3rc-6mm3-gc2m: request-controlled mm_processor_kwargs.code_revision reaches AutoProcessor.from_pretrained.
  • Affected: vLLM >= 0.7.3 and < 0.31.0.
  • Patched: >= 0.31.0 (PR #58830).
  • CVSS: CVE.org lists 9.2 (CVSS 4.0). Advisory suggests 9.8 in the affected config.
  • CWE: CWE-94 (code injection), CWE-829 (untrusted control sphere).

the prerequisites (all of them)

this is not “every vLLM on the internet is owned.” the advisory is specific. you need the whole set:

  1. served model processor uses dynamic auto_map.AutoProcessor code.
  2. operator enabled trust_remote_code (the default is False and is safe).
  3. server can fetch the request-selected revision, or it is already cached.
  4. attacker can create or control a revision in the same model repository (Hugging Face community PR refs are the textbook example).
  5. a multimodal request reaches the processor path.

miss any one and the chain breaks. hit all five and the API process runs their Python.

Kali terminal showing a lab tokenize request JSON with mm_processor_kwargs.code_revision set to refs/pr/9.
Step 1: the request. code_revision looks like a harmless processor knob. it is not.

step 1: the request surface

mm_processor_kwargs is accepted on TokenizeChatRequest and ChatCompletionRequest. /tokenize matters because vLLM’s AuthenticationMiddleware only guards /v1, /v2, /inference, and /cohere. so even with --api-key set, /tokenize stays open unless something in front of it cares. the vLLM Security Guide already documents that. documenting a hole is not the same as closing it.

{
  "messages": [{"role": "user", "content": [
    {"type": "text", "text": "describe"},
    {"type": "image_url", "image_url": {"url": "data:image/png;base64,AA=="}}
  ]}],
  "mm_processor_kwargs": {"code_revision": "refs/pr/9"}
}
Kali terminal lab loader showing AutoProcessor.from_pretrained with operator revision main and request code_revision refs/pr/9, then importing attacker processing_evil.py.
Step 2: loader path. data revision stays on main. code_revision picks the attacker’s module.

step 2: why the loader betrays you

the request value walks a polite little hallway:

  1. OnlineRenderer.preprocess_chat stuffs request mm_processor_kwargs into prompt extras.
  2. multimodal rendering forwards them into processor construction.
  3. MultiModalConfig.merge_mm_processor_kwargs overlays inference values on startup values. request wins.
  4. cached_get_processor_without_dynamic_kwargs filters recognized call keys. code_revision is a construction key, so it survives.
  5. cached_processor_from_config pins revision and trust_remote_code, then forwards the rest.
  6. get_processor calls AutoProcessor.from_pretrained(..., revision=revision, trust_remote_code=..., **kwargs).
  7. Transformers uses code_revision for get_class_from_dynamic_module, then drops it before loading processor data.

result: configuration and weights stay on the operator pin. the Python that executes comes from the attacker revision. importing a module is arbitrary code execution in the API/renderer process. the advisory PoC proves it with an import-time filesystem write. ours does the same offline.

Kali terminal showing the /tmp/vllm-sloth-rce.marker file written by the attacker processor at import time.
Step 3: marker on disk. in production this is a reverse shell, a credential grab, or a quiet implant.

step 3: impact in one breath

confidentiality, integrity, availability: all high. execution context is the vLLM API process, which usually sees prompts, keys, GPU hosts, and whatever else you glued to the inference box. “but we only let employees hit it” is cute until someone finds the tokenize URL on a shared cluster with trust_remote_code still on from last quarter’s demo.

why defenders care

  • unauthenticated by default on /tokenize: API key theater does not cover it.
  • trust_remote_code is a footgun: operators enable it for convenience, then forget the request path can pick a different revision.
  • same-repo PR refs: you do not need to hijack the whole model. a community PR on a permissive repo is enough.
  • data pin is not a code pin: pinning revision for weights does not pin the processor module when code_revision is attacker-set.

controls that are not theater

  1. upgrade to vLLM >= 0.31.0. the patch reserves/rejects request code_revision.
  2. leave trust_remote_code=False unless you have a written reason and a review process for every dynamic module.
  3. put auth in front of /tokenize (and every other non-/v1 surface). do not trust the built-in middleware map alone.
  4. pin both data revision and processor code_revision at server start. never accept loader keys from clients.
  5. network: inference hosts are crown jewels. do not put them on the same VLAN as the snack machine.
  6. detect: alert on unexpected code_revision / Hub fetches from the vLLM process; alert on the API process writing outside its model cache.
honesty check: our screenshots are a faithful offline recreation of the advisory’s loader path, not a full vLLM 0.30 install with a Hub PR. the control flow matches GHSA-h3rc-6mm3-gc2m. if your threat model requires a live GPU box, build one in a disposable lab and keep it offline.

sloth take

you asked the framework to trust remote code. a client asked it which remote code. it said yes to both. patch to 0.31.0, kill trust_remote_code unless you enjoy living like that, and stop leaving /tokenize on the porch with a bowl of candy.

sources