MONAI Deserialization, Injection, and RCE Flaws
2026-09-27
Deserialization of untrusted data in MONAI's auto3dseg utility (monai/auto3dseg/utils.py) allows arbitrary code execution when algo_from_pickle() is called on an attacker-supplied .pkl file: the function reads the raw file bytes and hands them to pickle.loads() without any source or content validation, so any object defining __reduce__ runs in the victim application's context. Exploitation is conditional rather than remote-against-a-service: an attacker must first deliver a malicious pickle (model exchange, shared storage, or a pipeline input) and the victim's code must invoke this specific function, and per the authoritative assessment the vector is local with user interaction required (CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H) rather than unauthenticated network exploitation. A working proof-of-concept is documented in the upstream GitHub advisory GHSA-89gg-p5r5-q6r4 (publicly available exploit code exists), but there is no confirmed active exploitation (CISA KEV).
OS command injection in MONAI's nnUNetV2Runner (monai.apps.nnunet.nnunetv2_runner) allows arbitrary command execution with the privileges of the user running an nnU-Net training or validation job, because values such as dataset_name_or_id from a YAML config - or from CLI/kwargs arguments - are concatenated into a command string and passed to subprocess with shell=True without quoting or validation. All MONAI releases before 1.6.0 are affected; exploitation is not network-facing and requires the victim to load an attacker-supplied configuration file and then launch a job such as train_single_model(), so the real-world risk is config-trust dependent rather than remotely triggerable. Publicly available exploit code exists (a Windows-verified proof of concept is included in the GHSA advisory), no authentication is required in the assessed vector (PR:N), and no confirmed active exploitation (CISA KEV) has been reported at time of analysis. Vendor-released patch: MONAI 1.6.0.
Arbitrary code execution in MONAI versions prior to 1.6.0 occurs when a crafted .npy or .npz file is loaded through the NumpyReader class, which hardcodes numpy.load with allow_pickle=True. An unauthenticated attacker who can place a malicious file on a path the victim opens can trigger pickle deserialization, leading to full compromise of confidentiality, integrity, and availability. Exploitation requires user interaction (the victim must load the file) and the attack vector is local; no public exploit code has been identified at time of analysis.
Local code execution in MONAI 1.6.0 and all released versions allows an authenticated low-privileged local attacker to run arbitrary code as another user by writing a malicious pickle file to a shared or world-writable MONAI cache directory (e.g., /tmp/monai_cache, HPC scratch, ~/.cache/monai). The victim must subsequently run a PersistentDataset pipeline that caches MetaTensors (the default in MONAI >= 1.0), which forces torch.load(weights_only=False) and pickle.loads on the poisoned file. No vendor-released patch identified at time of analysis; no public exploit identified at time of analysis.
MONAI through 1.6.0 will execute arbitrary code in the victim's process when it loads an attacker-supplied bundle, because the bundle configuration engine resolves '_target_' values to any importable callable without an allow list and passes '$' expressions straight to Python's eval(). An attacker who publishes or shares a crafted bundle achieves code execution as soon as an operator calls monai.bundle.load() or monai.bundle.run() on it; no credentials are required against the victim (PR:N), but the attack does depend on user interaction (UI:R) since the operator must obtain and load an untrusted bundle, and the payload runs with the privileges of the loading process. No public exploit code or confirmed in-the-wild exploitation was identified at time of analysis; the primary exposure is to environments that pull third-party or community-contributed MONAI bundles rather than first-party trusted ones.
Deserialization of attacker-controlled pickle data in MONAI's Auto3DSeg module (monai/auto3dseg/utils.py) lets code run inside any process that calls algo_from_pickle() on a file the attacker can supply or substitute, with full read/write/execute impact on that process and its data. Versions before 1.6.0 are affected (pip package monai < 1.6.0, CPE cpe:2.3:a:project-monai:monai); the vulnerable pickle.loads() at line 321 fires before any isinstance or key checks, so no special configuration flag is needed to reach the sink. The exposure is conditional rather than remote: the vector is local (AV:L) with passive user interaction (UI:P) - a victim, typically a medical-imaging or ML pipeline exchanging algorithm bundles or model checkpoints, must load the crafted .pkl file, and no authentication is required on the loading side (PR:N) - scored 8.5. There is no evidence of confirmed active exploitation (no CISA KEV entry), but publicly available exploit code exists: the upstream advisory ships a working proof-of-concept, and users who upgraded to v1.5.2 believing GHSA-89gg-p5r5-q6r4 fixed this remain fully vulnerable because that earlier patch was never actually implemented in the code.
MONAI through 1.6.0 lets a user who can supply or tamper with a bundle's metadata achieve code execution by abusing an eval()-based sandbox in _get_fake_spatial_shape() (monai/bundle/scripts.py). The vulnerable function screens shape expressions with a helper that walks the AST and only rejects ast.Name nodes outside the 'p'/'n' allowlist, so payloads assembled purely from constants and attribute, subscript, or call nodes - such as "(1).__class__.__bases__[0].__subclasses__()" - pass validation and then reach eval(), enabling object-introspection chains that escape to arbitrary code execution. The path is reachable through the non-default bundle 'verify_net_in_out' CLI verification flow (_get_real_input_data / verify_net_in_out), so exploitation is limited to authenticated local users (CVSS:3.1/AV:L/AC:H/PR:L/UI:N, CVA:H) who run that verification on an untrusted or modified bundle; default MONAI workflows that never verify untrusted bundles are not exposed, and no public exploit code was identified at time of analysis.