How to Inspect a DEB, RPM or TAR.ZST Package Without Installing It
Someone sends you a .deb. A vendor ships a driver as an .rpm. A build pipeline spits out a .tar.zst and you want to know whether it contains what you think it does. In every one of those cases the sensible first move is to look inside before you install - and the awkward part is that "looking inside" usually means being on the right distribution, with the right tools, on a machine you are willing to unpack an untrusted archive onto.
None of that is actually necessary. A Linux package is not a magic binary; it is an archive with metadata bolted on. This post explains what is really inside each format, what is and is not risky about opening one, and how to turn any of them into an ordinary ZIP you can browse on any operating system.
What a .deb actually is
A Debian package is an ar archive containing, in order, three members:
debian-binary- a text file with the format version, almost always2.0.control.tar.*- the metadata: dependencies, description, checksums, and the maintainer scripts.data.tar.*- the payload, a file tree that gets unpacked onto your root filesystem.
The maintainer scripts are the interesting part. preinst, postinst, prerm and postrm are shell scripts that run as root at defined points during install and removal. They exist for legitimate reasons - creating a system user, running ldconfig, registering a service - and they are also precisely where a malicious package would put its payload. When people say installing an untrusted package is dangerous, this is what they mean. It is not the binaries; it is the scripts that run before you have looked at anything.
What an .rpm actually is
RPM takes a different approach. Instead of an ar archive, it is a binary format: a lead, a signature header, a metadata header, and then a compressed cpio payload holding the file tree. The scriptlets are not separate files at all - they are stored as tagged entries inside the header itself.
The practical consequence is that unzip and tar are useless on an RPM. You need rpm2cpio piped into cpio, which means you need RPM tooling, which is exactly what you do not have if you are on Debian, Ubuntu, macOS or Windows.
And the modern tarballs
Arch and its derivatives package as .tar.zst, and plenty of build systems now emit .tar.zst or .tar.lz4 as artefacts. These are ordinary tar archives with a newer compressor wrapped round them, and the reason for the switch is asymmetry: a package is compressed once by a build server and decompressed on every single install, so decompression speed matters far more than compression speed.
- gzip - universal, decades of compatibility, the weakest ratio and middling speed.
- bzip2 - better ratio than gzip, notably slow both ways, largely superseded.
- xz - excellent ratio, very slow to compress, moderate to decompress. Still common for source tarballs.
- zstd - close to xz on ratio at a fraction of the cost, and dramatically faster to decompress. Now the default for Arch packages and used inside Fedora's RPMs.
- lz4 - a modest ratio in exchange for extreme speed. Made for pipelines and caches, not for distribution.
The catch is tooling. A stock macOS or Windows machine, and older Linux boxes, will happily open .tar.gz and have no idea what to do with .tar.zst.
Reading a package is safe; running it is not
This distinction is worth being precise about, because it decides how careful you need to be.
Unpacking an archive does not execute anything inside it. ar, tar and cpio copy bytes; they do not invoke them. So extracting a hostile .deb does not, by itself, run its postinst. The genuine risks are narrower and quite specific:
- Path traversal. An archive entry named
../../etc/cron.d/evilwill, with a naive extractor, write outside the directory you chose. - Decompression bombs. A few kilobytes that expand into hundreds of gigabytes and fill your disk.
- Bugs in the parser. The extractor itself is code reading attacker-controlled input.
- You, afterwards. Having extracted a tree full of executables, the remaining risk is that something runs one - by double-click, by an editor's "run" button, or by an over-helpful file manager.
So the goal is not to avoid opening the package. It is to open it somewhere the first three cannot hurt you, and to receive the contents in a shape where the fourth cannot happen by accident.
Convert the package to a ZIP instead
Turning the package into a ZIP solves the tooling problem and the safety problem at once. You get a file tree you can browse in Finder, Explorer, or any archive manager, on a machine that has never heard of rpm2cpio.
- DEB to ZIP · RPM to ZIP
- TAR.ZST to ZIP · TAR.LZ4 to ZIP · TAR.XZ to ZIP
- TAR.GZ to ZIP · TAR.BZ2 to ZIP · TAR to ZIP
Two deliberate decisions govern what comes out the other side.
The maintainer scripts are not in the output. For a .deb, only the payload is read. The control archive holding preinst, postinst, prerm and postrm is never unpacked into the result, so the parts of the package designed to execute as root simply are not there.
Executables in the payload are made inert. Real packages ship binaries and scripts, and stripping them would give you a useless view of the package. So they are kept, with their content byte-for-byte unchanged, and .txt appended to the filename. A shell script arrives as install.sh.txt: still perfectly readable, no longer something a double-click will launch. When any file is renamed this way, a PRIVCONVERT-NOTICE.txt is added to the archive listing exactly which ones, so nothing is silently altered behind your back.
The conversion itself runs entirely in server memory with a per-job memory cap, which is what bounds a decompression bomb, and unsafe paths are rejected rather than written. Nothing touches a disk, and nothing is retained after your download.
What to look for once it is open
With the tree in front of you, a few things tend to be informative quickly:
- The file layout. Does a package that claims to be a CLI tool install into
/usr/bin, or is it scattering files into/etc/cron.d,/etc/systemd/systemand/usr/lib/systemd? - Unexpected persistence. Timer units, cron entries, shell profile fragments and udev rules are how something arranges to run again later.
- Size sanity. A 40 MB "small utility" with one tiny binary and a large blob of data is worth a second look.
- The renamed files. Read the
.txtversions. Shell scripts are plain text, and a script that downloads and pipes something into a shell is not subtle.
This will not catch a determined, well-hidden backdoor - nothing short of proper reverse engineering will. What it does catch is the common case: a package doing something obviously outside its stated purpose.
Repacking, and the other direction
The reverse conversions exist too, which is useful when a build artefact arrives in the wrong shape or a CI system insists on a particular compressor:
One honest limitation: converting a .deb to a ZIP and back does not give you an installable package. You get the payload, not the control metadata or the scripts, which is the whole point. Treat these as tools for inspection and for moving file trees between systems, not for rebuilding packages - for that you want the real packaging tools on the target distribution.
If you would rather do it locally
None of this is a secret, and on a Linux box with the right tooling the commands are short. It is worth knowing them:
# Debian package: list, then extract just the payload
ar t package.deb
dpkg-deb -c package.deb # list payload contents
dpkg-deb -x package.deb ./out # payload only, no scripts
dpkg-deb -e package.deb ./ctrl # the maintainer scripts, to read
# RPM: convert to cpio and extract
rpm2cpio package.rpm | cpio -idmv
rpm -qp --scripts package.rpm # print the scriptlets
# Modern tarballs
tar --zstd -tvf package.tar.zst
tar -I lz4 -tvf artifact.tar.lz4 Use -t to list before you use -x to extract, and extract into a fresh empty directory. The browser-based route is for when you are not on Linux, do not have the tooling, or would simply rather the unpacking happened somewhere other than your own machine.