| name | archive-extraction-path-traversal |
| description | Security skill for detecting, testing, and mitigating archive extraction path traversal vulnerabilities (Zip-Slip, CVE-2025-8088, etc.). Use this skill whenever the user mentions archives (ZIP, RAR, TAR, 7-ZIP), file extraction, path traversal, zip-slip, archive security, or wants to test archive handling code. Also trigger when users ask about secure archive extraction, vulnerable code patterns, or creating security test cases for archive utilities. |
Archive Extraction Path Traversal Security
A comprehensive skill for understanding, detecting, and mitigating archive extraction path traversal vulnerabilities (commonly called "Zip-Slip").
What This Skill Does
- Detect vulnerable archive extraction code patterns
- Create PoC archives for security testing
- Analyze archive entries for suspicious paths
- Implement secure extraction patterns
- Understand real-world exploitation cases
Core Concepts
The Vulnerability
Archive formats (ZIP, RAR, TAR, 7-ZIP) allow each entry to carry its own internal path. When extraction utilities blindly trust these paths, crafted filenames containing .. or absolute paths can write files outside the intended directory.
Attack flow:
- Attacker creates archive with malicious entry paths (
../evil.exe or C:\Windows\payload.exe)
- Victim extracts with vulnerable tool
- File writes to attacker-controlled location
- If location is auto-run (Startup folder, cron), achieves RCE
Common Vulnerable Patterns
.NET Path.Combine + ZipArchive
using (var zip = ZipFile.OpenRead(zipPath))
{
foreach (var entry in zip.Entries)
{
var dest = Path.Combine(@"C:\samples\queue\", entry.FullName);
entry.ExtractToFile(dest);
}
}
Why it fails:
Path.Combine discards the left component if the right is absolute
- No path canonicalization before write
..\ sequences traverse outside destination
Go archiver.Unarchive()
archiver.Unarchive("exploit.zip", "/tmp/safe")
Python zipfile
import zipfile
with zipfile.ZipFile('archive.zip', 'r') as zf:
zf.extractall('/tmp/dest')
Creating Test Archives
Python: Create ZIP with Path Traversal
Use scripts/create_traversal_zip.py to generate test archives:
python scripts/create_traversal_zip.py \
--output test_traversal.zip \
--entry "../evil/payload.txt" \
--content "malicious content"
python scripts/create_traversal_zip.py \
--output test_absolute.zip \
--entry "C:\\Windows\\System32\\evil.dll" \
--content "payload"
python scripts/create_traversal_zip.py \
--output test_symlink.zip \
--symlink "/etc/passwd" \
--linkname "evil_link"
Bash: Create RAR with Path Traversal
mkdir -p "evil/../../../Users/Public/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup"
cp payload.exe "evil/../../../Users/Public/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup/"
rar a -ep evil.rar evil/*
The -ep flag preserves exact paths (doesn't prune leading ./).
Bash: Create ZIP with Symlink
mkdir -p out
ln -s /etc/cron.d evil
zip -y exploit.zip evil
Detection & Analysis
Analyze Archive Entries
Use scripts/analyze_archive.py to scan for suspicious entries:
python scripts/analyze_archive.py --file suspicious.zip
python scripts/analyze_archive.py --directory ./downloads/
python scripts/analyze_archive.py --file archive.zip --verbose
What it detects:
../ or ..\\ sequences
- Absolute paths (
/, C:, \\\\)
- Symlink entries pointing outside destination
- Null bytes or other obfuscation
Manual Detection Checklist
When reviewing archive extraction code, check for:
- Path canonicalization - Does code call
realpath(), PathCanonicalize(), or equivalent before write?
- Destination validation - After canonicalization, does the path still start with the intended destination?
- Symlink handling - Are symlinks extracted safely or blocked?
- Absolute path rejection - Are absolute paths in entries rejected?
- Sandbox extraction - Is extraction done in a disposable/sandboxed directory?
Secure Extraction Patterns
Python: Safe ZIP Extraction
import zipfile
import os
from pathlib import Path
def safe_extract(zip_path, dest_dir):
dest_dir = Path(dest_dir).resolve()
with zipfile.ZipFile(zip_path, 'r') as zf:
for entry in zf.infolist():
target_path = (dest_dir / entry.filename).resolve()
if not str(target_path).startswith(str(dest_dir)):
raise ValueError(f"Unsafe path: {entry.filename}")
if entry.external_attr >> 16 & 0xA000:
raise ValueError(f"Symlink not allowed: {entry.filename}")
zf.extract(entry, dest_dir)
Go: Safe Extraction Pattern
import (
"path/filepath"
"os"
)
func safeExtractEntry(destDir, entryName string) error {
destDir, err := filepath.Abs(destDir)
if err != nil {
return err
}
targetPath := filepath.Join(destDir, entryName)
targetPath, err = filepath.Abs(targetPath)
if err != nil {
return err
}
if !strings.HasPrefix(targetPath, destDir+string(os.PathSeparator)) {
return fmt.Errorf("path escapes destination: %s", entryName)
}
return extractToFile(targetPath, entry)
}
.NET: Safe Extraction Pattern
using System.IO;
using System.IO.Compression;
public static void SafeExtract(string zipPath, string destDir)
{
var dest = Path.GetFullPath(destDir);
using (var zip = ZipFile.OpenRead(zipPath))
{
foreach (var entry in zip.Entries)
{
var target = Path.GetFullPath(Path.Combine(dest, entry.FullName));
if (!target.StartsWith(dest, StringComparison.OrdinalIgnoreCase))
{
throw new SecurityException($"Path traversal detected: {entry.FullName}");
}
entry.ExtractToFile(target, true);
}
}
}
Real-World Cases
CVE-2025-8088: WinRAR ≤ 7.12
Impact: RCE via Startup folder
WinRAR failed to validate filenames during extraction. A malicious RAR with entry:
..\..\..\Users\victim\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\payload.exe
Would extract to the Startup folder, executing on next login.
Exploitation in the wild: RomCom (Storm-0978/UNC2596) used this for spear-phishing campaigns.
Fix: Update to WinRAR 7.13+
CVE-2025-11001: 7-Zip Symlink Traversal
Impact: RCE via cron/service locations
7-Zip 21.02–24.09 dereferenced symlinks during extraction, allowing escape from destination directory.
Fix: Update to 7-Zip 25.00+
CVE-2025-3445: Go mholt/archiver
Impact: Arbitrary file write
archiver.Unarchive() followed ../ and symlinked entries.
Fix: Switch to mholt/archives ≥ 0.1.0 or implement canonical-path checks.
Mitigation Strategies
1. Update Extractors
| Tool | Vulnerable | Fixed In |
|---|
| WinRAR | ≤ 7.12 | 7.13+ |
| 7-Zip | 21.02–24.09 | 25.00+ |
| Go archiver | ≤ 3.5.1 | Use mholt/archives ≥ 0.1.0 |
2. Safe Extraction Options
- 7-Zip: Use
-aoa (always overwrite) with path validation
- bsdtar: Use
--safe --xattrs --no-same-owner
- Unzip: Use
-o with pre-validation
3. Sandboxing
- Unix: Extract in chroot/namespace, drop privileges
- Windows: Use AppContainer or sandbox
- General: Extract to disposable directory, verify paths, then move
4. Code Review Checklist
References