Skip to main content

exarch

PyPI Python CI License

Memory-safe archive extraction and creation library for Python.

Important: exarch is designed as a secure replacement for vulnerable archive libraries like Python's tarfile, which has known CVEs with CVSS scores up to 9.4.

This package provides Python bindings for exarch-core, a Rust library with built-in protection against common archive vulnerabilities.

Installation

pip install exarch

Tip: Use uv pip install exarch for faster installation.

Alternative Package Managers

# Poetry
poetry add exarch

# Pipenv
pipenv install exarch

Requirements

  • Python >= 3.10

Quick Start

Extraction

import exarch

result = exarch.extract_archive("archive.tar.gz", "/output/path")
print(f"Extracted {result.files_extracted} files")

Creation

import exarch

result = exarch.create_archive("backup.tar.gz", ["src/", "Cargo.toml"])
print(f"Created archive with {result.files_added} files")

Usage

Basic Extraction

import exarch

result = exarch.extract_archive("archive.tar.gz", "/output/path")

print(f"Files extracted: {result.files_extracted}")
print(f"Bytes written: {result.bytes_written}")
print(f"Duration: {result.duration_ms}ms")

With pathlib.Path

from pathlib import Path
import exarch

archive = Path("archive.tar.gz")
output = Path("/output/path")

result = exarch.extract_archive(archive, output)

Custom Security Configuration

import exarch

config = exarch.SecurityConfig()
config = config.with_max_file_size(100 * 1024 * 1024)  # 100 MB

result = exarch.extract_archive("archive.tar.gz", "/output", config)

Verifying Payload Integrity

verify_archive checks security only by default and reports integrity_status as "SKIPPED". Opt in to decode the payload and verify checksums:

import exarch

options = exarch.VerificationOptions().with_integrity_check()  # 500 MiB budget
report = exarch.verify_archive("archive.zip", options=options)

print(report.integrity_status)  # "OK", "FAILED", "INCOMPLETE" or "SKIPPED"

Note: "INCOMPLETE" means part of the payload was not verified (budget, resource limit, solid 7z archive while allow_solid_archives is off, TAR without an end-of-archive marker); it comes with a Medium issue, so status is at least "WARNING". With the check on, a TAR entry whose content fails to decode raises InvalidArchiveError.

Error Handling

import exarch

try:
    result = exarch.extract_archive("archive.tar.gz", "/output")
    print(f"Extracted {result.files_extracted} files")
except exarch.PathTraversalError as e:
    print(f"Blocked path traversal: {e}")
except exarch.ZipBombError as e:
    print(f"Zip bomb detected: {e}")
except exarch.SecurityViolationError as e:
    # e.relaxable_by names the SecurityConfig setting that would admit the entry, or None
    print(f"Security violation ({e.relaxable_by}): {e}")
except exarch.ArchiveError as e:
    print(f"Extraction failed: {e}")

API Reference

extract_archive(archive_path, output_dir, config=None)

Extract an archive to the specified directory with security validation.

Parameters:

Name Type Description
archive_path str | Path Path to the archive file
output_dir str | Path Directory where files will be extracted
config SecurityConfig Optional security configuration

Returns: ExtractionReport

Attribute Type Description
files_extracted int Number of files extracted
directories_created int Number of directories created
symlinks_created int Number of symlinks created
bytes_written int Total bytes written
duration_ms int Extraction duration in milliseconds
files_skipped int Number of files skipped (e.g. duplicates)
warnings list[str] Warning messages generated during extraction

Raises:

Exception Description
PathTraversalError Path traversal attempt detected
SymlinkEscapeError Symlink points outside extraction directory
HardlinkEscapeError Hardlink target outside extraction directory
ZipBombError Potential zip bomb detected
QuotaExceededError Resource quota exceeded
SecurityViolationError Security policy violation
UnsupportedFormatError Archive format not supported
UnknownFormatError Archive format cannot be determined from path or magic bytes (subclass of UnsupportedFormatError)
InvalidArchiveError Archive is corrupted
IOError I/O operation failed

Note: Since v0.4.0, create_archive raises FileNotFoundError for missing sources, FileExistsError when the output already exists without overwrite, and ValueError for invalid compression levels — matching standard Python conventions.

extract_archive_with_progress(archive_path, output_dir, config, progress)

Extract an archive with a progress callback. The GIL is held when a callback is provided and released otherwise.

Parameters:

Name Type Description
archive_path str | Path Path to the archive file
output_dir str | Path Directory where files will be extracted
config SecurityConfig | None Optional security configuration
progress Callable[[str, int, int, int], None] | None Optional progress callback: (path, total_files, current_file, bytes_written)
import exarch


def on_progress(path: str, total: int, current: int, bytes_written: int) -> None:
    print(f"[{current}/{total}] {path} ({bytes_written} bytes)")


result = exarch.extract_archive_with_progress(
    "archive.tar.gz", "/output", config=None, progress=on_progress
)

