From 6317a8ccfa4a70d9d0d2d5335e8c95fc61968bb7 Mon Sep 17 00:00:00 2001 From: "R. Garcia-Dias" Date: Thu, 30 Jul 2026 17:13:15 +0100 Subject: [PATCH] fix: address Dependabot security alerts for mlflow, transformers, setuptools - mlflow: bump floor to >=3.11.1 (drops the <3.0 cap), closing CVEs across the 2.x/early-3.x line. The cap existed for a Python 3.12 packaging bug in mlflow.utils.uv_utils that is no longer present in current releases. mlflow>=3.13 also turns the local file-store warning into a hard error (#8891); MLFlowHandler now sets MLFLOW_ALLOW_FILE_STORE=true by default since it documents and relies on that local store. Documented the side effect in the class docstring and added tests covering both the unset-defaults-to-true and existing-value-is-preserved cases. - transformers: bump floor to >=5.5.0 (drops the <5.0 cap), closing two HIGH severity CVEs. The cap existed because transformers>=5.x broke Transchex: BertConfig was previously a bare ad-hoc class missing `_attn_implementation`, and BertLayer's forward() return type changed from a tuple to a bare Tensor (the latter was already handled). Fixed both in transchex.py and verified against transformers 4.36-4.40 and 5.5-5.14. The previous <5.0 cap's stated reason (torch.float8_e8m0fnu missing from the nv25.03 Docker image's PyTorch 2.7 build) is unrelated to transchex.py and should be re-verified against the current NGC base image before merging, since it wasn't reproducible against a stock PyPI torch>=2.8.0 install. - setuptools: bump requirements-min.txt floor to >=78.1.1, closing one HIGH severity CVE. Still capped at <=79.0.1 because setuptools>=80 breaks MONAI's own setup.py CLI usage (#8439); a MEDIUM severity CVE fixed in 83.0.0 remains open until that's resolved. Also drop requirements-dev.txt's separate `setuptools<71` cap, which conflicted with that floor and broke CI dependency installation (mypy, hyena-dep, full-dep): it was added for MetricsReloaded's legacy pkg_resources-based setup.py, but the `monai-support` branch already has that import commented out, and the pinned segment-anything commit never used pkg_resources either, so the cap is no longer needed. Verified via targeted venv testing against the actual pinned versions (transformers==5.5.0, mlflow==3.11.1): tests/networks/nets/test_transchex.py and tests/handlers/test_handler_mlflow.py both pass. CodeRabbit flagged MultiModal.__init__ (transchex.py) for allegedly calling transformers' PreTrainedModel.__init__() without a config, which 5.5.0 requires. That's a false positive: MultiModal subclasses transchex.py's own local `BertPreTrainedModel(nn.Module)` shim, not transformers' class, so HF's config-in-super().__init__() requirement doesn't apply. Confirmed by running the test suite unchanged against transformers 5.5.0 (3 passed). Co-Authored-By: Claude Sonnet 5 Signed-off-by: R. Garcia-Dias --- docs/requirements.txt | 4 ++-- monai/handlers/mlflow_handler.py | 9 +++++++++ monai/networks/nets/transchex.py | 7 ++++++- requirements-dev.txt | 12 +++++++++--- requirements-min.txt | 7 +++++-- tests/handlers/test_handler_mlflow.py | 25 +++++++++++++++++++++++++ 6 files changed, 56 insertions(+), 8 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 3027d401646..bae28396133 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -20,8 +20,8 @@ sphinxcontrib-serializinghtml sphinx-autodoc-typehints==1.11.1 pandas einops -transformers>=4.53.0 -mlflow>=2.12.2,<3.13 +transformers>=5.5.0 +mlflow>=3.11.1 # see requirements-dev.txt for why the previous <3.0/<3.13 caps are no longer needed clearml>=1.10.0rc0 tensorboardX imagecodecs; platform_system == "Linux" or platform_system == "Darwin" diff --git a/monai/handlers/mlflow_handler.py b/monai/handlers/mlflow_handler.py index 3078d89f97c..831ae689a8f 100644 --- a/monai/handlers/mlflow_handler.py +++ b/monai/handlers/mlflow_handler.py @@ -60,6 +60,10 @@ class MLFlowHandler: ``engine.state.metrics`` in MLFlow. - When ITERATION_COMPLETED, track expected item in ``self.output_transform(engine.state.output)`` in MLFlow, default to `Loss`. + - On construction, sets the ``MLFLOW_ALLOW_FILE_STORE`` environment variable to + ``"true"`` if it is not already set, since ``MLFlowHandler`` defaults to (and + documents) tracking to the local filesystem store, which mlflow>=3.13 otherwise + refuses to use. Any value the user has already set is left untouched. Usage example is available in the tutorial: https://github.com/Project-MONAI/tutorials/blob/master/3d_segmentation/unet_segmentation_3d_ignite.ipynb. @@ -156,6 +160,11 @@ def __init__( self.experiment_param = experiment_param self.artifacts = ensure_tuple(artifacts) self.optimizer_param_names = ensure_tuple(optimizer_param_names) + # mlflow>=3.13 raises instead of warning when the tracking URI resolves to the local + # filesystem store (e.g. the default `mlruns` directory), see + # https://github.com/Project-MONAI/MONAI/issues/8891. MLFlowHandler documents and relies + # on this local file store as its default, so opt back into it unless the user overrode it. + os.environ.setdefault("MLFLOW_ALLOW_FILE_STORE", "true") self.client = mlflow.MlflowClient(tracking_uri=tracking_uri if tracking_uri else None) self.run_finish_status = mlflow.entities.RunStatus.to_string(mlflow.entities.RunStatus.FINISHED) self.close_on_complete = close_on_complete diff --git a/monai/networks/nets/transchex.py b/monai/networks/nets/transchex.py index 6c40cae2aa3..0adab5f4e7d 100644 --- a/monai/networks/nets/transchex.py +++ b/monai/networks/nets/transchex.py @@ -23,6 +23,7 @@ transformers = optional_import("transformers") load_tf_weights_in_bert = optional_import("transformers", name="load_tf_weights_in_bert")[0] cached_file = optional_import("transformers.utils", name="cached_file")[0] +BertConfig = optional_import("transformers", name="BertConfig")[0] BertEmbeddings = optional_import("transformers.models.bert.modeling_bert", name="BertEmbeddings")[0] BertLayer = optional_import("transformers.models.bert.modeling_bert", name="BertLayer")[0] @@ -219,7 +220,11 @@ def __init__( """ super().__init__() - self.config = type("obj", (object,), bert_config) + self.config = BertConfig(**bert_config) + # explicitly select the eager attention path: transformers>=4.48 dispatches attention + # implementations via `config._attn_implementation`, which is otherwise left unset since + # `bert_config` above does not come from a `from_pretrained` call. + self.config._attn_implementation = "eager" self.embeddings = BertEmbeddings(self.config) self.language_encoder = nn.ModuleList([BertLayer(self.config) for _ in range(num_language_layers)]) self.vision_encoder = nn.ModuleList([BertLayer(self.config) for _ in range(num_vision_layers)]) diff --git a/requirements-dev.txt b/requirements-dev.txt index b2c36f8de62..93446fc7483 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -18,7 +18,6 @@ black>=26.3.1 isort>=5.1, <6, !=6.0.0 ruff>=0.14.11,<0.15 pybind11 -setuptools<71 # pkg_resources removed in setuptools>=71; needed by MetricsReloaded setup.py types-setuptools mypy>=1.5.0, <1.12.0 ninja @@ -34,8 +33,15 @@ tifffile; platform_system == "Linux" or platform_system == "Darwin" pandas requests einops -transformers>=4.53.0, <5.0 # 5.x references torch.float8_e8m0fnu absent in older PyTorch builds -mlflow>=2.12.2, <3.0 # 3.x broken on Python 3.12 (relative import in mlflow.utils.uv_utils) +transformers>=5.5.0 # 4.x/early-5.x are vulnerable (GHSA-fgcw-684q-jj6r, GHSA-29pf-2h5f-8g72); the +# previous <5.0 cap was needed because the nv25.03 Docker image's PyTorch 2.7 build lacked +# `torch.float8_e8m0fnu`; the PyPI `torch>=2.8.0` floor this repo declares has it, and +# `monai/networks/nets/transchex.py` has been updated for transformers>=5's BertLayer/BertConfig +# API changes. Re-verify against the current NGC base image before merging. +mlflow>=3.11.1 # <3.4.0rc0 through <=3.10.1 versions have several CVEs; the previous <3.0 cap was +# for a Python 3.12 packaging bug in mlflow.utils.uv_utils, no longer present in current releases. +# mlflow>=3.13 also hard-errors on the local file-store backend unless MLFLOW_ALLOW_FILE_STORE=true +# (see monai/handlers/mlflow_handler.py and https://github.com/Project-MONAI/MONAI/issues/8891). clearml>=1.10.0rc0 matplotlib>=3.6.3 tensorboardX diff --git a/requirements-min.txt b/requirements-min.txt index ddda9064a6b..81d3312c72b 100644 --- a/requirements-min.txt +++ b/requirements-min.txt @@ -1,7 +1,10 @@ # Requirements for minimal tests -r requirements.txt -setuptools>=50.3.0,<66.0.0,!=60.6.0 ; python_version < "3.12" -setuptools>=70.2.0,<=79.0.1; python_version >= "3.12" +# <78.1.1 is vulnerable to GHSA-5rjg-fvgr-3xxf (path traversal / arbitrary file write). The +# upper bound is unrelated to the CVE: setuptools>=80 dropped the legacy `setup.py` CLI +# invocation MONAI's own build script relies on (Project-MONAI/MONAI#8439), so this can't yet +# go as high as 83.0.0, which would also fix GHSA-h35f-9h28-mq5c (MANIFEST.in exclusion bypass). +setuptools>=78.1.1,<=79.0.1 coverage>=5.5 parameterized packaging diff --git a/tests/handlers/test_handler_mlflow.py b/tests/handlers/test_handler_mlflow.py index 80630e6f5a2..16d86e7305d 100644 --- a/tests/handlers/test_handler_mlflow.py +++ b/tests/handlers/test_handler_mlflow.py @@ -106,6 +106,31 @@ def _update_metric(engine): # the run count should equal to the times of creating engine self.assertEqual(create_engine_times, run_cnt) + def test_allow_file_store_env_var_defaults_true(self): + original = os.environ.pop("MLFLOW_ALLOW_FILE_STORE", None) + try: + with tempfile.TemporaryDirectory() as tempdir: + MLFlowHandler(tracking_uri=path_to_uri(os.path.join(tempdir, "mlflow_test"))) + self.assertEqual(os.environ["MLFLOW_ALLOW_FILE_STORE"], "true") + finally: + if original is None: + os.environ.pop("MLFLOW_ALLOW_FILE_STORE", None) + else: + os.environ["MLFLOW_ALLOW_FILE_STORE"] = original + + def test_allow_file_store_env_var_preserves_existing(self): + original = os.environ.get("MLFLOW_ALLOW_FILE_STORE") + os.environ["MLFLOW_ALLOW_FILE_STORE"] = "false" + try: + with tempfile.TemporaryDirectory() as tempdir: + MLFlowHandler(tracking_uri=path_to_uri(os.path.join(tempdir, "mlflow_test"))) + self.assertEqual(os.environ["MLFLOW_ALLOW_FILE_STORE"], "false") + finally: + if original is None: + os.environ.pop("MLFLOW_ALLOW_FILE_STORE", None) + else: + os.environ["MLFLOW_ALLOW_FILE_STORE"] = original + def test_metrics_track(self): experiment_param = {"backbone": "efficientnet_b0"} with tempfile.TemporaryDirectory() as tempdir: