CVE-2026-49119: Verified Reproduction
CVE-2026-49119: Gradio FileExplorer path traversal
CVE-2026-49119 is verified against gradio-app/gradio · github. Affected versions: < 6.16.0. Fixed in 6.16.0. Vulnerability class: Path Traversal. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00246.
What Is CVE-2026-49119?
CVE-2026-49119 is a high-severity path traversal vulnerability (CWE-22) in Gradio's FileExplorer component that lets an unauthenticated attacker read arbitrary files on the Gradio server host. Pruva reproduced it (reproduction REPRO-2026-00246).
CVE-2026-49119 Severity & CVSS Score
CVE-2026-49119 is rated high severity, with a CVSS base score of 7.5 out of 10.
High — serious impact or readily exploitable. Prioritize remediation.
Affected gradio-app/gradio Versions
gradio-app/gradio · github versions < 6.16.0 are affected.
How to Reproduce CVE-2026-49119
pruva-verify REPRO-2026-00246 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00246/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-49119
- reached the target end-to-end
- on the real production code path
- high confidence
- the upstream fix blocks the same trigger
FileExplorer payload with ../ traversal segments
- /gradio_api/run/predict/ of a running Gradio app with FileExplorer input
How the agent worked
Root Cause and Exploit Chain for CVE-2026-49119
Gradio before 6.16.0 contains a path-traversal vulnerability in the FileExplorer component's preprocess() method. When a Gradio app exposes a FileExplorer input, an unauthenticated remote attacker can send API requests containing .. segments as the selected file path. The vulnerable preprocess() implementation joins the attacker-controlled segments directly under the configured root_dir using os.path.join + os.path.normpath, producing a resolved path that escapes the intended root directory. The resulting path is passed to the user-defined prediction function, enabling arbitrary file read (CWE-22) from the Gradio server host.
- Product / component:
gradioPython package, specificallygradio/components/file_explorer.py(FileExplorercomponent). - Affected versions: Gradio before 6.16.0 (vulnerable code present at commit
0d670adf41a0b510f7fd745495dce1664d38f0e5). - Fixed version: Gradio 6.16.0 (fix commit
97d541f3d5fd05b2587a69ecc94b68fe5d2d7004). - Risk / consequences: High. Any unauthenticated user who can reach the Gradio API can read arbitrary files readable by the Gradio process (e.g.,
/etc/passwd, application secrets, source code). The attacker only needs to know or guess the relative path structure above the configuredroot_dir.
Impact Parity
- Disclosed / claimed maximum impact: Information disclosure / arbitrary file read via directory traversal (
info_leak). - Reproduced impact from this run: The running vulnerable Gradio app returned the contents of a file outside the configured
root_dir(/tmp/gradio_secret.txt) in response to an API call with a..traversal payload. The fixed commit rejected the same payload and did not return the file contents. - Parity:
full— the reproduction demonstrates the exact info-leak impact claimed by the ticket. - Not demonstrated: N/A (full impact was reached through the real API surface).
Root Cause
In the vulnerable FileExplorer.preprocess() implementation:
file_ = os.path.normpath(os.path.join(self.root_dir, *file))
os.path.join simply concatenates root_dir with the attacker-provided path segments, and os.path.normpath then resolves any .. segments. Because there is no validation that the final resolved path remains inside root_dir, a payload such as ["..", "gradio_secret.txt"] resolves to /tmp/gradio_root/../gradio_secret.txt → /tmp/gradio_secret.txt, which is outside the configured root. This behavior was inconsistent with the component's ls() method, which already validated paths via _safe_join.
The fix commit 97d541f3d5fd05b2587a69ecc94b68fe5d2d7004 (PR #13437) routes both preprocess branches through the same _safe_join helper used by ls(). _safe_join raises InvalidPathError when the combined path is absolute or escapes root_dir, blocking the traversal.
Reproduction Steps
- Run
bundle/repro/reproduction_steps.sh. The script is self-contained and works from any directory; it setsPRUVA_ROOTautomatically if not provided. - What the script does:
- Clones or reuses the Gradio repository in the durable project cache (
/data/pruva/project-cache/.../repo). - Creates a Python venv in the project cache and installs Gradio as an editable package from the repo.
- Checks out the vulnerable commit (
0d670adf41a0b510f7fd745495dce1664d38f0e5), starts a small Gradio app with aFileExplorerinput rooted at/tmp/gradio_root, and uses_frontend=Falseso the server can run without a built frontend. - Waits until the
/gradio_api/infohealth endpoint responds, then sends a crafted POST to/gradio_api/run/predict/with payload{"data": [[["..", "gradio_secret.txt"]]]}. - Verifies that the response contains the secret string
PRUVA_SECRET_12345read from/tmp/gradio_secret.txt, confirming the info leak. - Repeats the same test against the fixed commit (
97d541f3d5fd05b2587a69ecc94b68fe5d2d7004) and verifies that the secret is no longer returned (the API returns a 500 error with no secret data).
- Clones or reuses the Gradio repository in the durable project cache (
- Expected evidence: The vulnerable run logs a 200 response with
{"data": ["PRUVA_SECRET_12345"]}. The fixed run logs a 500 response with{"error": "", "visible": true}and no secret content.
Evidence
bundle/logs/reproduction_steps.log— full console output from both runs.bundle/logs/server_vuln.log— Gradio server logs for the vulnerable commit.bundle/logs/server_fixed.log— Gradio server logs for the fixed commit (contains theInvalidPathErrortraceback).bundle/repro/runtime_manifest.json— structured runtime evidence (service started, healthcheck passed, target endpoint reached, proof artifacts listed).bundle/repro/validation_verdict.json— structured verdict confirming the claim.
Key excerpt from the vulnerable run:
{
"data": ["PRUVA_SECRET_12345"],
"is_generating": false,
"duration": 0.0002281665802001953,
...
}
Key excerpt from the fixed run:
{
"error": "",
"visible": true
}
Recommendations / Next Steps
- Upgrade to Gradio 6.16.0 or later, which includes the
_safe_joinvalidation inFileExplorer.preprocess(). - Validate all user-provided paths against a known-safe root directory before using them for filesystem operations. Prefer library helpers such as
safe_joinover rawos.path.join/os.path.normpathfor user input. - Regression tests should be added that exercise
preprocess()with..and absolute-path payloads, asserting thatInvalidPathError(or equivalent) is raised. - Defense in depth: run the Gradio service with minimal file-system permissions and avoid placing sensitive files in locations readable by the process.
Additional Notes
- Idempotency: The reproduction script was run twice consecutively and produced the same confirmed result both times.
- Environment: The script runs in a clean sandbox using only Python 3.14 and the tools available there. It installs Gradio from source into a project-cache venv, so subsequent runs reuse the build environment while still performing fresh current-run proofs.
- Limitations: The reproduction uses
_frontend=Falsebecause the checked-out source repository does not contain the built frontend assets. This is a deployment convenience and does not affect the API surface under test; the real/gradio_api/run/predict/endpoint is exercised and the vulnerableFileExplorer.preprocess()code path is reached.
CVE-2026-49119 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
Artifacts and Evidence for CVE-2026-49119
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2026-49119
Upgrade gradio-app/gradio · github to 6.16.0 or later.
FAQ: CVE-2026-49119
How does the CVE-2026-49119 path traversal work?
.. segments as the selected FileExplorer path; the vulnerable preprocess() implementation resolves the path outside root_dir and passes it to the user-defined prediction function, letting the attacker read files such as /etc/passwd or application secrets that are readable by the Gradio process.Which Gradio versions are affected by CVE-2026-49119, and where is it fixed?
How severe is CVE-2026-49119?
How can I reproduce CVE-2026-49119?
References for CVE-2026-49119
Authoritative sources for CVE-2026-49119 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.