Archive Extraction Is a Filesystem Security Boundary

An archive extractor can receive a destination directory, join each stored name beneath it, and still write somewhere else. The gap appears when archive metadata is treated as harmless naming information even though extraction ultimately asks a filesystem to resolve paths, links, and object types with its own semantics.

The familiar ../ traversal is only the most visible form of the problem. Absolute paths, symbolic links, hard links, platform-specific path syntax, pre-existing filesystem objects, and replacement races can all affect where a write lands. A robust design therefore cannot reduce extraction safety to a string check performed once before files are created.

Archive names are untrusted path material

ZIP, tar, and similar formats preserve names for objects that are expected to reappear during extraction. Those names come from the archive, so an extractor handling untrusted input has to treat them as attacker-controlled path material.

A lexical traversal is straightforward: an entry such as ../../config attempts to escape the selected root. Normalizing a candidate path and confirming that it remains beneath the destination can reject this class of input, provided the check uses the target platform’s path rules and does not rely on naive string prefixes.

String prefixes are particularly fragile. A destination such as /srv/app is a prefix of /srv/application, but the latter is not inside the former. Path-component boundaries matter. On platforms with multiple separators, drive-qualified names, or other special path forms, validation also has to match the filesystem semantics used for the eventual operation.

Normalization is necessary, but it describes the path text rather than every object the filesystem may encounter while resolving that path.

Consider an archive containing a symbolic link named cache that points outside the extraction root, followed by a regular-file entry named cache/session.db. The second name can look lexically confined to the destination. If the extractor has already created the link and later opens the nested path using ordinary filesystem resolution, the write can follow that link outside the root.

This is a different mechanism from embedding .. directly in the file entry. The dangerous redirection lives in filesystem state established by an earlier entry.

Tar archives can represent symbolic and hard links directly. ZIP handling varies by producer and library, but Unix-origin metadata can be used to represent symbolic links in some ZIP archives. An extraction policy has to account for the actual object types exposed by the parser rather than assuming every entry becomes a regular file or directory.

Hard links deserve separate treatment. A hard link does not redirect path traversal in the same manner as a symbolic link; it creates another directory entry for an existing inode where the filesystem permits it. An extractor that supports archive hard-link records still needs to constrain link targets and ordering so archive metadata cannot create references beyond the intended extraction set.

The safest policy for many upload, package-inspection, and document-processing services is narrower than the archive format itself: accept directories and regular files, and reject link entries and special filesystem objects unless the application has a concrete need for them.

The destination can change during extraction

Even careful validation can become stale if checking and writing are separate operations against mutable filesystem state.

Suppose an extractor verifies that output/images/a.png is beneath its destination and later opens that path. Another process with access to the extraction tree may replace images with a symbolic link between those operations. The validated pathname has not changed, but its resolution has.

This is a time-of-check to time-of-use problem. Its practical relevance depends on who can modify the destination and on the filesystem interfaces available to the application. A private extraction directory that is inaccessible to other principals sharply reduces the race surface. A shared temporary tree or a destination writable by another tenant creates a much harder boundary.

Operating systems expose mechanisms that can make resolution more deliberate. On Linux, directory-relative operations and flags that refuse symbolic-link following can constrain individual opens; openat2 adds resolution controls such as keeping lookup beneath a supplied directory and rejecting selected link behavior. These controls have exact kernel and flag semantics, so applications should use well-maintained platform abstractions rather than approximate them with ad hoc path tests.

The broader point is architectural: confinement is strongest when the filesystem operation itself enforces the boundary, not when a prior string calculation merely predicts where that operation should go.

Extraction limits are part of the same trust decision

A path-confined archive can still be hostile.

Compressed data may expand far beyond its input size. An archive can contain huge numbers of tiny entries, deeply nested directory structures, duplicate names, sparse files, or metadata that consumes substantial processing and storage. The exact resource risks depend on the format and extractor, but path safety alone does not establish that extraction is safe to perform.

Production services commonly need explicit budgets for total expanded bytes, entry count, per-entry size, nesting or path depth, and elapsed work. Limits should be enforced as data is processed rather than only after extraction has consumed the resource being protected.

Declared sizes are useful signals but should not be treated as the sole accounting source. Parsers and formats differ in when size metadata is available and how trustworthy it is. Counting bytes actually written provides a stronger enforcement point for output-volume limits.

Duplicate paths also need a defined policy. Silently allowing later entries to replace earlier ones can make security inspection disagree with the final filesystem state if different stages observe different entries. Rejecting duplicates is often simpler for security-sensitive pipelines; applications that permit replacement need consistent semantics across validation, scanning, and use.

Temporary directories do not create isolation by themselves

Extracting into a fresh temporary directory is good hygiene, but the directory’s ownership and permissions determine how much isolation it provides. Predictable names, shared writable parents, inherited permissions, and later movement of extracted files can reintroduce exposure.

The lifecycle after extraction matters as much as the initial write. A service may safely unpack files into a private location, scan them, then copy selected output into a serving directory. If that promotion stage follows links, preserves unexpected metadata, or trusts paths recorded during the first stage without reopening them safely, the boundary has merely moved.

Security scanners also need to inspect the representation that downstream code will consume. Scanning archive bytes without considering extracted object types can miss filesystem effects; scanning extracted files and then transforming or re-extracting the archive creates a gap between inspected and used content.

A useful design keeps one controlled extraction result as the object of subsequent policy decisions, with clear ownership and no attacker-controlled mutation between inspection and consumption.

Format support should be narrower than parser capability

Archive libraries are often designed for compatibility. Security-sensitive applications have a different objective: accept only the features required by the product.

That can mean rejecting absolute names, traversal components, links, device nodes, FIFOs, sockets, unsupported metadata, duplicate destinations, and entries that exceed resource policy. It can also mean declining an entire archive format if the application cannot preserve its semantics safely on the target filesystem.

This narrower contract reduces the number of interactions that need to remain safe across parser behavior, operating-system path rules, filesystem state, and downstream processing. It also makes failures easier to reason about. An entry outside policy is rejected rather than coerced into a shape that appears convenient.

Archive extraction is therefore not merely decompression followed by file creation. It is a translation from attacker-controlled metadata into persistent filesystem effects. The security boundary holds only when the application constrains both sides of that translation: what the archive is allowed to express and what the filesystem is allowed to resolve.