Apr 7, 2026·6 min read·2 visits
MONAI versions prior to 1.5.2 are vulnerable to Remote Code Execution via insecure pickle deserialization in the `algo_from_pickle` function. Supplying a maliciously crafted `.pkl` file results in arbitrary system command execution.
The Medical Open Network for AI (MONAI) framework contains a critical remote code execution vulnerability in the Auto3DSeg utility. The `algo_from_pickle` function insecurely deserializes untrusted data using Python's `pickle` module, allowing an attacker who can supply a crafted `.pkl` file to execute arbitrary commands within the context of the application process. This vulnerability affects all versions of the MONAI PyPI package prior to 1.5.2.
The Medical Open Network for AI (MONAI) framework exposes an insecure deserialization vulnerability (CWE-502) in its Auto3DSeg utility module. The vulnerability resides specifically within the monai/auto3dseg/utils.py file, which contains the algo_from_pickle function. This function is designed to load algorithm configurations or state representations from serialized Python pickle files.
The core issue stems from the application accepting serialized data from potentially untrusted sources and passing it directly to the pickle.loads() function without prior validation or cryptographic signature verification. Python's pickle module is explicitly documented as unsafe for handling untrusted data, as the deserialization process allows for the execution of arbitrary code via specifically crafted object reconstruction instructions.
Successful exploitation requires the attacker to supply a malicious .pkl file to the system and trigger a workflow that invokes the algo_from_pickle function. While the CVSS attack complexity is marked as high due to the required file delivery mechanism, the resulting impact is total compromise of the application environment, yielding arbitrary remote code execution.
The root cause of this vulnerability is the implementation of an unsafe deserialization sink operating on user-controllable file inputs. The algo_from_pickle function reads the raw bytes from a specified file path and immediately supplies them to the pickle.loads() method.
Python's pickle protocol defines a custom serialization format that includes opcodes for reconstructing Python object hierarchies. When the pickle.loads() function encounters an object defining the __reduce__ method, it interprets the returned tuple as a callable and its arguments, executing the callable to construct the object. An attacker leverages this specification by constructing a class where the __reduce__ method returns a system command execution function, such as os.system or subprocess.call.
The MONAI codebase lacks any defensive mechanisms around this operation. There is no implementation of a restricted Unpickler class to limit the modules and functions that can be dynamically loaded, nor is there a cryptographic integrity check (such as HMAC) to ensure the .pkl file originated from a trusted source. Consequently, the deserialization engine blindly executes the attacker's payload during the parsing phase, before the application logic even interacts with the reconstructed object.
Analysis of the monai/auto3dseg/utils.py module reveals the direct path from file input to code execution. The algo_from_pickle function accepts a pkl_filename string, opens the file in binary read mode, and extracts the contents.
def algo_from_pickle(pkl_filename: str, template_path: PathLike | None = None, **kwargs: Any) -> Any:
# ... configuration and path handling ...
with open(pkl_filename, "rb") as f_pi:
data_bytes = f_pi.read()
# Vulnerability: Raw bytes are passed to pickle.loads without validation
data = pickle.loads(data_bytes)
# ... further processing of the data object ...The vulnerability manifests exactly at the pickle.loads(data_bytes) call. Because the data_bytes variable contains the raw byte stream from the file system, any manipulation of the file at pkl_filename directly influences the deserialization engine.
Remediation for this class of vulnerability typically requires replacing pickle with a safer serialization format, such as JSON or safetensors, which do not support executable code reconstruction. In contexts where complex Python object states must be saved, developers must implement a custom pickle.Unpickler that overrides the find_class method to strictly whitelist permitted modules and classes, or ensure the file loading operation is tightly constrained to cryptographically signed files.
Exploiting this vulnerability requires crafting a malicious serialized object and delivering it to the target system. The attacker authors a Python script defining a class with a __reduce__ method containing the payload.
import pickle
import subprocess
class MaliciousAlgo:
def __reduce__(self):
return (subprocess.call, (['calc.exe'],))
malicious_algo_bytes = pickle.dumps(MaliciousAlgo())
attack_data = {
"algo_bytes": malicious_algo_bytes,
}
with open("attack_algo.pkl", "wb") as f:
f.write(pickle.dumps(attack_data))The attacker then introduces attack_algo.pkl into the target environment. The delivery mechanism depends heavily on the application's specific implementation of MONAI. The file could be uploaded via an exposed web interface handling algorithm configurations, transferred via a shared network drive, or injected into a machine learning pipeline repository.
Once the file is on the filesystem and the application logic triggers algo_from_pickle("attack_algo.pkl"), the deserialization process fires. The subprocess.call instruction executes immediately, spawning the malicious process before the algo_from_pickle function completes its execution.
The CVSS v3.1 vector evaluates to 8.3 (CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:H). This score reflects the severe consequences of successful exploitation balanced against the specific prerequisites required to trigger the payload.
The attack vector is network-based (AV:N), assuming the attacker can introduce the malicious file through a network interface or data pipeline. The complexity is high (AC:H) and requires high privileges (PR:H) because the attacker must navigate the target environment's access controls to overwrite or supply the target .pkl file. User interaction (UI:R) is required to trigger the actual processing of the algorithm file.
The scope is changed (S:C) because the vulnerability allows the attacker to break out of the application's intended operational boundaries. Exploitation results in total compromise of Confidentiality, Integrity, and Availability (C:H/I:H/A:H) for the host system, constrained only by the operating system privileges assigned to the Python process executing the MONAI framework.
The primary remediation for this vulnerability is upgrading the MONAI package to version 1.5.2 or later. The patched version alters the mechanism by which algorithm states are loaded, mitigating the insecure deserialization flaw.
Organizations unable to immediately upgrade must implement strict access controls around the storage locations of .pkl files used by the MONAI application. Ensure that directory permissions prevent unauthorized write or overwrite operations. Validating the origin and integrity of files before they enter the data pipeline drastically reduces the likelihood of exploitation.
Security teams should conduct a broader audit of the application codebase to identify any other instances of unsafe deserialization. This includes searching for unvalidated calls to pickle.loads(), pickle.load(), or torch.load() without the weights_only=True parameter, which present identical attack vectors in machine learning environments.
CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
monai Project MONAI | < 1.5.2 | 1.5.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-502 |
| Vulnerability Class | Deserialization of Untrusted Data |
| CVSS v3.1 Base Score | 8.3 |
| Attack Vector | Network |
| Impact | Remote Code Execution (RCE) |
| Exploit Status | Proof of Concept Available |
The product deserializes untrusted data without sufficiently verifying that the resulting data will be valid.