The archiver npm package is a compression library for creating zip and tar streams, and its safe-usage story is mostly about understanding what it does not do: it builds archives, so the classic extraction risks like zip slip come from whatever you use to unpack them, not from archiver itself. That distinction is the single most useful thing to know before you audit a codebase that depends on it.
npm archiver is one of the most widely used Node.js libraries for producing archives programmatically — generating a downloadable zip of user files, bundling logs, packaging build artifacts. It streams output, which keeps memory flat even for large archives. Understanding its actual role keeps you from chasing the wrong threats.
What archiver does, and what it does not
The core API is deliberately narrow. You create an archive, append files or streams, and pipe the result somewhere:
const fs = require("fs");
const archiver = require("archiver");
const output = fs.createWriteStream("output.zip");
const archive = archiver("zip", { zlib: { level: 9 } });
archive.pipe(output);
archive.file("report.pdf", { name: "report.pdf" });
archive.directory("logs/", "logs");
archive.finalize();
That is the whole shape of it: input files in, archive stream out. Archiver does not extract archives. So the most notorious archive vulnerability class — zip slip — is not something archiver's creation path exposes on its own. Zip slip is an extraction problem: a malicious archive contains an entry named something like ../../etc/passwd, and a careless extractor writes outside the intended directory. If your app only creates archives with archiver, that particular attack does not apply to your use of it.
This matters because security scanners and blog posts sometimes lump all archive libraries together. Read advisories carefully and match them to the function you actually call.
Where the real risk lives
Three areas deserve attention when you depend on npm archiver:
The extraction library you pair it with. Most apps that create archives also unpack them somewhere, using a different package (unzipper, adm-zip, tar, and others). That is where zip slip and path traversal bite. If you accept uploaded archives and extract them, validate every entry path before writing:
const path = require("path");
function safeJoin(base, entryName) {
const target = path.resolve(base, entryName);
if (!target.startsWith(path.resolve(base) + path.sep)) {
throw new Error("Path traversal detected: " + entryName);
}
return target;
}
The transitive dependency tree. Archiver pulls in compression and stream helpers, and over the years advisories have surfaced in that tree rather than in archiver's own code. Audit the full resolution, not just the top-level name:
npm ls archiver
npm audit --omit=dev
An SCA tool such as Safeguard can flag a vulnerable transitive dependency of archiver even when archiver itself is clean, which is the common case for mature creation libraries.
Resource exhaustion. Because archiver streams data you feed it, an endpoint that lets users trigger archive creation over arbitrary inputs can be pushed into heavy CPU and disk use with high compression levels. Bound the number of files, total size, and concurrency of any user-triggered archive operation.
Safe patterns for creating archives
A few habits keep archive creation from becoming a liability:
- Control the entry names you write. If filenames inside the archive come from user input, sanitize them. A user-controlled name like
../secretinside an archive you generate becomes a zip-slip payload for whoever extracts it downstream — you would be producing the malicious archive. - Do not archive paths blindly. When appending a directory, be explicit about what goes in. Accidentally including a
.envor a credentials file in a downloadable zip is a real and common leak. - Set sane compression. Level 9 maximizes ratio but costs CPU. For user-facing endpoints, a middle level plus rate limiting is usually the right trade.
- Handle errors on the stream. Attach an
errorhandler to the archive and the output stream; an unhandled stream error can crash a Node process.
archive.on("error", (err) => {
// log and fail the request cleanly
throw err;
});
archive.on("warning", (err) => {
if (err.code !== "ENOENT") throw err;
});
Keeping the dependency healthy
Archiver is actively maintained and widely depended upon, which is a good sign, but "popular" is not "safe forever." Pin your version, commit the lockfile, and re-audit on a schedule rather than trusting a one-time green scan. When a transitive advisory appears, the fix is usually a straightforward npm update followed by re-checking the resolved tree — occasionally an overrides entry if the fixed version has not propagated up to archiver's own release yet. Our SCA product overview explains how transitive fixes and overrides interact if you need the mechanics.
FAQ
Is the archiver npm package affected by zip slip?
Zip slip is an extraction-time vulnerability, and archiver creates archives rather than extracting them, so its creation path does not expose zip slip on its own. The risk applies to whatever library you use to unpack archives. That said, if user input controls the entry names archiver writes, you could produce a malicious archive that harms a downstream extractor.
Does archiver have known CVEs?
Archiver's own creation code has a clean record for most releases, but advisories have appeared in its transitive dependency tree over time. Audit the resolved tree with npm ls archiver and npm audit rather than trusting the top-level name, since that is where issues typically surface.
How do I extract archives safely alongside archiver?
Use a dedicated extraction library and validate every entry path before writing to disk. Resolve each target path and confirm it stays within the intended base directory, rejecting anything that escapes it. That check is your primary defense against zip slip and path traversal.
Can archive creation be a denial-of-service risk?
Yes, if users can trigger it over arbitrary inputs. High compression levels and large or numerous files consume CPU and disk. Bound file counts, total size, and concurrency, and rate-limit any user-facing endpoint that creates archives.