From 1c21f7527cee6af17232e0f704d9ef73860bf694 Mon Sep 17 00:00:00 2001 From: "R. Garcia-Dias" Date: Thu, 3 Sep 2026 11:11:08 +0100 Subject: [PATCH 1/3] fix(auto3dseg): warn before instantiating _target_ from algo_object.json algo_from_json resolves the JSON _target_ value to an importable callable and invokes it, and adds file-influenced directories to sys.path. Emit a trust-boundary warning before instantiation (GHSA-2wx3-8x3w-r8qv). Signed-off-by: R. Garcia-Dias --- monai/auto3dseg/utils.py | 8 ++++++++ tests/apps/test_auto3dseg.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/monai/auto3dseg/utils.py b/monai/auto3dseg/utils.py index f349561bdcb..b509da2b45c 100644 --- a/monai/auto3dseg/utils.py +++ b/monai/auto3dseg/utils.py @@ -493,6 +493,14 @@ def algo_from_json(filename: str, template_path: PathLike | None = None, **kwarg if state_template_path: algo_config["template_path"] = state_template_path + warnings.warn( + f"loading {filename}: the file's `_target_` value is resolved to an importable callable and " + "invoked, and template directories from the file may be added to `sys.path`; only load " + "algo_object.json files from a source you trust " + "(see https://github.com/Project-MONAI/MONAI/security/advisories/GHSA-2wx3-8x3w-r8qv).", + stacklevel=2, + ) + parser = ConfigParser(algo_config) algo = parser.get_parsed_content() used_template_path = path diff --git a/tests/apps/test_auto3dseg.py b/tests/apps/test_auto3dseg.py index 57e05d1ee6f..6037484ac6c 100644 --- a/tests/apps/test_auto3dseg.py +++ b/tests/apps/test_auto3dseg.py @@ -11,9 +11,11 @@ from __future__ import annotations +import json import os import tempfile import unittest +import warnings from copy import deepcopy from numbers import Number @@ -36,6 +38,7 @@ SampleOperations, SegSummarizer, SummaryOperations, + algo_from_json, datafold_read, verify_report_format, ) @@ -177,6 +180,20 @@ def __call__(self, data): return d +class _DummyAlgo: + """Minimal stand-in for an Auto3DSeg Algo object used in warning tests.""" + + def __init__(self) -> None: + self.template_path: str | None = None + self.output_path = os.getcwd() + + def load_state_dict(self, state: dict) -> None: + pass + + def get_output_path(self) -> str: + return self.output_path + + class TestDataAnalyzer(unittest.TestCase): def setUp(self): self.test_dir = tempfile.TemporaryDirectory() @@ -619,5 +636,20 @@ def tearDown(self) -> None: self.test_dir.cleanup() +class TestAlgoFromJsonSecurityWarning(unittest.TestCase): + def test_warns_about_untrusted_target(self) -> None: + with tempfile.TemporaryDirectory() as tmpdir: + algo_file = os.path.join(tmpdir, "algo_object.json") + with open(algo_file, "w", encoding="utf-8") as f: + json.dump({"_target_": f"{__name__}._DummyAlgo"}, f) + + with warnings.catch_warnings(record=True) as caught: + warnings.simplefilter("always") + algo_from_json(algo_file) + + messages = [str(w.message) for w in caught] + assert any("algo_object.json" in msg and "trust" in msg for msg in messages), messages + + if __name__ == "__main__": unittest.main() From 1c6945fd50b742a4abfefd2b925a6a154f4f4670 Mon Sep 17 00:00:00 2001 From: "R. Garcia-Dias" Date: Thu, 3 Sep 2026 14:55:27 +0100 Subject: [PATCH 2/3] fix: address PR #9085 review feedback - wording: 'Loading' and 'imported callable' in the algo_from_json warning - clearer assertion message in the warning test Signed-off-by: R. Garcia-Dias --- monai/auto3dseg/utils.py | 2 +- tests/apps/test_auto3dseg.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/monai/auto3dseg/utils.py b/monai/auto3dseg/utils.py index b509da2b45c..518c91919da 100644 --- a/monai/auto3dseg/utils.py +++ b/monai/auto3dseg/utils.py @@ -494,7 +494,7 @@ def algo_from_json(filename: str, template_path: PathLike | None = None, **kwarg algo_config["template_path"] = state_template_path warnings.warn( - f"loading {filename}: the file's `_target_` value is resolved to an importable callable and " + f"Loading {filename}: the file's `_target_` value is resolved to an imported callable and " "invoked, and template directories from the file may be added to `sys.path`; only load " "algo_object.json files from a source you trust " "(see https://github.com/Project-MONAI/MONAI/security/advisories/GHSA-2wx3-8x3w-r8qv).", diff --git a/tests/apps/test_auto3dseg.py b/tests/apps/test_auto3dseg.py index 6037484ac6c..c310afc76ab 100644 --- a/tests/apps/test_auto3dseg.py +++ b/tests/apps/test_auto3dseg.py @@ -648,7 +648,10 @@ def test_warns_about_untrusted_target(self) -> None: algo_from_json(algo_file) messages = [str(w.message) for w in caught] - assert any("algo_object.json" in msg and "trust" in msg for msg in messages), messages + self.assertTrue( + any("algo_object.json" in msg and "trust" in msg for msg in messages), + f"Keywords 'algo_object.json' and 'trust' not found in warning messages: {messages}", + ) if __name__ == "__main__": From 63f08da01aed0302d62a199ed7a29bc09148c5c6 Mon Sep 17 00:00:00 2001 From: "R. Garcia-Dias" Date: Thu, 3 Sep 2026 15:16:43 +0100 Subject: [PATCH 3/3] chore: re-trigger CI