CVE-2023-6975 (published 2023-12-20T06:15Z)

A malicious user could use this issue to get command execution on the vulnerable machine and get access to data & models information.

CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-29
cwe_name: Path Traversal: '\..\filename'
description: The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize '\..\filename' (leading backslash dot dot) sequences that can resolve to a location that is outside of that directory.
extended_description: 
            This allows attackers to traverse the file system to access files or directories that are outside of the restricted directory.
            This is similar to CWE-25, except using "\" instead of "/". Sometimes a program checks for "..\" at the beginning of the input, so a "\..\" can bypass that check. It is also useful for bypassing path traversal protection schemes that only assume that the "/" separator is valid.
         
         

Fix information:
repo_url: https://github.com/mlflow/mlflow
commit_details: repo_url: https://github.com/mlflow/mlflow
author: Harutaka Kawamura
author_date: 2023-12-12 17:35:51+09:00
msg: Apply `os.path.basename` before `.` or `..` check in `FTPArtifactRepository` (#10657)

Signed-off-by: harupy <17039389+harupy@users.noreply.github.com>
repository: repo_url: https://github.com/mlflow/mlflow
repo_name: mlflow/mlflow
description: Open source platform for the machine learning lifecycle
repo_language: Python
owner: mlflow
file_changes: filename: ftp_artifact_repo.py
change_type: ModificationType.MODIFY
diff: @@ -106,10 +106,10 @@ class FTPArtifactRepository(ArtifactRepository):
             if not self._is_dir(ftp, list_dir):
                 return []
             artifact_files = ftp.nlst(list_dir)
-            artifact_files = list(filter(lambda x: x != "." and x != "..", artifact_files))
             # Make sure artifact_files is a list of file names because ftp.nlst
             # may return absolute paths.
             artifact_files = [os.path.basename(f) for f in artifact_files]
+            artifact_files = list(filter(lambda x: x != "." and x != "..", artifact_files))
             infos = []
             for file_name in artifact_files:
                 file_path = file_name if path is None else posixpath.join(path, file_name)

programming_language: Python
filename: test_ftp_artifact_repo.py
change_type: ModificationType.MODIFY
diff: @@ -67,6 +67,18 @@ def test_list_artifacts(ftp_mock):
     assert artifacts[1].file_size is None
 
 
+def test_list_artifacts_malicious_path(ftp_mock):
+    artifact_root_path = "/experiment_id/run_id/"
+    repo = FTPArtifactRepository("ftp://test_ftp" + artifact_root_path)
+    repo.get_ftp_client = MagicMock()
+    call_mock = MagicMock(return_value=ftp_mock)
+    repo.get_ftp_client.return_value = MagicMock(__enter__=call_mock)
+    ftp_mock.nlst = MagicMock(return_value=[".", "/.", "/..", "//.."])
+
+    artifacts = repo.list_artifacts(path=None)
+    assert artifacts == []
+
+
 def test_list_artifacts_when_ftp_nlst_returns_absolute_paths(ftp_mock):
     artifact_root_path = "/experiment_id/run_id/"
     repo = FTPArtifactRepository("ftp://test_ftp" + artifact_root_path)

programming_language: Python