Zip Slip is a directory traversal vulnerability that occurs when software extracts files from a compressed archive—zip, tar, war, cpio, jar, or rar—without validating that the extracted file paths stay inside the intended target directory. An archive entry named ../../etc/cron.d/malicious or ..\..\..\Windows\System32\evil.dll will resolve outside the extraction folder on vulnerable code, letting an attacker overwrite system files, planted executables, or configuration used by the running application. Snyk's security research team publicly disclosed the pattern on June 5, 2018, after finding the same flawed extraction logic reused across more than 20 open-source libraries spanning Java, .NET, Go, and Ruby. Because so many frameworks, CI tools, and package managers extract archives as a routine operation, Zip Slip became one of the more widely propagated single-root-cause vulnerabilities in recent memory, and variants of it still surface in CVE databases every year.
How does a Zip Slip attack actually work?
A Zip Slip attack works by embedding relative path sequences (../) inside the filename field of an archive entry, then relying on extraction code that concatenates that filename directly onto a destination path without canonicalizing or bounds-checking the result. For example, a crafted zip might contain an entry literally named ../../../../home/deploy/.ssh/authorized_keys. When a vulnerable extractor calls something equivalent to new File(destDir, entry.getName()) and writes to it, Java's File constructor happily resolves the traversal, and the write lands outside destDir entirely. On Windows, the same trick works with backslashes and can target paths like ..\..\Startup\payload.exe to achieve persistence. Symlink-based variants go further: an archive can contain a symlink entry pointing outside the extraction root, so that a later, perfectly ordinary-looking file write follows the symlink and lands on a sensitive target such as /etc/passwd.
Why is Zip Slip so widespread across programming languages?
Zip Slip is widespread because the vulnerable pattern—trusting an archive's internal filenames during extraction—was copy-pasted or independently reimplemented across dozens of unrelated libraries rather than centralized in one place. Snyk's original 2018 audit found the flaw in libraries including Apache Ant, Apache Commons Compress, ZeroTurnaround's zt-zip, java-unrar, plexus-archiver, DotNetZip, and SharpCompress, and assigned a batch of CVEs in the CVE-2018-1002200 range to track fixes across the affected projects. Each of these libraries is a dependency embedded transitively in thousands of downstream applications, build plugins, and CI/CD tools, so a single unsafe extractEntry() function propagated the same bug into build systems, artifact repositories, and web frameworks that had no direct authorship connection to one another. This is the same "one bug, many consumers" dynamic seen later in Log4Shell (CVE-2021-44228) and the XZ Utils backdoor (CVE-2024-3094), and it is precisely why supply chain visibility into transitive dependencies matters as much as first-party code review.
What real-world software was affected by Zip Slip?
Real-world software affected by Zip Slip at disclosure included Java build and packaging tools, .NET compression libraries, and Go-based CLI utilities that all shipped an extraction routine missing a path-containment check. Because Apache Ant and Apache Commons Compress sit underneath countless Maven and Gradle build pipelines, any project that extracted a zip or tar during its build process inherited the flaw until it patched. Jenkins plugins that unpacked build artifacts, IDE plugin installers that unzipped extension packages, and CI runners that decompressed uploaded artifacts were all named as exposed use cases in the original research. Beyond the initial 2018 wave, the same root cause has resurfaced repeatedly: CVE-2021-29425 in Apache Commons IO, CVE-2020-9354 in Zip4j-adjacent tooling, and multiple container-image and Kubernetes-adjacent tooling advisories in 2022–2023 all describe path traversal during archive or layer extraction, showing the pattern never fully disappeared—it just kept getting reimplemented in new tools.
What's the difference between Zip Slip and a standard directory traversal vulnerability?
The difference is the delivery mechanism: standard directory traversal (CWE-22) typically abuses a URL parameter or file-upload field like ../../../etc/passwd to read or write a file directly through an application endpoint, while Zip Slip smuggles the traversal sequence inside archive metadata that gets processed later, during extraction, often in a completely different code path than the one that received the upload. A web application might correctly sanitize every user-facing file path parameter and still be vulnerable to Zip Slip if it later calls an archive library to unpack an uploaded .zip or .tar.gz without applying the same validation to the entries inside it. That gap—treating archive contents as trusted internal data rather than attacker-controlled input—is what let the vulnerability slip past code review in mature, otherwise well-secured projects for years before Snyk's audit named the pattern.
How can Zip Slip lead to remote code execution?
Zip Slip can lead to remote code execution when the attacker-controlled write target is a file the system will later execute, load, or interpret as trusted. Overwriting a cron entry in /etc/cron.d/, dropping a .jsp or .php file into a web server's document root, replacing a startup script in ~/.bashrc or a Windows Startup folder, or clobbering a .jar or .dll that gets loaded on next application restart all convert an arbitrary-file-write bug into code execution without needing a second vulnerability. In CI/CD contexts, extracting a malicious build artifact or plugin package can let an attacker overwrite a pipeline script or Jenkins plugin file, achieving execution inside the build agent itself—an especially valuable target because build agents typically hold signing keys, registry credentials, and deployment access.
How do you detect and fix Zip Slip vulnerabilities?
You detect Zip Slip by auditing every place your code or its dependencies extract an archive and checking whether the resolved output path is verified to remain inside the intended destination directory before the file is written. The canonical fix, which Snyk published alongside its 2018 disclosure, is to resolve each entry's absolute canonical path (destFile.getCanonicalPath() in Java, filepath.Clean plus a prefix check in Go, Path.GetFullPath in .NET) and reject the entry if that path does not start with the destination directory's canonical path. Modern archive libraries—Apache Commons Compress since 1.21, Go's archive/zip combined with manual validation, and Python's zipfile when paired with os.path.commonpath checks—now document this requirement explicitly, but plenty of custom extraction code written before 2018, or copied from Stack Overflow answers that predate the disclosure, still lacks the check. Dependency scanning alone often misses this because the vulnerable pattern can be hand-rolled application code rather than a flagged library version.
How Safeguard Helps
Safeguard's Griffin AI engine performs reachability analysis on archive-handling code paths to determine whether a flagged Zip Slip pattern—whether in a scanned dependency or in first-party extraction logic—is actually reachable from an attacker-controlled input such as a file upload endpoint or CI artifact ingestion path, cutting through noisy CVE alerts on libraries that are present but never invoked. Safeguard generates and ingests SBOMs across your build and container pipelines so every version of Apache Commons Compress, zt-zip, or similar archive libraries is inventoried and matched against known Zip Slip advisories the moment a new CVE lands. Where a fix is available, Safeguard opens an auto-fix pull request that bumps the dependency to a patched release or adds the canonical-path containment check directly to custom extraction code, so teams can close the gap without manually tracing every extractEntry() call in their codebase.