If progress raises: extraction is not aborted early — the progress-callback contract has no cancellation signal, so extraction always runs to completion first, and progress is not called again for the remaining entries once it has raised. If extraction otherwise succeeded, progress's own exception propagates unchanged, with files_extracted/bytes_written attributes describing what was written and a progress_callback_error = True marker attribute (check this marker before treating the presence of files_extracted as a partial-extraction signal, since a genuine partial-extraction failure carries the same two attribute names). If extraction also failed, the extraction error takes priority — a raising progress can never mask a security error such as SymlinkEscapeError — and progress's exception is attached as __cause__ instead of being dropped. create_archive_with_progress behaves the same way, using files_added in place of files_extracted.

SecurityConfig

Builder-style security configuration.

config = exarch.SecurityConfig()
config = config.with_max_file_size(100 * 1024 * 1024)  # 100 MB per file
config = config.with_max_total_size(1024 * 1024 * 1024)  # 1 GB total
config = config.with_max_file_count(10_000)  # Max 10k files
config = config.with_max_compression_ratio(50.0)  # Zip bomb threshold
config = config.add_allowed_extension(".txt")  # Extension allowlist
config = config.add_allowed_extension(".md")
config = config.add_banned_component("__MACOSX")  # Skip components
config = config.with_allow_solid_archives(True)  # Allow solid 7z archives
config = config.with_zip_consistency(
    "ignore"
)  # ZIP structure policy: "enforce" (default) or "ignore"
config = config.with_parallel_decode_memory(
    256 * 1024 * 1024
)  # 7z LZMA2 lookahead memory (default 128 MiB); None decodes on one thread
# Each extract/verify call may start up to 16 worker threads and hold its own
# lookahead, so concurrent calls multiply both.

Security Features

The library provides built-in protection against:

Protection Description
Path traversal Blocks ../ and absolute paths
Symlink attacks Prevents symlinks escaping extraction directory
Hardlink attacks Validates hardlink targets
Zip bombs Detects high compression ratios
TAR metadata bombs Bounds GNU long-name/long-link and PAX header record reads
Permission sanitization Strips setuid/setgid bits
Size limits Enforces file and total size limits

Caution: Unlike Python's standard tarfile module, exarch applies security validation by default.

Supported Formats

Format Extensions Extract Create List Verify
TAR .tar ✅ ✅ ✅ ✅
TAR+GZIP .tar.gz, .tgz ✅ ✅ ✅ ✅
TAR+BZIP2 .tar.bz2, .tbz2 ✅ ✅ ✅ ✅
TAR+XZ .tar.xz, .txz ✅ ✅ ✅ ✅
TAR+ZSTD .tar.zst, .tzst ✅ ✅ ✅ ✅
ZIP .zip ✅ ✅ ✅ ✅
ZIP-family .jar, .war, .ear, .nar, .nbm, .apk, .aab, .ipa, .appx, .msix, .whl, .vsix, .xpi, .epub ✅ — ✅ ✅
7z .7z ✅ — ✅ ✅

Note: ZIP-family formats share the ZIP container but add extra structure (signing, checksum manifests, ordering rules) that exarch doesn't produce, so creation is rejected for those extensions. 7z creation is not yet supported. Solid and encrypted 7z archives are rejected for security reasons. A 7z archive holding a Windows reparse point is refused as a whole; a Unix S_IFLNK symlink is read and validated through the symlink policy, so it is created only with symlinks allowed, and a 7z FIFO, socket or device node is refused.

Comparison with tarfile

# UNSAFE - tarfile has known vulnerabilities (CVE-2007-4559)
import tarfile

with tarfile.open("archive.tar.gz") as tar:
    tar.extractall("/output")  # May extract outside target directory!

# SAFE - exarch validates all paths
import exarch

exarch.extract_archive("archive.tar.gz", "/output")  # Protected by default

Development

This package is built using PyO3 and maturin.

# Clone repository
git clone https://github.com/bug-ops/exarch
cd exarch/crates/exarch-python

# Build with maturin
pip install maturin
maturin develop

# Run tests
pytest tests/

License

Licensed under either of:

at your option.

Metadata

