Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Python tar preflight: reject links and path escapes before extraction

Last updated: 1 Oct 20265 min read
tutorial
IntermediateBy AITrove Editorial

Archive member metadata can contain parent traversal or links even when a tar stream parses successfully.

Download Python source kit

Operation contract

A report archive is allowed to contain regular files under a known folder. This program inspects names, rejects parent components and absolute paths, and refuses non-file members. It never extracts. In an actual ingestion path, apply a supported extraction filter, unpack into a fresh directory, and enforce member-count and total-size budgets while writing.

Failure and ownership boundary

Preflight metadata alone cannot stop a changing archive source or a race in a shared destination. Duplicate member names, case-insensitive collisions, decompression cost, and special files deserve separate checks. An extraction filter is a defense layer, not a complete quota or sandbox. This fixture makes no cross-platform extraction guarantee.

Working program

python
import io
import tarfile
from pathlib import PurePosixPath

archive_bytes = io.BytesIO()
with tarfile.open(fileobj=archive_bytes, mode="w") as archive:
    safe = tarfile.TarInfo("reports/quarter-47.txt")
    safe.size = 3
    archive.addfile(safe, io.BytesIO(b"47\n"))
    escape = tarfile.TarInfo("../outside.txt")
    escape.size = 0
    archive.addfile(escape, io.BytesIO())
    link = tarfile.TarInfo("reports/shortcut")
    link.type = tarfile.SYMTYPE
    link.linkname = "../outside.txt"
    archive.addfile(link)

archive_bytes.seek(0)
accepted = []
rejected = 0
with tarfile.open(fileobj=archive_bytes, mode="r:") as archive:
    for member in archive:
        name = PurePosixPath(member.name)
        if (not member.isfile() or not name.parts or name.is_absolute()
                or ".." in name.parts or name.parts[0] != "reports"):
            rejected += 1
        else:
            accepted.append(member.name)
print("accepted", accepted)
print("rejected", rejected)

Output

Output
accepted ['reports/quarter-47.txt']
rejected 2

Costs and limits

Preflight walks all members and stores only accepted names here. A real extractor must budget the bytes written and clean up a partial directory on failure.

Common Mistakes

  • A valid tar header does not make a member path safe.
  • Rejecting '..' in names does not alone solve link or destination races.
  • The data extraction filter does not enforce storage, CPU, or member-count budgets.

Connected lessons

Test this boundary.

Continue with Python tar extraction: reject members before exceeding a byte quota.

python
tar-member-preflight
Storage details