This repository demonstrates a critical bug in tokio-tar and related async Rust
tar libraries where PAX extended header size overrides are not applied before
calculating the next header position.
Root Cause: When processing tar files with PAX extended headers that override the file size, the library uses the octal size field (often zero) instead of the PAX override for position calculations.
Impact: This causes the parser to jump into file content and mistake it for tar headers, leading to extraction of wrong files.
Known Affected Libraries:
async-tarhttps://github.com/dignifiedquire/async-tartokio-tarhttps://github.com/vorot93/tokio-tarkrata-tokio-tarhttps://github.com/edera-dev/tokio-tarastral-tokio-tarhttps://github.com/astral-sh/tokio-tar
# Requirements: CMake, Rust/Cargo, C++ compiler, system tar command
cmake -S . -B build
cmake --build build --target generate_reportThis will:
- Build all C++ and Rust tools
- Generate a repro case tar file
- Run comparisons showing the bug
- Generate detailed reports in
build/output/
├── disclosure/ # Security disclosure documentation tree
│ └── blast_radius/ # Record of projects depending on tokio-tar variants
├── repro_generator/ # C++ tool to generate a repro case tar file
├── tar-bug-detector/ # Rust tool comparing tar libraries
├── tarwalk/ # Correct C++ tar parser
│ ├── tarwalk.cpp # Handles PAX correctly
│ └── tarwalk_bad.cpp # Reproduces the same bug
├── CMakeLists.txt # Build system
├── generate_report.cmake # Report generation
└── README.md # This file
Header -> Content (size from octal field) -> Next Header
PAX Header (size=1024) -> File Header (octal size=0) -> Content (1024 bytes) -> Next Header
PAX Header (size=1024) -> File Header (octal size=0) -> Content (0 bytes) -> WRONG POSITION
↓
Reading content as headers!
Docker save creates tar files with:
- Large layers (>8GB) requiring PAX extensions
- Layer content starting with filesystem tar headers (
etc/,usr/) - When the bug triggers, parsers extract filesystem content instead of image manifests
pax_bug_compact.tar- Minimal reproduction case
Correct libraries (GNU tar, sync tar crate):
normal.txt -> blob.bin -> marker.txt
Buggy libraries (tokio-tar):
normal.txt -> blob.bin -> INNER_FILE -> marker.txt
The appearance of INNER_FILE indicates the bug - the library jumped into
blob.bin content and mistook a fake tar header for a real entry.
The fix requires applying PAX overrides before position calculations:
// Read header
let mut file_size = header.size();
// Apply PAX overrides BEFORE calculating next position
if let Some(pax_size) = pending_pax.get("size") {
file_size = pax_size.parse().unwrap();
}
// Now calculate next header position using effective size
let next_pos = current_pos + 512 + pad_to_512(file_size);This reproduction code is provided for security research and responsible disclosure purposes.
See COPYING for original source code license.
