GHSA-f396-4rp4-7v2j: Boxlite: Path Traversal Vulnerability Leads to Arbitrary File Write on the Host
SummaryBoxlite is a sandbox service that allows users to create lightweight virtual machines (Boxes) and run OCI containers within them. Boxlite allows users to specify the OCI image used by containers in the sandbox. However, when processing tar entries in OCI images, Boxlite does not account for the possibility that entries may be symlinks pointing to absolute paths. An attacker can craft a malicious OCI image and distribute it on image hosting platforms such as DockerHub, tricking users into using it. Once a user loads the malicious image, the attacker can write arbitrary content to any path on the host, which can further lead to remote code execution on the host.DetailsEntry Point — OCI Layer Tarball Extraction**File:** `boxlite/src/images/archive/tar.rs` **Function:** `extract_layer_tarball_streaming()` (line 24) **Code:****Issue:** The function passes the tar reader into `apply_oci_layer`. The tarball comes from a registry blob that has passed SHA256 integrity verification against the manifest digest — but the manifest itself is controlled by the registry, so a malicious registry can serve a valid manifest pointing to a crafted layer blob with a matching digest.Main Extraction Loop — Symlink Created Without Target Validation**File:** `boxlite/src/images/archive/tar.rs` **Function:** `apply_oci_layer()` (line 196) **Code:****Issue:** The symlink's `full_path` (the link itself) is sanitized by `normalize_entry_path` to stay within `dest`. However, the `target` (what the symlink points to) is never validated. An entry with path `usr` and link target `/etc` creates `{dest}/usr -> /etc`, a symlink pointing outside the extraction root. There is no check that `target` stays within `dest`, is relative, or doesn't escape the container root.Symlink Target Written Verbatim**File:** `boxlite/src/images/archive/tar.rs` **Function:** `create_symlink()` (line 747) **Code:****Issue:** `std::os::unix::fs::symlink` is an `lstat`-level operation — it creates the symlink with the provided target string verbatim, no matter what it contains. If `target` is `/etc`, the link records `/etc` as the target. No containment check.ensure_parent_dirs Deliberately Follows and Preserves Escape Symlinks**File:** `boxlite/src/images/archive/tar.rs` **Function:** `ensure_parent_dirs()` (line 457) **Code:****Issue:** When the next tar entry has path `usr/passwd` and the code calls `ensure_parent_dirs("{dest}/usr/passwd", dest)`, it walks up to `{dest}/usr`, finds it is a symlink pointing to a directory (e.g., `/etc`), and explicitly **breaks** the loop to preserve it — treating the out-of-root symlink as a valid, navigable parent. The `create_dir_all` call is then skipped for this path. The caller proceeds to open and write `{dest}/usr/passwd`, which the kernel resolves through the symlink to `/etc/passwd`.File Written Through Escaped Symlink**File:** `boxlite/src/images/archive/tar.rs` **Function:** `create_regular_file()` (line 715) **Code:****Issue:** `OpenOptions::open()` follows symlinks in path components by default. The kernel resolves `{dest}/usr/passwd` → `{dest}/usr` is a symlink to `/etc` → file opened at `/etc/passwd`. Attacker-controlled tar entry content is copied there verbatim.As seen from the code, when a tar entry is a symlink, Boxlite's security checks are insufficient. An attacker can exploit this vulnerability to achieve arbitrary file write once a user loads a maliciously crafted image. The write permission is consistent with the process privilege running the Boxlite service, which is commonly root on Linux. The attacker can further leverage this capability to achieve remote code execution, such as writing the attacker's public key into the host's authorized_keys.PoCInstall Boxlite following the official tutorial.Run the following Python script:This script constructs a malicious OCI image and passes it to the SimpleBox function via rootfs_path to create a container. In the malicious image, a symlink is first created pointing `escape` to `/tmp`, and then files are written under `escape`, thereby achieving file writes to the root filesystem.Sample output:ImpactAn attacker can craft a malicious OCI image and distribute it on image hosting platforms such as DockerHub, tricking users into using it. Once a user loads the malicious image, the attacker can write arbitrary content to any path on the host, which can further lead to remote code execution on the host.ScoreSeverity: Critical, Score: 9.7, rationale as follows:AV:N — The attacker can distribute the malicious image over the network, tricking users into pulling and using itAC:L — This is a logic vulnerability that requires no complex exploitationPR:N — The attacker does not need any additional privileges to exploit this vulnerabilityUI:R — The attacker needs to trick the victim into using the maliciously crafted imageS:C — The attacker can leverage the vulnerability to achieve arbitrary command execution on the host, extending the impact to the host operating system and crossing the security boundaryC:H/I:H/A:H — The attacker can leverage the vulnerability to gain RCE capability on the host, posing a significant threat to confidentiality, integrity, and availabilityCreditThis vulnerability was discovered by:XlabAI Team of Tencent Xuanwu LabAtuin Automated Vulnerability Discovery EngineCVE and credit are preferred.If you have any questions regarding the vulnerability details, please feel free to reach out to us for further discussion. Our email address is xlabai@tencent.com.NoteNote that we follow the industry-standard **90+30 disclosure policy** (Reference: https://googleprojectzero.blogspot.com/p/vulnerability-disclosure-policy.html). This means that we reserve the right to disclose the details of the vulnerability 30 days after the fix has been implemented.
CVSS v3.1: 9.6