CVE-2023-51449: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') (CWE-22)
value: Gradio is an open-source Python package that allows you to quickly build a demo or web application for your machine learning model, API, or any arbitary Python function. Versions of `gradio` prior to 4.11.0 contained a vulnerability in the `/file` route which made them susceptible to file traversal attacks in which an attacker could access arbitrary files on a machine running a Gradio app with a public URL (e.g. if the demo was created with `share=True`, or on Hugging Face Spaces) if they knew the path of files to look for. This issue has been patched in version 4.11.0.
CWE description: The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
CVSS v3 base score: 7.5
Published: 2023-12-22T21:15Z
Repository: https://github.com/gradio-app/gradio
Language: Python
Files changed: .changeset/tough-zoos-move.md, gradio/utils.py, test/test_utils.py
Commit date: 2023-12-18 14:30:22 -0800
Commit message: Prevent file traversals (#6833)

* prevent file traversal

* fix

* add changeset

* unit test

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Diff: diff --git a/.changeset/tough-zoos-move.md b/.changeset/tough-zoos-move.md
new file mode 100644
index 000000000..b307a92e6
--- /dev/null
+++ b/.changeset/tough-zoos-move.md
@@ -0,0 +1,5 @@
+---
+"gradio": minor
+---
+
+feat:Prevent file traversals
diff --git a/gradio/utils.py b/gradio/utils.py
index fdb644758..ab42006c7 100644
--- a/gradio/utils.py
+++ b/gradio/utils.py
@@ -930,11 +930,11 @@ def is_in_or_equal(path_1: str | Path, path_2: str | Path):
         path_1: str or Path (should be a file)
         path_2: str or Path (can be a file or directory)
     """
     path_1, path_2 = abspath(path_1), abspath(path_2)
     try:
-        if str(path_1.relative_to(path_2)).startswith(".."):  # prevent path traversal
+        if ".." in str(path_1.relative_to(path_2)):  # prevent path traversal
             return False
     except ValueError:
         return False
     return True
 
diff --git a/test/test_utils.py b/test/test_utils.py
index d10bafdc0..15c269771 100644
--- a/test/test_utils.py
+++ b/test/test_utils.py
@@ -401,10 +401,11 @@ def test_is_in_or_equal():
     assert is_in_or_equal("files/lion.jpg", "files")
     assert not is_in_or_equal("files", "files/lion.jpg")
     assert is_in_or_equal("/home/usr/notes.txt", "/home/usr/")
     assert not is_in_or_equal("/home/usr/subdirectory", "/home/usr/notes.txt")
     assert not is_in_or_equal("/home/usr/../../etc/notes.txt", "/home/usr/")
+    assert not is_in_or_equal("/safe_dir/subdir/../../unsafe_file.txt", "/safe_dir/")
 
 
 @pytest.mark.parametrize(
     "path_or_url, extension",
     [

Vulnerable code:         if str(path_1.relative_to(path_2)).startswith(".."):  # prevent path traversal
Fixed code: ---
"gradio": minor
---

feat:Prevent file traversals
        if ".." in str(path_1.relative_to(path_2)):  # prevent path traversal
    assert not is_in_or_equal("/safe_dir/subdir/../../unsafe_file.txt", "/safe_dir/")