Release files for exarch 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for exarch 0.7.0
File Actions
exarch-0.7.0-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details for exarch-0.7.0-cp39-abi3-win_amd64.whl
exarch-0.7.0-cp39-abi3-musllinux_1_2_x86_64.whl CPython 3.9 abi3 Linux musl 1.2+ x86-64 Details for exarch-0.7.0-cp39-abi3-musllinux_1_2_x86_64.whl
exarch-0.7.0-cp39-abi3-musllinux_1_2_aarch64.whl CPython 3.9 abi3 Linux musl 1.2+ ARM64 Details for exarch-0.7.0-cp39-abi3-musllinux_1_2_aarch64.whl
exarch-0.7.0-cp39-abi3-manylinux_2_34_x86_64.whl CPython 3.9 abi3 Linux glibc 2.34+ x86-64 Details for exarch-0.7.0-cp39-abi3-manylinux_2_34_x86_64.whl
exarch-0.7.0-cp39-abi3-manylinux_2_34_aarch64.whl CPython 3.9 abi3 Linux glibc 2.34+ ARM64 Details for exarch-0.7.0-cp39-abi3-manylinux_2_34_aarch64.whl
exarch-0.7.0-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details for exarch-0.7.0-cp39-abi3-macosx_11_0_arm64.whl
exarch-0.7.0-cp39-abi3-macosx_10_12_x86_64.whl CPython 3.9 abi3 macOS 10.12+ x86-64 Details for exarch-0.7.0-cp39-abi3-macosx_10_12_x86_64.whl

Total release size: 12.9 MB

Release files / exarch-0.7.0-cp39-abi3-win_amd64.whl

Download URL exarch-0.7.0-cp39-abi3-win_amd64.whl
Size 1.7 MB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
2419fee38d896e3d8b44a20f0fc1acdf25e1d7c10f52bcdb4102dd863ae9e6c0
BLAKE2b-256 checksum
How to use checksums
7bd16f3d1202da6a69fb8b0c0d38074cc4bbfc03a4a7269e940f762634e83f71
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Release files / exarch-0.7.0-cp39-abi3-musllinux_1_2_x86_64.whl

Download URL exarch-0.7.0-cp39-abi3-musllinux_1_2_x86_64.whl
Size 2.1 MB
Tags CPython 3.9 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
87ff698f41942eb82e47b299f7ff7884322784484a18157d5715ff2904c49e51
BLAKE2b-256 checksum
How to use checksums
c9dae23b22dc4e7e90c7ed44d538ed6beaee3362b3e156f3842b5ca13c08f490
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Release files / exarch-0.7.0-cp39-abi3-musllinux_1_2_aarch64.whl

Download URL exarch-0.7.0-cp39-abi3-musllinux_1_2_aarch64.whl
Size 2.0 MB
Tags CPython 3.9 Linux musl 1.2+ ARM64 abi3
SHA-256 checksum
How to use checksums
ed8a1848deb7e9cc6990a0b41e2af909aaf5f586e3393ff1a617228e39806076
BLAKE2b-256 checksum
How to use checksums
04fc5e43b29c36cd03b5b48086e95012cbcc51326ad4985240409c9640e680dc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Release files / exarch-0.7.0-cp39-abi3-manylinux_2_34_x86_64.whl

Download URL exarch-0.7.0-cp39-abi3-manylinux_2_34_x86_64.whl
Size 1.9 MB
Tags CPython 3.9 Linux glibc 2.34+ x86-64 abi3
SHA-256 checksum
How to use checksums
342199fe8edfef9183415cc4e6a72d6015556fc8d472fadea903fc89fb166d44
BLAKE2b-256 checksum
How to use checksums
450f549a07fe7494edcd94e8d737c7abee0ef7feafc4bc2a49e02b35b3c0da84
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Release files / exarch-0.7.0-cp39-abi3-manylinux_2_34_aarch64.whl

Download URL exarch-0.7.0-cp39-abi3-manylinux_2_34_aarch64.whl
Size 1.8 MB
Tags CPython 3.9 Linux glibc 2.34+ ARM64 abi3
SHA-256 checksum
How to use checksums
7f47c33326f82eef62b2b9b03adc19c986229593ea2c7dae2e855a065ca73645
BLAKE2b-256 checksum
How to use checksums
d7762ab50e57dde15ce5731aabf75c3ce83b4ece235731aeba64f325e51d11b1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Release files / exarch-0.7.0-cp39-abi3-macosx_11_0_arm64.whl

Download URL exarch-0.7.0-cp39-abi3-macosx_11_0_arm64.whl
Size 1.7 MB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
2ff68b71fb4af41989b1cbbafc1afed4549cdf2dafa9a85f68069f9a91e89542
BLAKE2b-256 checksum
How to use checksums
20e40f747137e8eb2a9dcf74f07b70f3f38e6aa4414b41ad3f43076fe2fd6151
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Release files / exarch-0.7.0-cp39-abi3-macosx_10_12_x86_64.whl

Download URL exarch-0.7.0-cp39-abi3-macosx_10_12_x86_64.whl
Size 1.8 MB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
1d471adb6853e2a0e3aff2a0d9e2dd686c8c1b0b7742d78f52d309bc049dfe97
BLAKE2b-256 checksum
How to use checksums
7e7124a33f1c63f516af2f80bb9c21b1bc33542f591509850dee4308a75be791
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Security for exarch 0.7.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 7 files in this release have been uploaded with provenance metadata.

Select from 7 files

Attestation for exarch-0.7.0-cp39-abi3-win_amd64.whl

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page