VYPR
High severity7.0NVD Advisory· Published May 18, 2026· Updated May 19, 2026

CVE-2026-4137

CVE-2026-4137

Description

In mlflow/mlflow versions prior to 3.11.0, the get_or_create_nfs_tmp_dir() function in mlflow/utils/file_utils.py creates temporary directories with world-writable permissions (0o777), and the _create_model_downloading_tmp_dir() function in mlflow/pyfunc/__init__.py creates directories with group-writable permissions (0o770). These insecure permissions allow local attackers to tamper with model artifacts, such as cloudpickle-serialized Python objects, and achieve arbitrary code execution when the tampered artifacts are deserialized via cloudpickle.load(). This vulnerability is particularly critical in environments with shared NFS mounts, such as Databricks, where NFS is enabled by default. The issue is a continuation of the vulnerability class addressed in CVE-2025-10279, which was only partially fixed.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Insecure temporary directory permissions in mlflow prior to 3.11.0 allow local attackers to tamper with model artifacts and achieve arbitrary code execution via cloudpickle deserialization.

Vulnerability

In mlflow versions prior to 3.11.0, the get_or_create_nfs_tmp_dir() function in mlflow/utils/file_utils.py creates temporary directories with world-writable permissions (0o777), and the _create_model_downloading_tmp_dir() function in mlflow/pyfunc/__init__.py creates directories with group-writable permissions (0o770). These insecure permissions allow any local user on a shared system to write to these directories. The issue is a continuation of the vulnerability class addressed in CVE-2025-10279, which was only partially fixed [1][2].

Exploitation

An attacker with local access to the system (or to a shared NFS mount, such as in Databricks where NFS is enabled by default) can place a malicious cloudpickle-serialized Python object into the world-writable temporary directory. When mlflow later deserializes the model artifact via cloudpickle.load(), the attacker's payload executes, leading to arbitrary code execution. No authentication or user interaction beyond local access is required [2].

Impact

Successful exploitation allows the attacker to execute arbitrary Python code in the context of the mlflow process. This can lead to full compromise of the mlflow service, including data exfiltration, privilege escalation, and lateral movement within the environment. The impact is particularly severe in multi-tenant or shared NFS deployments [1][2].

Mitigation

The vulnerability is fixed in mlflow version 3.11.0. The fix changes the directory permissions to 0o750 (owner: rwx, group: r-x, others: none) for both functions, as shown in commit [1]. Users should upgrade to mlflow 3.11.0 or later. For environments where immediate upgrade is not possible, restrict local access to the NFS mount and ensure that only trusted users can write to the temporary directories [1][2].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2
  • Mlflow/Mlflowreferences2 versions
    (expand)+ 1 more
    • (no CPE)
    • (no CPE)range: <3.11.0

Patches

1
1dcbb0c2fbd1

Update directory permissions for Spark UDF accessibility (#20960)

https://github.com/mlflow/mlflowTomuHirataFeb 25, 2026via nvd-ref
2 files changed · +6 4
  • mlflow/pyfunc/__init__.py+3 2 modified
    @@ -1485,8 +1485,9 @@ def _create_model_downloading_tmp_dir(should_use_nfs):
     
         tmp_model_dir = tempfile.mkdtemp(dir=root_model_cache_dir)
         # mkdtemp creates a directory with permission 0o700
    -    # change it to be 0o770 to ensure it can be seen in spark UDF
    -    os.chmod(tmp_model_dir, 0o770)
    +    # For Spark UDFs, we need to make it accessible to other processes
    +    # Use 0o750 (owner: rwx, group: r-x, others: None) instead of 0o770
    +    os.chmod(tmp_model_dir, 0o750)
         return tmp_model_dir
     
     
    
  • mlflow/utils/file_utils.py+3 2 modified
    @@ -792,8 +792,9 @@ def get_or_create_nfs_tmp_dir():
         else:
             tmp_nfs_dir = tempfile.mkdtemp(dir=nfs_root_dir)
             # mkdtemp creates a directory with permission 0o700
    -        # change it to be 0o777 to ensure it can be seen in spark UDF
    -        os.chmod(tmp_nfs_dir, 0o777)
    +        # For Spark UDFs, we need to make it accessible to other processes
    +        # Use 0o750 (owner: rwx, group: r-x, others: None) instead of 0o777
    +        os.chmod(tmp_nfs_dir, 0o750)
             atexit.register(shutil.rmtree, tmp_nfs_dir, ignore_errors=True)
     
         return tmp_nfs_dir
    

Vulnerability mechanics

Root cause

"Temporary directories for NFS and model-downloading are created with overly permissive world-writable (0o777) or group-writable (0o770) permissions, allowing local attackers to tamper with model artifacts."

Attack vector

A local attacker with access to the shared filesystem (e.g., an NFS mount on Databricks) can write malicious content into the world-writable or group-writable temporary directories created by `get_or_create_nfs_tmp_dir()` or `_create_model_downloading_tmp_dir()` [CWE-378]. Because these directories hold cloudpickle-serialized Python objects that are later deserialized via `cloudpickle.load()`, the attacker can replace a model artifact with a malicious pickle payload. When MLflow loads the tampered artifact, arbitrary code execution occurs in the context of the victim process. The attack requires local filesystem access and is especially dangerous in multi-tenant environments where NFS is enabled by default.

Affected code

The vulnerability exists in two functions: `get_or_create_nfs_tmp_dir()` in `mlflow/utils/file_utils.py` and `_create_model_downloading_tmp_dir()` in `mlflow/pyfunc/__init__.py`. Both functions call `tempfile.mkdtemp()` (which creates directories with 0o700 permissions) and then immediately relax permissions via `os.chmod()` — the former to 0o777 and the latter to 0o770 — to allow Spark UDF access. This relaxation introduces the insecure permissions.

What the fix does

The patch tightens directory permissions from 0o777 (world-writable) to 0o750 (owner: rwx, group: r-x, others: none) in `get_or_create_nfs_tmp_dir()` [patch_id=424399], and from 0o770 (group-writable) to 0o750 in `_create_model_downloading_tmp_dir()` [patch_id=424399]. The 0o750 mode still allows Spark UDF processes running under the same group to read and traverse the directory, which was the original reason for the permissive modes, but it removes write access from group members and all access from others. This prevents local attackers who are not the directory owner from planting malicious files in the temporary directories.

Preconditions

  • authAttacker must have local user access to the shared filesystem (e.g., NFS mount) where MLflow creates temporary directories.
  • configThe environment must use NFS (enabled by default on Databricks) or otherwise share the filesystem between users.
  • inputA victim process must deserialize a cloudpickle artifact from the tampered temporary directory.

Generated on May 19, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

2

News mentions

0

No linked articles in our index yet.