tarfile.extractall() Path Traversal Still Not Blocked By Default (tested)
A tar archive can contain a member whose name is ../outside.txt. We measured what tarfile.extractall() does with one of those in Python 3.13.5: it writes the file wherever the .. points, outside the folder you asked it to extract to, with no exception — just a warning easy to miss.
1. A tar member can name a path outside the extraction dir
import tarfile, io
with tarfile.open("evil.tar", "w") as tf:
data = b"pwned"
info = tarfile.TarInfo(name="../outside.txt")
info.size = len(data)
tf.addfile(info, io.BytesIO(data))
Measured: tarfile happily writes a member named ../outside.txt into the archive. Nothing about creating the tar stops this — the danger is entirely on the extraction side.
2. extractall() with no filter writes outside the destination, silently
import tarfile
with tarfile.open("evil.tar") as tf:
tf.extractall("extract_dir")
<string>:1: DeprecationWarning: Python 3.14 will, by default, filter extracted tar
archives and reject files or modify their metadata. Use the filter argument to
control this behavior.
Measured: the call completes with no exception. Checking the filesystem afterward, outside.txt exists next to extract_dir, not inside it — extractall() followed the .. straight out of the destination. The only signal anything is wrong is a DeprecationWarning, which most scripts never print or notice, and nothing raises at runtime.
3. zipfile, for contrast, already strips the ".." by default
import zipfile
with zipfile.ZipFile("evil.zip", "w") as zf:
zf.writestr("../outside_zip.txt", "pwned")
with zipfile.ZipFile("evil.zip") as zf:
zf.extractall("extract_dir2")
Measured: with the identical ../outside_zip.txt member name, zipfile.extractall() strips the leading .. component and writes outside_zip.txt inside extract_dir2 — no file lands outside the destination, no warning either. zipfile and tarfile handle the exact same attack shape differently; code that extracts both archive types the same way is only safe for one of them.
4. Fix: pass filter="data" (or "tar") explicitly
with tarfile.open("evil.tar") as tf:
tf.extractall("extract_dir3", filter="data")
tarfile.OutsideDestinationError: '../outside.txt' would be extracted to
'/tmp/.../outside.txt', which is outside the destination
Measured: with filter="data", the same archive now raises tarfile.OutsideDestinationError during extraction and no file is written outside extract_dir3. filter="data" (added in 3.12, per the docs) also strips absolute paths, device files, and ownership/permission bits that could affect files outside the archive. Per the docs, Python 3.14 is planned to make "data" the default — until then, on 3.12/3.13 you must pass it yourself, every call.
5. Why this matters
Any code that extracts a tar file someone else produced — a user upload, a package download, a CI artifact — is extracting attacker-controlled member names. Without filter="data", a crafted archive can overwrite files anywhere the extracting process can write, not just inside the folder you intended. This is the long-standing tar path-traversal issue (sometimes called "Tarslip"); it predates Python and affects any extractor that trusts member names, but tarfile itself still requires you to opt in to the safe behavior on 3.12 and 3.13.
Frequently asked questions
Does tarfile.extractall() check for '../' in member names by default?
No -- in our Python 3.13.5 test, extractall() with no filter argument wrote a '../outside.txt' member outside the destination directory with no exception, only a DeprecationWarning.
Is zipfile safe from the same path traversal?
We measured zipfile.extractall() stripping the leading '../' from an identical member name and writing the file inside the destination directory -- tarfile and zipfile behave differently for the same attack.
How do I make tarfile.extractall() safe?
Pass filter="data" explicitly. We confirmed it raises tarfile.OutsideDestinationError for a '../' member instead of writing outside the destination, and per the docs also strips dangerous metadata like device files and absolute paths.
Will Python block this automatically in the future?
Per the tarfile docs, Python 3.14 is planned to make the 'data' filter the default. On 3.12 and 3.13, the DeprecationWarning is the only hint -- you still have to pass filter yourself to get the safe behavior.
Is this only a risk for archives from the internet?
Any tar file whose contents you didn't fully control when it was created is a risk -- user uploads, third-party downloads, or anything passed through a pipeline you don't fully trust. We only tested a hand-crafted local archive, but the same member-name mechanism applies regardless of source.
Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in tarfile module: built a .tar containing one member named '../outside.txt', extracted it with extractall() using no filter argument and again with filter='data', and checked whether the file landed outside the destination directory. Compared against zipfile with the same '../' member name for contrast. PlainHeaders is our extension; Python's tarfile and zipfile modules are built in.