A vendor drops a .rar into a support inbox, your CI expects a ZIP or a tarball, and the first library you try either cannot open it, cannot take the password, or writes files somewhere you did not ask for. The extension looks simple. The format is not.
I built rar.now because I kept hitting that mismatch in hand-offs and build pipelines, and I am the site's maker, so I will be explicit about that. Here is how to handle RAR archives in 2026 without surprises.
RAR4 and RAR5 are not the same format
Both use the .rar extension, and they are incompatible on disk. WinRAR has defaulted to RAR5 since 2013 and writes RAR4 only if you ask it to; older RAR4-only tools will reject a current archive. Tell them apart by the signature, not the filename:
| RAR4 | RAR5 | |
|---|---|---|
| Signature | 52 61 72 21 1A 07 00 |
52 61 72 21 1A 07 01 00 |
| Names | OEM / Unicode | UTF-8 |
| File checksum | CRC-32 | CRC-32 or BLAKE2sp |
| Encryption | AES-128 | AES-256 (PBKDF2-HMAC-SHA256) |
| Dictionary | up to 4 MB | up to 1 GB; up to 64 GB in RAR 7.0 |
function rarVersion(buf) {
if (buf.length < 7) return null;
const rar4 = Buffer.from([0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00]);
const rar5 = Buffer.from([0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00]);
if (buf.subarray(0, 8).equals(rar5)) return 5;
if (buf.subarray(0, 7).equals(rar4)) return 4;
return null;
}
Do not trust file.type. Browsers often send application/octet-stream, or flip between application/x-rar-compressed and application/vnd.rar. Read the first eight bytes on the server.
Encrypted headers hide the file list until you have the password. Solid archives compress files as one stream, so extracting one entry can mean decompressing everything before it, and some libraries fail on solid RAR4. A RAR 7.0 dictionary larger than 4 GB needs UnRAR 7.0 or newer. Windows 11 File Explorer can extract unencrypted RAR files from 23H2 onward, but encrypted archives, repair, and creation still need a dedicated tool. macOS and most CI images have no built-in RAR extractor.
You can extract RAR. You generally cannot create it
RAR is proprietary. Only WinRAR and RARLAB's commercial rar CLI write a compatible archive. RARLAB publishes UnRAR source, which you may use to extract — including in commercial products — but the license forbids using that code to build a RAR-compatible archiver. It is not an OSI open-source license.
-
UnRAR (the official library or
unrarCLI) opens RAR4 and RAR5, including encrypted archives, volumes, and large dictionaries. -
libarchive (and therefore
bsdtar, plus Windows 11's built-in extractor) reads RAR4 and RAR5 under a BSD license. It does not decrypt password-protected RAR, and it does not extract solid RAR4. Solid RAR5 works. -
7-Zip extracts RAR4 and RAR5 (RAR5 since version 15.06). Its RAR decompressor is based on UnRAR source and carries the same "no archiver" restriction. On Debian and Ubuntu, RAR support often lives in a separate
7zip-rarpackage for that reason.
If your pipeline needs an archive you can create and read everywhere, convert to ZIP, 7Z or TAR after extraction. Do not plan to emit .rar from application code.
Node and Python: pick a backend on purpose
Python. rarfile is the usual choice. It parses the archive in Python and shells out to an external tool for compressed entries: unrar (best), 7z, unar, or bsdtar. The backend on PATH decides what actually works. bsdtar inherits libarchive's limits: no passwords, no solid archives, and no multi-volume support. Install unrar in CI if you need the full format.
import rarfile
rf = rarfile.RarFile("bundle.rar")
# rf.needs_password() — call rf.setpassword(...) before extract
for info in rf.infolist():
print(info.filename, info.file_size, info.is_dir())
Node.js. There is no blessed standard-library extractor. node-unrar-js embeds official UnRAR compiled to WebAssembly, so it handles RAR4 and RAR5, Unicode names, and passwords without a native toolchain. It does not support multi-volume archives. Keep the UnRAR license in mind: the npm wrapper is MIT, the decoder it ships is still UnRAR. Calling 7z or unrar from a worker is often clearer in production than bundling WASM.
List first, extract second. Look at filenames, unpacked sizes, encryption flags and volume markers before you write anything.
Multipart volumes and recovery records
A large archive may be split into volumes. Current sets are usually named name.part1.rar, name.part2.rar; older RAR4 sets use name.rar, name.r00, name.r01. Open the first volume; tools locate the rest by name, in the same directory. Copy every volume, including any .rev recovery volumes, before you extract.
RAR can also store a recovery record inside the archive, and optionally separate .rev files, so a tool can rebuild a limited amount of damage — RAR5 uses Reed-Solomon data for this. Test before you extract: unrar t bundle.rar checks headers and payload checksums (CRC-32, or BLAKE2sp on some RAR5 archives). Repair is a different operation. The free unrar binary tests and extracts; rebuilding a damaged archive is a job for WinRAR, the commercial rar r command, or a repair tool, and it only has a chance when recovery data is present.
Extract untrusted archives as if they are hostile
Zip Slip is not a ZIP-only bug. Snyk documented the same path-traversal pattern in RAR, 7z and TAR extractors: an entry named ../../etc/cron.d/x will leave the destination directory if you naively join and write. Archive bombs are the other failure mode: a small file that expands to gigabytes, or thousands of entries. Nested archives only become a problem if your code opens them again.
Treat every untrusted RAR like this:
- Extract into a fresh directory you created, not an existing tree that may already contain symlinks or junctions.
- Resolve each destination path and reject it unless it stays inside that directory. Checking the raw name for
..is not enough: absolute paths and already-present symlinks will bypass a string filter. - Cap entry count, per-file unpacked size, total unpacked bytes, and path depth. Trust a running byte count, not only the header — a lying header is part of the attack.
- Refuse symlink and hardlink entries unless you have a reason to honor them, do not extract as root, and do not overwrite files outside the job.
import path from "node:path";
export function safeJoin(destDir, entryName) {
const root = path.resolve(destDir);
const target = path.resolve(root, entryName);
const prefix = root.endsWith(path.sep) ? root : root + path.sep;
if (target !== root && !target.startsWith(prefix)) {
throw new Error(`refusing path traversal: ${entryName}`);
}
return target;
}
A conversion pipeline should do the same work: extract safely to a staging directory, then pack a new ZIP, 7Z or TAR from the files you actually wrote. Recovery records, archive comments, some attributes, and solid compression will not survive the repack, so keep the original if those matter.
If you only need to convert or inspect a handful of archives and you are not building a pipeline, a browser tool is enough. rar.now is the one I use for that job: RAR to ZIP, 7Z or TAR, plus extraction, an integrity test, repair when the archive has recovery data, and tools for multipart and password-protected sets. It does not create RAR files. Guests can use it with no account — 10 conversions a day, 10 MB per file. Uploads travel over HTTPS, work runs on the server, and guest files are deleted within 24 hours.
For a product, make the format and the safety checks part of the upload path, so the first artifact your build sees is already a ZIP or tarball you packed yourself.
Top comments (0)