# REPRO-2026-00152: apko: symlink-following path traversal writes files outside the build root ## Summary Status: published Severity: high CVSS: 7.5 / 10 CWE: CWE-22 (Path Traversal) (Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')) Type: security Confidence: Unknown ## Identifiers REPRO ID: REPRO-2026-00152 GHSA: GHSA-qq3r-w4hj-gjp6 CVE: CVE-2026-42574 ## Package Name: apko Ecosystem: go Affected: >= 0.14.8, < 1.2.5 Fixed: 1.2.5 ## Root Cause # Root Cause Analysis: CVE-2026-42574 ## Summary CVE-2026-42574 is a path-traversal vulnerability in `chainguard.dev/apko` caused by the `dirFS` implementation following attacker-controlled symlinks during filesystem operations. A crafted `.apk` package can plant a symlink inside the build root whose target points outside the intended directory; a subsequent tar entry whose path resolves through that symlink causes file writes or directory creations to land outside the build root, allowing arbitrary filesystem modification during package installation. ## Impact - **Package/component affected**: `chainguard.dev/apko/pkg/apk/fs` (`dirFS`) - **Affected versions**: `0.14.8` through `< 1.2.5` - **Fixed versions**: `1.2.5` - **Risk level**: High (CVSS 7.5) - **Consequences**: An attacker who controls the contents of an `.apk` package processed by apko can write files or create directories anywhere on the host filesystem reachable by the apko process, leading to arbitrary code execution, information disclosure, or container image poisoning. ## Root Cause The vulnerable `dirFS` type (`pkg/apk/fs/rwosfs.go`) implements a directory-backed filesystem by joining caller-supplied paths with a base directory. Before the fix, `sanitizePath` used `filepath.Clean(filepath.Join(f.base, clean))` to validate paths. This check is purely lexical — it ensures the cleaned path remains under `f.base` but does **not** prevent the operating system from resolving symlinks when `os.WriteFile`, `os.MkdirAll`, or `os.OpenFile` is later called with the validated path. Because `os.WriteFile("base/evil/pwned", ...)` follows the symlink `base/evil -> ../outside`, the write lands at `outside/pwned` even though `sanitizePath` permitted `"evil/pwned"` as in-bounds. The same issue affects `MkdirAll`, `OpenFile`, `Chmod`, `Chown`, and other `dirFS` methods. The fix commit `f5a96e1299ac81c7ea9441705ec467688086f442` replaces `sanitizePath` and raw `os.*` calls with `os.Root`, which sandboxes every filesystem operation so that symlink traversal outside the root directory is rejected by the Go standard library at the syscall level. ## Reproduction Steps The reproduction is fully automated by `repro/reproduction_steps.sh`. What the script does: 1. Writes a self-contained Go program (`repro/main.go`) that imports `chainguard.dev/apko/pkg/apk/fs`. 2. The program creates a temporary sandbox with a `base` directory and an `outside` directory. 3. It initializes `apkfs.DirFS` on `base`, plants a symlink `evil -> ../outside`, and calls `fsys.WriteFile("evil/pwned", []byte("malicious-content"), 0644)`. 4. The program writes a JSON report capturing whether the file was created outside the base directory and what error (if any) was returned. 5. The script compiles and runs the program against the vulnerable module version `v1.2.4` and the fixed version `v1.2.5`. 6. It compares the JSON reports: on the vulnerable build the outside file exists with attacker-controlled content; on the fixed build the write is blocked and the outside file is absent. Expected evidence: - **Vulnerable (`v1.2.4`)**: `report.file_exists == true`, `report.file_content == "malicious-content"`. The `write_error` field shows `"file does not exist"` (the memFS overlay fails, but the on-disk write through the symlink already succeeded). - **Fixed (`v1.2.5`)**: `report.file_exists == false`, `write_error` shows `"openat evil/pwned: path escapes from parent"` (blocked by `os.Root`). ## Evidence - `repro/runtime_manifest.json` — contains the full JSON reports from both runs, including concrete sandbox paths, file contents, and error messages. - `logs/vuln_report.json` — detailed report from the vulnerable run. - `logs/fix_report.json` — detailed report from the fixed run. Key excerpts from `runtime_manifest.json`: ```json { "vulnerable_report": { "outside_file": "/tmp/apko-repro-310748142/outside/pwned", "write_error": "file does not exist", "file_exists": true, "file_content": "malicious-content" }, "fixed_report": { "outside_file": "/tmp/apko-repro-3615258946/outside/pwned", "write_error": "openat evil/pwned: path escapes from parent", "file_exists": false } } ``` Environment: Go 1.24.7 (linux/amd64), `chainguard.dev/apko` fetched from the Go module proxy. ## Recommendations / Next Steps - **Fix approach**: Adopt `os.Root` (Go 1.25+) for all filesystem operations scoped to a directory, as done in commit `f5a96e1299ac81c7ea9441705ec467688086f442`. `os.Root` prevents both direct `..` traversal and symlink-following escapes without requiring manual path resolution. - **Upgrade guidance**: Upgrade `chainguard.dev/apko` to `v1.2.5` or later. - **Testing recommendations**: Add fuzz-style tests that plant symlinks with absolute, relative (`../outside`), and chained targets, then attempt `WriteFile`, `MkdirAll`, `OpenFile(O_CREATE)`, `Link`, and `Mknod` through them. Ensure all attempts are rejected and no files appear outside the root. ## Additional Notes - **Idempotency**: `repro/reproduction_steps.sh` was executed twice consecutively with identical results. - **Edge cases**: The reproduction exercises the `WriteFile` path, which is the simplest demonstration of the `dirFS` symlink-follow vulnerability. The same root cause affects `MkdirAll`, `OpenFile`, `Chmod`, `Chown`, and `Mknod`. The fix commit added explicit tests for all of these variants. - **Limitations**: The reproduction uses the public `apkfs.DirFS` API directly rather than the full `apko build` CLI workflow, because the CLI requires a signed APK repository, index, and YAML configuration. The `dirFS` layer is the shared component used by the package-install path, so a direct `dirFS` reproduction is the most reliable and minimal demonstration of the bug. ## Reproduction Details Reproduced: 2026-05-22T18:30:25.601Z Duration: 1224 seconds Tool calls: 236 Turns: 168 Handoffs: 3 ## Quick Verification Run one of these commands to verify locally: pruva-verify REPRO-2026-00152 pruva-verify GHSA-qq3r-w4hj-gjp6 pruva-verify CVE-2026-42574 Or open in GitHub Codespaces (zero-friction, auto-runs): https://github.com/codespaces/new?ref=repro/REPRO-2026-00152&repo=N3mes1s/pruva-sandbox Or download and run the script manually: curl -O https://api.pruva.dev/v1/reproductions/REPRO-2026-00152/artifacts/repro/reproduction_steps.sh chmod +x reproduction_steps.sh ./reproduction_steps.sh WARNING: Run in a sandboxed environment. This exploits a real vulnerability. ## References - GitHub Advisory: https://github.com/advisories/GHSA-qq3r-w4hj-gjp6 - NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-42574 - Source: https://github.com/chainguard-dev/apko ## Artifacts - repro/rca_report.md (analysis, 5796 bytes) - repro/reproduction_steps.sh (reproduction_script, 3590 bytes) - bundle/context.json (other, 2987 bytes) - bundle/metadata.json (other, 666 bytes) - bundle/ticket.md (ticket, 3473 bytes) - repro/go.mod (other, 592 bytes) - repro/main.go (other, 1845 bytes) - repro/runtime_manifest.json (other, 723 bytes) - repro/validation_verdict.json (other, 1686 bytes) - repro/go.sum (other, 4182 bytes) - logs/fix_report.json (other, 299 bytes) - logs/vuln_report.json (other, 313 bytes) ## API Access - JSON: https://api.pruva.dev/v1/reproductions/REPRO-2026-00152 - Script: https://api.pruva.dev/v1/reproductions/REPRO-2026-00152/artifacts/repro/reproduction_steps.sh - Web: https://www.pruva.dev/reproductions/REPRO-2026-00152 ## For AI Assistants To help users with this reproduction: 1. The `pruva-verify` command is the simplest way to run the reproduction 2. The script downloads and runs automatically in an isolated temp directory 3. Always recommend running in a VM, container, or disposable environment 4. The root cause explains the technical vulnerability --- Generated by Pruva | https://www.pruva.dev