{"schema":"threatline.record/2","record":{"id":"GHSA-vm9c-7j6g-c7mm","aliases":["GHSA-vm9c-7j6g-c7mm"],"summary":"RCE via SENet pretrained weights loaded over plaintext HTTP and unpickled without weights_only=True","details":"## Summary\r\nMONAI's SENet family fetches pretrained weights over **plaintext HTTP** and then deserializes them with `torch.hub.load_state_dict_from_url`, which defaults `weights_only=False` (full pickle) on all supported torch versions (verified on torch 2.13.0). `SEResNet50(pretrained=True)` (and the other SENet variants) therefore performs an unauthenticated, integrity-unchecked download from `http://data.lip6.fr/...` and unpickles it, so an on-path attacker who substitutes a crafted `.pth` achieves remote code execution at model-construction time. The sibling `torch.load` branch in the same function uses `weights_only=True`, but that branch is unreachable for built-in models — the reachable `load_state_dict_from_url` branch was never hardened.\r\n\r\nThis same \"pretrained loaders omit `weights_only=True`\" root cause is also present (over HTTPS transport) at `monai/networks/nets/efficientnet.py:796` (`model_zoo.load_url`), `monai/networks/nets/densenet.py:280` (`load_state_dict_from_url`), and `monai/networks/blocks/text_embedding.py:70` (`model_zoo.load_url`); those call-sites share the identical one-line fix and are listed here as additional affected locations. The SENet path is the most severe because its transport is plaintext HTTP (trivial MITM), whereas the others require compromising a TLS-secured distribution host/account.\r\n\r\n## Root Cause\r\n- `senet.py` `SE_NET_MODELS` (lines 41-46): all six pretrained URLs are `http://data.lip6.fr/...` (no TLS).\r\n- `_load_state_dict` (line ~285): `model_url = look_up_option(arch, SE_NET_MODELS, None)`. Every allowlisted value is a `str`, so `isinstance(model_url, dict)` is always False for built-in models → the reachable branch is `else` at line 307: `load_state_dict_from_url(model_url, progress=progress)`. The safe sibling at line 305 (`torch.load(..., weights_only=True)`) is dead for built-in models.\r\n- `torch.hub.load_state_dict_from_url` and `torch.utils.model_zoo.load_url` both forward their own default `weights_only=False` to `torch.load` → full unpickle. Confirmed via `inspect.signature` on torch 2.13.0.\r\n- No hash/integrity check is applied on these branches (`download_url`/`hash_val` not used).\r\n\r\n## Impact\r\nRemote code execution at model-construction time on the victim host for the SENet plaintext-HTTP path (on-path MITM). For the HTTPS call-sites (efficientnet/densenet/text_embedding), RCE requires distribution-host/account or registry compromise (supply-chain), or a shared-writable torch hub cache.\r\n\r\n## Proof of Concept\r\n1. Victim calls `SEResNet50(spatial_dims=2, pretrained=True)`.\r\n2. MONAI fetches `http://data.lip6.fr/.../se_resnet50-ce0d4300.pth` over plaintext HTTP.\r\n3. On-path attacker (rogue Wi-Fi/proxy, ARP/DNS spoof, BGP hijack, compromised mirror) returns a crafted `.pth` whose pickle payload runs on load.\r\n4. `load_state_dict_from_url` → `torch.load(bytes, weights_only=False)` → `__reduce__` RCE.\r\n\r\n## Attack Chain\r\n1. Entry: victim calls `SEResNet50(..., pretrained=True)` (documented public API). Guard: `look_up_option(arch, SE_NET_MODELS)` allowlist. Bypass proof: allowlist only maps name→URL; every allowlisted URL is plaintext HTTP.\r\n2. Transport: MONAI fetches `http://data.lip6.fr/.../se_resnet50-ce0d4300.pth`. Guard: none — no TLS, no hash. Bypass proof: scheme is `http://` at senet.py:42; on-path attacker returns crafted `.pth`.\r\n3. Sink: `load_state_dict_from_url` → `torch.load(bytes, weights_only=False)` → full unpickling → `__reduce__` RCE. Bypass proof: `inspect.signature(torch.hub.load_state_dict_from_url)` shows `weights_only: bool = False` on torch 2.13.0; sibling senet.py:305 uses `weights_only=True`, senet.py:307 does not.\r\n4. Impact: RCE at model-construction time.\r\n\r\n## Bypass Evidence\r\n- `python3 -c \"import inspect,torch.hub;print(inspect.signature(torch.hub.load_state_dict_from_url))\"` → `... weights_only: bool = False ...` on torch 2.13.0 (and defaults False on all supported torch versions).\r\n- `SE_NET_MODELS` URLs are `http://` (plaintext) at senet.py:41-46.\r\n- Asymmetry: senet.py:305 (dict branch, dead for built-in models) uses `weights_only=True`; senet.py:307 (reachable branch) does not.\r\n\r\n## Affected Versions\r\n`<= 1.6.0` (all sinks confirmed present at the `1.6.0` release tag via `git show 1.6.0:<file>`; no hardening commit on the reachable branch). Not covered by GHSA-6vm5-6jv9-rjpj, whose fix scope is direct `torch.load` in the CheckpointLoader path (affected `<= 1.5.0`); `load_state_dict_from_url` / `model_zoo.load_url` were never swept.\r\n\r\n## Suggested Fix\r\nPass `weights_only=True` to every pretrained-weights loader call (`load_state_dict_from_url` at senet.py:307 and densenet.py:280; `model_zoo.load_url` at efficientnet.py:796 and text_embedding.py:70), switch the SENet URLs to HTTPS, and route downloads through `download_url(..., hash_val=...)` to enforce integrity.\r\n\r\n---\r\nReported by **zx (Jace)** — GitHub: @manus-use","categories":["Unclassified"],"product":"monai","vendor":"","ecosystem":null,"affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/Project-MONAI/MONAI/security/advisories/GHSA-vm9c-7j6g-c7mm","source_modified_at":"2026-09-27T19:49:43Z","fetched_at":"2026-10-25T01:05:06.841276Z","package":{"ecosystem":"pip","name":"monai"},"range":"<= 1.6.0"}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/Project-MONAI/MONAI/security/advisories/GHSA-vm9c-7j6g-c7mm","source_modified_at":"2026-09-27T19:49:43Z","fetched_at":"2026-10-25T01:05:06.841276Z","package":{"ecosystem":"pip","name":"monai"},"version":"1.6.1"}],"cvss":7.5,"severity":"High","kev":{"listed":false},"epss":{"probability":null,"percentile":null,"score_date":null},"published_at":"2026-09-27T19:49:43Z","modified_at":"2026-09-27T19:49:43Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/Project-MONAI/MONAI/security/advisories/GHSA-vm9c-7j6g-c7mm","fetched_at":"2026-10-25T01:05:06.841276Z","source_modified_at":"2026-09-27T19:49:43Z"}],"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-09-27T19:49:43Z","content_hash":"2bdb481a0aefa232bf4994b73a13687039eae9907a8286f065aa222e166f7842"}}
