{"id":"CVE-2026-41523","aliases":["EUVD-2026-38406","GHSA-q8gq-377p-jq3r","PYSEC-2026-2300"],"status":"published","title":"vLLM: Security Check Bypass via assert Statement in Activation Function Loading Allows Arbitrary Code Execution","description":"vLLM is an inference and serving engine for large language models (LLMs). Prior to 0.22.0, an 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). This vulnerability is fixed in 0.22.0.","severity":{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-10","score":0.00913,"percentile":0.6039,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-617","CWE-94"],"published":"2026-06-16T17:34:49Z","modified":"2026-10-28T02:30:33Z","fixes":[{"ecosystem":"PyPI","package":"vllm","fixed_in":["0.22.0"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"PyPI","package":"vllm","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.22.0"}]}]},{"source":"osv","ecosystem":"PyPI","package":"vllm","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.22.0"}]}],"versions":["0.0.1","0.1.0","0.1.1","0.1.2","0.1.3","0.1.4","0.1.5","0.1.6","0.1.7","0.10.0","0.10.1","0.10.1.1","0.10.2","0.11.0","0.11.1","0.11.2","0.12.0","0.13.0","0.14.0","0.14.1","0.15.0","0.15.1","0.16.0","0.17.0","0.17.1","0.18.0","0.18.1","0.19.0","0.19.1","0.2.0","0.2.1","0.2.1.post1","0.2.2","0.2.3","0.2.4","0.2.5","0.2.6","0.2.7","0.20.0","0.20.1","0.20.2","0.21.0","0.3.0","0.3.1","0.3.2","0.3.3","0.4.0","0.4.0.post1","0.4.1","0.4.2","0.4.3","0.5.0","0.5.0.post1","0.5.1","0.5.2","0.5.3","0.5.3.post1","0.5.4","0.5.5","0.6.0","0.6.1","0.6.1.post1","0.6.1.post2","0.6.2","0.6.3","0.6.3.post1","0.6.4","0.6.4.post1","0.6.5","0.6.6","0.6.6.post1","0.7.0","0.7.1","0.7.2","0.7.3","0.8.0","0.8.1","0.8.2","0.8.3","0.8.4","0.8.5","0.8.5.post1","0.9.0","0.9.0.1","0.9.1","0.9.2"]},{"source":"osv","ecosystem":"PyPI","package":"vllm","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.22.0"}]}],"versions":["0.0.1","0.1.0","0.1.1","0.1.2","0.1.3","0.1.4","0.1.5","0.1.6","0.1.7","0.10.0","0.10.1","0.10.1.1","0.10.2","0.11.0","0.11.1","0.11.2","0.12.0","0.13.0","0.14.0","0.14.1","0.15.0","0.15.1","0.16.0","0.17.0","0.17.1","0.18.0","0.18.1","0.19.0","0.19.1","0.2.0","0.2.1","0.2.1.post1","0.2.2","0.2.3","0.2.4","0.2.5","0.2.6","0.2.7","0.20.0","0.20.1","0.20.2","0.21.0","0.3.0","0.3.1","0.3.2","0.3.3","0.4.0","0.4.0.post1","0.4.1","0.4.2","0.4.3","0.5.0","0.5.0.post1","0.5.1","0.5.2","0.5.3","0.5.3.post1","0.5.4","0.5.5","0.6.0","0.6.1","0.6.1.post1","0.6.1.post2","0.6.2","0.6.3","0.6.3.post1","0.6.4","0.6.4.post1","0.6.5","0.6.6","0.6.6.post1","0.7.0","0.7.1","0.7.2","0.7.3","0.8.0","0.8.1","0.8.2","0.8.3","0.8.4","0.8.5","0.8.5.post1","0.9.0","0.9.0.1","0.9.1","0.9.2"]}],"products":[{"vendor":"red hat","product":"red hat ai inference server"},{"vendor":"red hat","product":"red hat ai inference server 3.2"},{"vendor":"red hat","product":"red hat ai inference server 3.3"},{"vendor":"red hat","product":"red hat ai inference server 3.4"},{"vendor":"red hat","product":"red hat enterprise linux ai 3.3"},{"vendor":"red hat","product":"red hat enterprise linux ai 3.4"},{"vendor":"red hat","product":"red hat openshift ai (rhoai)"},{"vendor":"vllm","product":"vllm"},{"vendor":"vllm-project","product":"vllm"}],"references":[{"url":"https://github.com/vllm-project/vllm/security/advisories/GHSA-q8gq-377p-jq3r","tags":["x_refsource_CONFIRM","Exploit","Third Party Advisory","advisory","web","evidence"]},{"url":"https://github.com/vllm-project/vllm/commit/b3c7ffcab82c2439726f8cb213800f6f38c023d3","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://huntr.com/bounties/dcb05b04-e625-41e7-adbc-bbae0cc2d64c","tags":["x_refsource_MISC","Third Party Advisory","web","advisory"]},{"url":"https://access.redhat.com/security/cve/CVE-2026-41523","tags":["vdb-entry","x_refsource_REDHAT","advisory","web"]},{"url":"https://bugzilla.redhat.com/show_bug.cgi?id=2491582","tags":["issue-tracking","x_refsource_REDHAT","report","web"]},{"url":"https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-41523.json","tags":["x_sadp-csaf-vex","web"]},{"url":"https://access.redhat.com/errata/RHSA-2026:61627","tags":["vendor-advisory","x_refsource_REDHAT","advisory","web"]},{"url":"https://access.redhat.com/errata/RHSA-2026:36005","tags":["vendor-advisory","x_refsource_REDHAT","advisory","web"]},{"url":"https://access.redhat.com/errata/RHSA-2026:61629","tags":["vendor-advisory","x_refsource_REDHAT","advisory","web"]},{"url":"https://access.redhat.com/errata/RHSA-2026:36006","tags":["vendor-advisory","x_refsource_REDHAT","advisory","web"]},{"url":"https://access.redhat.com/errata/RHSA-2026:59138","tags":["vendor-advisory","x_refsource_REDHAT","advisory","web"]},{"url":"https://access.redhat.com/errata/RHSA-2026:59139","tags":["vendor-advisory","x_refsource_REDHAT","advisory","web"]},{"url":"https://access.redhat.com/errata/RHSA-2026:57380","tags":["vendor-advisory","x_refsource_REDHAT","advisory","web"]},{"url":"https://access.redhat.com/errata/RHSA-2026:57389","tags":["vendor-advisory","x_refsource_REDHAT","advisory","web"]},{"url":"https://access.redhat.com/errata/RHSA-2026:57390","tags":["vendor-advisory","x_refsource_REDHAT","advisory","web"]},{"url":"https://access.redhat.com/errata/RHSA-2026:57387","tags":["vendor-advisory","x_refsource_REDHAT","advisory","web"]},{"url":"https://access.redhat.com/errata/RHSA-2026:62336","tags":["vendor-advisory","x_refsource_REDHAT","advisory","web"]},{"url":"https://access.redhat.com/errata/RHSA-2026:62335","tags":["vendor-advisory","x_refsource_REDHAT","advisory","web"]},{"url":"https://access.redhat.com/errata/RHSA-2026:59151","tags":["vendor-advisory","x_refsource_REDHAT","advisory","web"]},{"url":"https://access.redhat.com/errata/RHSA-2026:59144","tags":["vendor-advisory","x_refsource_REDHAT","advisory","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41523","tags":["advisory"]},{"url":"https://github.com/pypa/advisory-database/tree/main/vulns/vllm/PYSEC-2026-2300.yaml","tags":["web"]},{"url":"https://github.com/advisories/GHSA-q8gq-377p-jq3r"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/41xxx/CVE-2026-41523.json","tags":["advisory"]},{"url":"https://github.com/vllm-project/vllm","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-41523","title":"vLLM: Security Check Bypass via assert Statement in Activation Function Loading Allows Arbitrary Code Execution","description":"vLLM is an inference and serving engine for large language models (LLMs). Prior to 0.22.0, an 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). This vulnerability is fixed in 0.22.0.","status":"published","published":"2026-06-22T22:18:14.494Z","modified":"2026-09-04T12:04:58.778Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high","assessor":"cna"},{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high","assessor":"adp"}],"cwes":["CWE-94","CWE-617","CWE-617"],"updated_at":"2026-11-02T13:41:08.498858Z"}],"euvd":[{"id":"EUVD-2026-38406","description":"vLLM is an inference and serving engine for large language models (LLMs). Prior to 0.22.0, an 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). This vulnerability is fixed in 0.22.0.","status":"published","published":"2026-06-22T22:18:14Z","modified":"2026-09-04T12:04:58Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high"}],"updated_at":"2026-11-02T18:01:12.73639Z"}],"ghsa":[{"id":"GHSA-q8gq-377p-jq3r","title":"vLLM: Security Check Bypass via assert Statement in Activation Function Loading Allows Arbitrary Code Execution","description":"### 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) -\u003e 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","status":"published","published":"2026-06-16T17:34:49Z","modified":"2026-09-03T15:31:59Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-94","CWE-617"],"updated_at":"2026-11-02T14:41:11.621873Z"}],"nvd":[{"id":"CVE-2026-41523","description":"vLLM is an inference and serving engine for large language models (LLMs). Prior to 0.22.0, an 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). This vulnerability is fixed in 0.22.0.","status":"published","published":"2026-06-22T23:16:30.2Z","modified":"2026-10-25T23:10:00.167Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high","assessor":"secondary"},{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high","assessor":"secondary"}],"cwes":["CWE-94","CWE-617"],"updated_at":"2026-11-02T14:12:25.288279Z"}],"osv":[{"id":"CVE-2026-41523","title":"vLLM: Security Check Bypass via assert Statement in Activation Function Loading Allows Arbitrary Code Execution","description":"vLLM is an inference and serving engine for large language models (LLMs). Prior to 0.22.0, an 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). This vulnerability is fixed in 0.22.0.","status":"published","published":"2026-06-22T22:18:14.494Z","modified":"2026-10-28T02:30:33.089544597Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-617","CWE-94"],"updated_at":"2026-11-02T15:45:03.764807Z"},{"id":"GHSA-q8gq-377p-jq3r","title":"vLLM: Security Check Bypass via assert Statement in Activation Function Loading Allows Arbitrary Code Execution","description":"### 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) -\u003e 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","status":"published","published":"2026-06-16T17:34:49Z","modified":"2026-09-10T03:50:50.172404895Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-617","CWE-94"],"updated_at":"2026-11-02T15:46:54.40888Z"},{"id":"PYSEC-2026-2300","description":"vLLM is an inference and serving engine for large language models (LLMs). Prior to 0.22.0, an 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). This vulnerability is fixed in 0.22.0.","status":"published","published":"2026-06-22T23:16:30.2Z","modified":"2026-07-13T07:15:12.552873453Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high"}],"updated_at":"2026-11-02T15:52:55.537808Z"}]}}
