Skip to content

Unauthenticated static path traversal

Moderate
dgtlmoon published GHSA-9jj8-v89v-xjvw Feb 16, 2026

Package

changedetection.io

Affected versions

<= 0.52.9

Patched versions

None

Description

Summary

The /static/<group>/<filename> route accepts group="..", which causes send_from_directory("static/..", filename) to execute. This moves the base directory up to /app/changedetectionio, enabling unauthenticated local file read of application source files (e.g., flask_app.py). Severity is low information disclosure (C:L).

Details

The vulnerable code is in changedetectionio/flask_app.py inside static_content():

group = re.sub(r'[^\w.-]+', '', group.lower())
filename = re.sub(r'[^\w.-]+', '', filename.lower())
...
return send_from_directory(f"static/{group}", path=filename)

The group sanitization allows dots, so group=".." passes validation.
This results in send_from_directory("static/..", filename), effectively shifting the base directory to /app/changedetectionio and allowing reads of files in that directory.
The route is unauthenticated, so any user can retrieve source files without logging in.

Limitation: the route only matches /static/<group>/<filename> and rejects slashes inside filename, so it cannot traverse further to arbitrary system paths like /etc/passwd. It is limited to files inside the application package directory.

PoC

  1. Start an instance (example: Docker on port 5050)
docker run -d --name cdio -p 127.0.0.1:5050:5000 -v cdio-data:/datastore cdio-local
  1. Reproduce
    (URL-encoded traversal)
curl -i http://127.0.0.1:5050/static/%2e%2e/flask_app.py

(curl path passthrough)

curl --path-as-is -i http://127.0.0.1:5050/static/../flask_app.py
  1. Observe that the response body contains Python source code from flask_app.py.

Impact

  • Vulnerability type: Directory Traversal / Local File Read
  • Affected users: Anyone with network access (no authentication required)
  • Scope: Source files under /app/changedetectionio
  • Security impact: Internal logic exposure can aid further exploitation (Confidentiality: Low)

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
Low
Integrity
None
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N

CVE ID

CVE-2026-25527

Weaknesses

Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

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. Learn more on MITRE.

Credits