Loading workspace insights... Statistics interval
7 days30 daysLatest CI Pipeline Executions
ad296578 fix(core): prevent path traversal / zip-slip in self-hosted remote cache (#36116)
## Current Behavior
The self-hosted HTTP remote cache extracts and restores artifacts
without
containment:
- Extraction joins untrusted tar entry names onto the cache directory
and unpacks
them with tar's unguarded `Entry::unpack()`, which performs no boundary
check.
- Restore copies the **entire** cache directory into the workspace and
recreates
entries while following symlinks, and clears prior outputs with a delete
that
follows symlinks.
A malicious — or on-path/MITM'd — `NX_SELF_HOSTED_REMOTE_CACHE_SERVER`
can craft a
tarball whose entries (`../`, absolute paths, or symlinks/hardlinks)
escape the
cache directory / workspace and write to arbitrary locations the Nx
process can
reach. That arbitrary file write becomes RCE by targeting files like
`~/.ssh/authorized_keys`, a git hook, or `~/.zshrc`. Several
malformed-input cases
also panic the process, and a remote-cached exit code is decoded from
only the
first 2 of its 4 stored bytes (so a nonzero code can restore as `0`).
## Expected Behavior
- **Extraction is contained** via tar's `unpack_in`: `..` entries are
rejected,
absolute paths are stripped to relative, and writes *through*
symlinks/hardlinks
are refused — nothing escapes `<cacheDir>/<hash>`.
- **Restore copies only the declared task outputs** (never the whole
cache dir),
each confined to the workspace root. Parent directories are realized as
real
directories, so a write never traverses a symlink; symlinks are
recreated
verbatim (the pointer is allowed — writing *through* it is not); stale
destinations are removed without following symlinks.
- **Declared outputs that resolve outside the workspace are rejected**
with a clear
error (both when storing and restoring).
- **Malformed artifacts error instead of panicking** — unreadable
response body,
short/missing exit-code entry, and non-UTF8 entry names (the last only
surfaced
on Windows).
- **The exit code is read from all 4 stored bytes**, fixing a nonzero
code being
restored as `0`.
- Adds extensive native tests: parent-dir traversal, absolute-path
containment,
symlink/hardlink write-through rejection, restore confined to declared
outputs,
symlink-not-followed / write-through-blocked, out-of-workspace output
rejection,
malformed/short/missing exit code, and exit-code round-trip.
## Related Issue(s)
NXC-4593 — self-hosted HTTP remote cache path traversal
<!-- polygraph-session-start -->
---
[View session information
↗](https://app.trypolygraph.com/orgs/6a061dcb561c062131116eca/sessions/lucid-sparrow-3e44e727)
<!-- polygraph-session-end -->
---------
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> ad296578 fix(core): prevent path traversal / zip-slip in self-hosted remote cache (#36116)
## Current Behavior
The self-hosted HTTP remote cache extracts and restores artifacts
without
containment:
- Extraction joins untrusted tar entry names onto the cache directory
and unpacks
them with tar's unguarded `Entry::unpack()`, which performs no boundary
check.
- Restore copies the **entire** cache directory into the workspace and
recreates
entries while following symlinks, and clears prior outputs with a delete
that
follows symlinks.
A malicious — or on-path/MITM'd — `NX_SELF_HOSTED_REMOTE_CACHE_SERVER`
can craft a
tarball whose entries (`../`, absolute paths, or symlinks/hardlinks)
escape the
cache directory / workspace and write to arbitrary locations the Nx
process can
reach. That arbitrary file write becomes RCE by targeting files like
`~/.ssh/authorized_keys`, a git hook, or `~/.zshrc`. Several
malformed-input cases
also panic the process, and a remote-cached exit code is decoded from
only the
first 2 of its 4 stored bytes (so a nonzero code can restore as `0`).
## Expected Behavior
- **Extraction is contained** via tar's `unpack_in`: `..` entries are
rejected,
absolute paths are stripped to relative, and writes *through*
symlinks/hardlinks
are refused — nothing escapes `<cacheDir>/<hash>`.
- **Restore copies only the declared task outputs** (never the whole
cache dir),
each confined to the workspace root. Parent directories are realized as
real
directories, so a write never traverses a symlink; symlinks are
recreated
verbatim (the pointer is allowed — writing *through* it is not); stale
destinations are removed without following symlinks.
- **Declared outputs that resolve outside the workspace are rejected**
with a clear
error (both when storing and restoring).
- **Malformed artifacts error instead of panicking** — unreadable
response body,
short/missing exit-code entry, and non-UTF8 entry names (the last only
surfaced
on Windows).
- **The exit code is read from all 4 stored bytes**, fixing a nonzero
code being
restored as `0`.
- Adds extensive native tests: parent-dir traversal, absolute-path
containment,
symlink/hardlink write-through rejection, restore confined to declared
outputs,
symlink-not-followed / write-through-blocked, out-of-workspace output
rejection,
malformed/short/missing exit code, and exit-code round-trip.
## Related Issue(s)
NXC-4593 — self-hosted HTTP remote cache path traversal
<!-- polygraph-session-start -->
---
[View session information
↗](https://app.trypolygraph.com/orgs/6a061dcb561c062131116eca/sessions/lucid-sparrow-3e44e727)
<!-- polygraph-session-end -->
---------
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>