Repository: termux/proot-distro
Component: proot_distro/commands/install.py → _extract_plain_tar(); also helpers/docker.py → _apply_layer()
| Component | Version | |---------------|------------------------------| | proot-distro | 5.0.2 (confirmed vulnerable) | | Termux app | 0.119.0-beta.3 | | Device / ABI | Samsung Galaxy A23 / aarch64 | | Python (host) | 3.13 |
proot-distro install extracts a plain tarball rootfs by calling _extract_plain_tar() in
proot_distro/commands/install.py. This function correctly rejects tar member names
containing .. components, but applies no equivalent check on symlink targets
(member.linkname). A tar archive can therefore:
/data/data/com.termux/files/home).Python's open() follows the symlink, writing the file on the host filesystem at the
privilege level of the Termux process — entirely during proot-distro install, before the
container is ever run.
The same _extract_plain_tar function is reachable via proot-distro reset, and the
equivalent _apply_layer in helpers/docker.py contains the same flaw.
proot_distro/commands/install.py, _extract_plain_tar():
elif member.issym():
# linkname taken verbatim from archive — no validation of target
os.symlink(member.linkname, dest) # ← symlink planted on host
elif member.isreg():
dest = os.path.join(rootfs_dir, rel_path)
with open(dest, 'wb') as out: # ← follows symlink above
...
The existing traversal guard only covers member names:
if any(p in ('..', '') for p in rel_parts):
continue # only checks the name, not the...
5.1.5Exploitability
AV:LAC:LPR:NUI:RScope
S:CImpact
C:HI:HA:N8.2/CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:NOther