{"id":"CVE-2026-41523","aliases":["GHSA-q8gq-377p-jq3r","PYSEC-2026-2300"],"url":"https://o3.security/vulnerability/CVE-2026-41523","summary":"vLLM: Security Check Bypass via assert Statement in Activation Function Loading Allows Arbitrary Code Execution","details":"### Summary\n\nAn `assert`-based security check in vLLM's activation function loading allows any unauthenticated attacker to achieve arbitrary code execution on the server by publishing a malicious HuggingFace model, when vLLM runs in Python optimized mode (`python -O` or `PYTHONOPTIMIZE=1`).\n\n### Details\n\nvLLM uses an `assert` statement at [`vllm/model_executor/layers/pooler/activations.py:48`](https://github.com/vllm-project/vllm/blob/main/vllm/model_executor/layers/pooler/activations.py#L48) as its sole security control to restrict which activation functions can be loaded from a HuggingFace model's `config.json`:\n\n```python\n# vllm/model_executor/layers/pooler/activations.py:35-53\nfunction_name: str | None = None\nif (\n    hasattr(config, \"sentence_transformers\")\n    and \"activation_fn\" in config.sentence_transformers\n):\n    function_name = config.sentence_transformers[\"activation_fn\"]\nelif (\n    hasattr(config, \"sbert_ce_default_activation_function\")\n    and config.sbert_ce_default_activation_function is not None\n):\n    function_name = config.sbert_ce_default_activation_function\n\nif function_name is not None:\n    assert function_name.startswith(\"torch.nn.modules.\"), (\n        \"Loading of activation functions is restricted to \"\n        \"torch.nn.modules for security reasons\"\n    )\n    fn = resolve_obj_by_qualname(function_name)()\n```\n\nPython's `assert` statements are stripped at compile time when running in optimized mode (`python -O` or `PYTHONOPTIMIZE=1`). When the assert is absent, the attacker-controlled `function_name` from the model's `config.json` is passed directly to [`resolve_obj_by_qualname()`](https://github.com/vllm-project/vllm/blob/main/vllm/utils/import_utils.py#L106) — an unrestricted import gadget:\n\n```python\ndef resolve_obj_by_qualname(qualname: str) -> Any:\n    module_name, obj_name = qualname.rsplit(\".\", 1)\n    module = importlib.import_module(module_name)\n    return getattr(module, obj_name)\n```\n\nThis is the same vulnerability class as **CVE-2017-1000433** (pysaml2 assert-based auth bypass), flagged by Bandit B101 and Ruff S101, and the reason Django proactively replaced all assert-based security checks (ticket #32508).\n\n**Attacker-controlled input sources:**\n- `config.sentence_transformers[\"activation_fn\"]` (line 40)\n- `config.sbert_ce_default_activation_function` (line 45)\n\n**Affected call sites** — `get_act_fn()` is called via `resolve_classifier_act_fn()` from:\n- `vllm/model_executor/layers/pooler/seqwise/poolers.py:122` — SequencePooler\n- `vllm/model_executor/layers/pooler/tokwise/poolers.py:130` — TokenPooler\n\n**Broader systemic risk:** `resolve_obj_by_qualname` is called from ~20 locations across the codebase with no validation of its own. Any future caller feeding user-controlled input to it without validation creates the same vulnerability class.\n\n**Suggested fix:** Replace the `assert` with an explicit conditional raise:\n\n```python\nif not function_name.startswith(\"torch.nn.modules.\"):\n    raise ValueError(\n        \"Loading of activation functions is restricted to \"\n        \"torch.nn.modules for security reasons\"\n    )\n```\n\n### Impact\n\n**Arbitrary code execution.** A malicious model author publishes a HuggingFace model with a crafted `config.json`. When a victim loads this model with vLLM running under `python -O` or `PYTHONOPTIMIZE=1`, arbitrary code executes during model initialization with the privileges of the vLLM process.\n\nThe attack requires:\n1. Victim loads a malicious model from HuggingFace (user interaction)\n2. vLLM runs under `python -O` or `PYTHONOPTIMIZE=1` (documented in production use)\n3. Model uses a cross-encoder architecture (e.g. BERT or RoBERTa with sequence classification)\n\n**Coordinated disclosure note:** This vulnerability was also reported via huntr.com on April 2, 2026 (https://huntr.com/bounties/dcb05b04-e625-41e7-adbc-bbae0cc2d64c). A GitHub Security Advisory was also filed because it is vLLM's stated preferred disclosure channel per SECURITY.md.\n\n### Fix\n\nA fix for this was introduced in this commit: https://github.com/vllm-project/vllm/commit/b3c7ffcab82c2439726f8cb213800f6f38c023d3","published":"2026-06-22T22:18:14.494Z","modified":"2026-09-06T03:30:48.234493896Z","cvss":{"score":7.5,"severity":"HIGH","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H"},"epss":{"score":0.00913,"percentile":0.58401,"asOf":"2026-09-17"},"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"PyPI","name":"vllm","fixedVersion":"0.22.0"}],"fix":{"url":"https://github.com/vllm-project/vllm/commit/b3c7ffcab82c2439726f8cb213800f6f38c023d3","label":"vllm-project/vllm@b3c7ffc"},"references":[{"type":"WEB","url":"https://huntr.com/bounties/dcb05b04-e625-41e7-adbc-bbae0cc2d64c"},{"type":"WEB","url":"https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-41523.json"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:36005"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:36006"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:57380"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:57387"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:57389"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:57390"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:59138"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:59139"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:59144"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:59151"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:61627"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:61629"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:62335"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:62336"},{"type":"ADVISORY","url":"https://access.redhat.com/security/cve/CVE-2026-41523"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/41xxx/CVE-2026-41523.json"},{"type":"ADVISORY","url":"https://github.com/vllm-project/vllm/security/advisories/GHSA-q8gq-377p-jq3r"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41523"},{"type":"REPORT","url":"https://bugzilla.redhat.com/show_bug.cgi?id=2491582"},{"type":"FIX","url":"https://github.com/vllm-project/vllm/commit/b3c7ffcab82c2439726f8cb213800f6f38c023d3"},{"type":"PACKAGE","url":"https://github.com/vllm-project/vllm"},{"type":"WEB","url":"https://github.com/pypa/advisory-database/tree/main/vulns/vllm/PYSEC-2026-2300.yaml"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-09-06T03:30:48.234493896Z"}}