exarch-rs
v0.2.2
Published
Memory-safe archive extraction library with built-in security validation
Downloads
925
Maintainers
Readme
exarch-rs
Memory-safe archive extraction and creation library for Node.js.
[!IMPORTANT] exarch is designed as a secure replacement for vulnerable archive libraries like
tar-fs, which has known CVEs with CVSS scores up to 9.4.
This package provides Node.js bindings for exarch-core, a Rust library with built-in protection against common archive vulnerabilities.
Installation
# npm
npm install exarch-rs
# yarn
yarn add exarch-rs
# pnpm
pnpm add exarch-rs
# bun
bun add exarch-rs[!NOTE] This package includes TypeScript definitions. No need for separate
@typespackage.
Requirements
- Node.js >= 18
Quick Start
Extraction
const { extractArchive } = require('exarch-rs');
// Async (recommended)
const result = await extractArchive('archive.tar.gz', '/output/path');
console.log(`Extracted ${result.filesExtracted} files`);Creation
const { createArchive } = require('exarch-rs');
// Async (recommended)
const result = await createArchive('backup.tar.gz', ['src/', 'package.json']);
console.log(`Created archive with ${result.filesAdded} files`);Usage
Async API (Recommended)
const { extractArchive } = require('exarch-rs');
const result = await extractArchive('archive.tar.gz', '/output/path');
console.log(`Files extracted: ${result.filesExtracted}`);
console.log(`Bytes written: ${result.bytesWritten}`);
console.log(`Duration: ${result.durationMs}ms`);Sync API
const { extractArchiveSync } = require('exarch-rs');
const result = extractArchiveSync('archive.tar.gz', '/output/path');
console.log(`Extracted ${result.filesExtracted} files`);[!TIP] Prefer the async API to avoid blocking the event loop during extraction.
ES Modules
import { extractArchive } from 'exarch-rs';
const result = await extractArchive('archive.tar.gz', '/output/path');TypeScript
import { extractArchive, SecurityConfig, ExtractionReport } from 'exarch-rs';
const result: ExtractionReport = await extractArchive('archive.tar.gz', '/output/path');
console.log(`Extracted ${result.filesExtracted} files`);Custom Security Configuration
import { extractArchive, SecurityConfig } from 'exarch-rs';
const config = new SecurityConfig()
.maxFileSize(100 * 1024 * 1024) // 100 MB per file
.maxTotalSize(1024 * 1024 * 1024) // 1 GB total
.maxFileCount(10_000); // Max 10k files
const result = await extractArchive('archive.tar.gz', '/output', config);Error Handling
const { extractArchive } = require('exarch-rs');
try {
const result = await extractArchive('archive.tar.gz', '/output');
console.log(`Success: ${result.filesExtracted} files`);
} catch (error) {
// Error codes: PATH_TRAVERSAL, SYMLINK_ESCAPE, ZIP_BOMB, QUOTA_EXCEEDED, etc.
console.error(`Extraction failed: ${error.message}`);
}API
extractArchive(archivePath, outputDir, config?)
Extract an archive asynchronously with security validation.
Parameters:
| Name | Type | Description |
|------|------|-------------|
| archivePath | string | Path to the archive file |
| outputDir | string | Directory where files will be extracted |
| config | SecurityConfig | Optional security configuration |
Returns: Promise<ExtractionReport>
extractArchiveSync(archivePath, outputDir, config?)
Synchronous version. Blocks the event loop until extraction completes.
Returns: ExtractionReport
ExtractionReport
interface ExtractionReport {
filesExtracted: number; // Number of files extracted
bytesWritten: number; // Total bytes written
durationMs: number; // Extraction duration in milliseconds
}SecurityConfig
Builder-style security configuration.
const config = new SecurityConfig()
.maxFileSize(bytes) // Max size per file
.maxTotalSize(bytes) // Max total extraction size
.maxFileCount(count) // Max number of files
.maxCompressionRatio(n); // Max compression ratio (zip bomb detection)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 |
| Permission sanitization | Strips setuid/setgid bits |
| Size limits | Enforces file and total size limits |
[!CAUTION] Unlike many Node.js archive libraries, exarch applies security validation by default.
Supported Formats
| Format | Extensions | Extract | Create |
|--------|------------|:-------:|:------:|
| TAR | .tar | ✅ | ✅ |
| TAR+GZIP | .tar.gz, .tgz | ✅ | ✅ |
| TAR+BZIP2 | .tar.bz2, .tbz2 | ✅ | ✅ |
| TAR+XZ | .tar.xz, .txz | ✅ | ✅ |
| TAR+ZSTD | .tar.zst, .tzst | ✅ | ✅ |
| ZIP | .zip | ✅ | ✅ |
| 7z | .7z | ✅ | — |
[!NOTE] 7z creation is not yet supported. Solid and encrypted 7z archives are rejected for security reasons.
Comparison with tar-fs
// UNSAFE - tar-fs has known vulnerabilities
const tar = require('tar-fs');
const fs = require('fs');
fs.createReadStream('archive.tar')
.pipe(tar.extract('/output')); // May extract outside target directory!
// SAFE - exarch-rs validates all paths
const { extractArchive } = require('exarch-rs');
await extractArchive('archive.tar', '/output'); // Protected by defaultDevelopment
This package is built using napi-rs.
# Clone repository
git clone https://github.com/bug-ops/exarch
cd exarch/crates/exarch-node
# Install dependencies
npm install
# Build native module
npm run build
# Run tests
npm testRelated Packages
- exarch-core — Core Rust library
- exarch (PyPI) — Python bindings
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT License (LICENSE-MIT)
at your option.
