Skip to content
GHSA 873f Pvrv 4x83

GHSA 873f Pvrv 4x83

github.com • September 27, 2026

monai.bundle.load() is documented as a helper to load a bundle's model weights. With its default arguments it downloads a bundle from a remote source and then builds the bundle's network by parsing the bundle's own configuration. Parsing runs MONAI's configuration engine on attacker controlled content, which resolves any _target_ value to an importable callable with no allow list and passes any "$..." value to Python eval() . Loading a malicious bundle therefore runs arbitrary code on the host.

This is runtime confirmed on monai 1.6.0, the current PyPI release. The torch.load call on this path already uses weights_only=True , so this issue is separate from the previously fixed pickle and torch.load advisories.

Remote code execution through a malicious model artifact.

CVSS 3.1 base score 7.8 (High), vector CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H .

Attack Vector is Local because exploitation relies on a user loading a malicious bundle, which is the "open a malicious document" case in the CVSS specification. User Interaction is Required for the same reason. An attacker needs no privileges and only has to publish a bundle to a source the victim downloads from. Code execution yields full confidentiality, integrity, and availability impact within the loading process.

Affected component and versions

Package monai (Project-MONAI/MONAI). Component: the monai.bundle configuration engine reached through monai.bundle.load and monai.bundle.run . Runtime confirmed on 1.6.0 and on the current dev branch. The relevant code is long standing, so earlier releases are also affected.

The configuration engine has two code execution sinks and neither is restricted.

_target_ resolves to any importable object and is then called, in monai/utils/module.py , instantiate() :

$ expressions are passed to eval() , in monai/bundle/config_item.py , ConfigExpression.evaluate() :

There is no allow list, type check, or trust flag on either path.

These sinks are reached from the monai.bundle.load weights loading helper, in monai/bundle/scripts.py :

If the bundle is not present locally, load calls download(...) to fetch it from source , which can be huggingface_hub , github , ngc , or monaihosting (lines 718 to 728).

torch.load(full_path, ..., weights_only=True) reads the weights safely (line 734).

With the default model=None , load reads the downloaded configs/train.json and calls create_workflow(config_file=...) (lines 742 to 751).

load then reads _workflow.network_def (line 760).

In monai/bundle/workflows.py , reading network_def calls self.parser.get_parsed_content(id=...) (lines 541 to 560), which instantiates the network definition from the attacker's config and triggers the _target_ resolution and $ evaluation above.

monai.bundle.run(...) reaches the same get_parsed_content sink and is affected in the same way.

The attacker prepares a bundle whose configs/train.json sets, for example, "network_def": "$__import__('os').system(' ')" , or uses a _target_ that points at an arbitrary callable.

The attacker publishes the bundle to a source MONAI can download from, such as a HuggingFace Hub repository or a GitHub release.

The victim calls monai.bundle.load(name=..., source="huggingface_hub", repo="attacker/repo") or monai.bundle.run(...) , expecting to load weights.

MONAI downloads the bundle, parses the config to build the network, and runs the attacker's code.

See monai_rce_poc.py . It uses a benign marker, writing a proof file instead of running a harmful command, and demonstrates three things:

Part A: ConfigParser({"exploit": "$ "}).get_parsed_content("exploit") runs the payload through eval . This is the primitive get_parsed_content applies to bundle config values.

Part B: a _target_ of os.system is resolved by locate() with no allow list.

Part C: an end to end monai.bundle.load() against a locally staged malicious bundle. No network is needed because load skips the download when the bundle path already exists.

Output from an isolated python:3.11-slim container using the official PyPI monai :

In case C the payload runs while MONAI builds network_def . The later AttributeError happens only after the code has already executed.

Any application or pipeline that loads MONAI bundles from a remote or otherwise untrusted source can be made to run arbitrary code on the loading host. In clinical imaging deployments this can mean code execution on systems that process sensitive patient data.

Suggested remediation

Restrict the configuration engine when it processes bundles that come from a download or another untrusted source. Reasonable options, matching what NeMo and Uni2TS adopted for the same class of issue:

Add an allow list of permitted modules and classes for _target_ resolution, verified before instantiation, and confirm the resolved object matches the expected type such as a torch.nn.Module for network_def .

Disable $ eval expressions for untrusted bundles, or require an explicit opt in.

Document that bundle.load and bundle.run execute code from the bundle configuration, and default to the safe behavior.

Relationship to existing advisories

This is a distinct issue from the published MONAI advisories. Those cover pickle deserialization ( CVE-2025-58756 , CVE-2025-58757 , GHSA-89gg-p5r5-q6r4 , GHSA-qxq5-qhx6-94qw , GHSA-wg9g-w2j2-8pgr ), path traversal ( CVE-2025-58755 , CVE-2026-21851 ), and OS command injection in the nnUNet runner ( GHSA-rghg-q7wp-9767 ). None of them is the ConfigParser _target_ to locate() instantiation or the $ expression eval() reached through bundle.load and bundle.run . The behavior is unmitigated on the current dev branch.

GHSA-rghg-q7wp-9767 already establishes within this project that a malicious configuration file leading to code execution is treated as a vulnerability and fixed. This report is the same category, a malicious bundle configuration leading to code execution, with a different sink.

The broader class is described by Palo Alto Unit42 in "Remote Code Execution With Modern AI/ML Formats and Libraries", which covers NeMo ( CVE-2025-23304 ), Uni2TS ( CVE-2026-22584 ), and FlexTok, and does not name MONAI.