An archive entry with a traversal path like ../../etc/cron.d writes outside the extraction root - confirming ZIP slip uses a nonce file landing check, not a read of any sensitive system path.
An archive entry with a filename like ../../etc/cron.d/backdoor writes outside the extraction directory. The vulnerability is not in the payload content - it is in the path. A file upload handler, a CI artifact unpacker, or a package installer that trusts entry paths without stripping traversal sequences is a write primitive handed to whoever controls the archive.
URL-path traversal (accessing ../../../etc/passwd via a file-read endpoint) and ZIP slip share a root cause but live in different layers. URL traversal is caught by application-layer input validation. ZIP slip is triggered at the moment the extraction library iterates archive entries - before any application logic runs, in code the application developer did not write. Library-level entry sanitization is the only reliable fix, and many versions of widely used libraries lacked it.
The natural impulse is to craft an archive that writes /etc/passwd and confirm by checking whether the response changes. That is a real exploit on a production host, not a probe. The confirming artifact that avoids it is a nonce path: craft an entry whose traversal sequence resolves to a writable but benign location you control - a temporary directory under the service account's home, a predictable side path within the application tree - and verify the landing rather than a system file.
import zipfile, os, tempfile # Build a probe archive with one traversal entry nonce = "62615533" # benign oracle marker target_rel = "../../tmp/apposture-probe-" + nonce + ".txt" with tempfile.NamedTemporaryFile(suffix=".zip", delete=False) as f: probe_path = f.name with zipfile.ZipFile(probe_path, "w") as zf: zf.writestr(target_rel, "apposture-nonce-" + nonce) # Upload probe_path to the target endpoint, then probe # for the nonce file at the expected resolved path. # A hit confirms the write; no system file was touched.
The endpoint under test receives an archive with one entry whose path traverses two directories above the extraction root. If the file lands at the resolved path and the nonce content is verifiable - via a separate read request, a directory listing endpoint, or an in-band include - the boundary is confirmed broken. If the library or the application strips the traversal before writing, the nonce never appears and the finding stays at reachable.
ZIP slip is named for the ZIP format but the vulnerability class applies to any archive format where entry paths are controlled by the archive creator. TAR is actually more dangerous because the specification permits absolute paths (entries starting with /) and symlinks, both of which a naive extractor passes through. JAR and WAR are ZIP files - Java application servers that auto-deploy dropped WARs are a historically exploited instance of this class. Each format has distinct probe mechanics because each has distinct path representation rules.
| Format | Traversal vector | Extra risk | Confirming probe |
|---|---|---|---|
| ZIP | Relative entry name with ../ sequences | None beyond path write | Nonce entry at resolved side path |
| TAR | Relative ../ or absolute / entry names; symlinks | Symlink to sensitive file read on extract | Nonce entry + symlink to writable self-path |
| JAR / WAR | ZIP format; auto-deploy triggers on landing | Code execution if server reloads dropped WAR | Nonce entry; watch for 404-to-200 after extract |
| 7z / RAR | Relative ../ in entry headers | Depends on extractor library version | Same nonce-path probe as ZIP |
A scanner that only probes ZIP files, or that only tests the Java servlet context, silently clears every other extraction surface. The probe adapts to the observed Content-Type and the extraction library fingerprint the application exposes in error responses or response headers.
An arbitrary write is not a single-severity finding. The severity is set by where the traversal sequence resolves and what the service account can write there. A nonce written to /tmp confirms the boundary failed but the impact is limited by the write target's role. The same mechanism pointed at a cron job directory, a git hook, a web root, or a configuration file the service reads on startup converts the write primitive into privilege escalation or code execution.
The fix is in the extraction layer, not the application layer: canonicalize each entry path against the extraction root before opening the destination file, and reject entries whose canonical path does not begin with that root. For TAR, also reject absolute paths and defer symlink resolution to after the full archive is extracted. No application-level input filter runs early enough to close this - the write happens inside the library call.