Build, Inspect and Safely Extract Packages with dpkg-deb
Every .deb on your system started as a folder and a control file, and dpkg-deb is the tool that builds one and lets you look back inside it. This builds a small Debian binary package, inspects its metadata and file list, then extracts it into a staging directory without installing anything. The commands below were checked with dpkg-deb from dpkg 1.22.6, installed here as package version 1.22.6ubuntu6.6.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about 15 minutes. You need dpkg-deb, a shell, and write access to a temporary working directory. None of the build, inspection or extraction commands need elevated privileges. Do not use dpkg-deb as an installer: installation belongs to dpkg or a higher-level package manager.
1. Make the package tree
A package build tree has a DEBIAN directory for control information and a separate filesystem tree for the files that will actually be installed. The DEBIAN directory itself never becomes part of the installed filesystem.
work=$(mktemp -d)
mkdir -p "$work/pkg/DEBIAN" "$work/pkg/usr/local/bin"
cat > "$work/pkg/DEBIAN/control" <<'EOF'
Package: example-tool
Version: 1.0-1
Section: utils
Priority: optional
Architecture: all
Maintainer: Example Maintainer <[email protected]>
Description: Small example command
A package used to demonstrate dpkg-deb.
EOF
cat > "$work/pkg/usr/local/bin/example-tool" <<'EOF'
#!/bin/sh
printf '%s\n' 'example-tool works'
EOF
chmod 0755 "$work/pkg/usr/local/bin/example-tool"
The control file uses Debian's continuation rule: the long description's continuation line starts with one space. The package name, version and architecture here also get reused later, when a target directory is supplied to the build command.
Checkpoint
Confirm the two important files exist before building.
$ find "$work/pkg" -maxdepth 4 -type f -printf '%P\n'
DEBIAN/control
usr/local/bin/example-tool
2. Build a .deb with the normal checks
Build into the working directory. Supplying a directory as the destination makes dpkg-deb choose a filename from the control fields itself:
dpkg-deb --build "$work/pkg" "$work"
deb="$work/example-tool_1.0-1_all.deb"
test -f "$deb"
Typical output identifies the package:
dpkg-deb: building package 'example-tool' in '/tmp/.../example-tool_1.0-1_all.deb'.
- The default checks parse
DEBIAN/controland check control-file permissions and maintainer scripts. Keep them enabled. --nocheckdeliberately permits a broken archive. It is not a repair option, whatever the name suggests.- Newly built archives use format 2.0 and zstd compression by default in this dpkg version. The format is an ar archive containing debian-binary, control.tar and data.tar, in that order: the control archive holds metadata and optional maintainer scripts, and the data archive holds the filesystem tree.
3. Inspect metadata before opening files
Use --info for a human-readable summary and control-file listing:
$ dpkg-deb --info "$deb"
new Debian package, version 2.0.
Package: example-tool
Version: 1.0-1
Architecture: all
The exact size lines vary, so check the package identity and format rather than copying byte counts into a script. To pull selected fields without parsing the summary, use --field:
$ dpkg-deb --field "$deb" Package Version Architecture
example-tool
1.0-1
all
Missing field names are not errors for --field: if a script needs a required field, validate the returned value itself. For a compact package-and-version line, use --show, whose default format is the package name and version separated by a tab:
$ dpkg-deb --show "$deb"
example-tool 1.0-1
4. Review the payload without extracting it
--contents lists the filesystem archive using tar's verbose listing format, a useful checkpoint for catching an unintended path before extraction or installation:
$ dpkg-deb --contents "$deb"
drwxr-xr-x ... ... ./usr/
drwxr-xr-x ... ... ./usr/local/
drwxr-xr-x ... ... ./usr/local/bin/
-rwxr-xr-x ... ... ... ./usr/local/bin/example-tool
Owner, group, timestamps and byte counts depend on the build environment: check the paths and permissions you intended, and do not treat those display details as fixed output.
Warning
A package is not safe just because its file list looks ordinary. The control archive may contain maintainer scripts, and dpkg-deb never authenticates a package. Treat an archive from an untrusted source as untrusted data.
5. Extract into a disposable staging directory
Extract only into a directory you created for inspection. dpkg-deb may create the target directory itself, but its parents must already exist:
stage=$(mktemp -d)
dpkg-deb --extract "$deb" "$stage"
test -x "$stage/usr/local/bin/example-tool"
"$stage/usr/local/bin/example-tool"
rm -rf -- "$stage"
The command prints:
example-tool works
Warning
This extracts the data archive's filesystem tree only. It runs no maintainer scripts and registers nothing with dpkg. Never extract a package to / as a shortcut for installation: the manual explicitly warns that this does not produce a correct install.
For a full inspection tree containing both payload and control files, use --raw-extract instead:
raw=$(mktemp -d)
dpkg-deb --raw-extract "$deb" "$raw"
test -f "$raw/DEBIAN/control"
test -f "$raw/usr/local/bin/example-tool"
rm -rf -- "$raw"
Recovery
Those final rm -rf commands are destructive, but their targets are freshly created temporary directories held in shell variables. Check the variable before running a cleanup command in a longer script. If you need the tree back, rebuild the staging directory from the original archive; do not try to restore files by copying an extracted tree over a live system.
6. Extract one control or filesystem member
For a targeted read, --ctrl-tarfile and --fsys-tarfile stream tar data to standard output. This prints the control file without unpacking the complete archive:
$ dpkg-deb --ctrl-tarfile "$deb" | tar -xO ./control
Package: example-tool
Version: 1.0-1
...
To print the payload file itself, use the filesystem stream instead:
$ dpkg-deb --fsys-tarfile "$deb" | tar -xO ./usr/local/bin/example-tool
#!/bin/sh
printf '%s\n' 'example-tool works'
Warning
The streamed archive is still untrusted input. Do not pipe an unknown package into a command that executes its output, and do not run these operations as root unless the boundary is understood and necessary.
7. Remove the example safely
The example only ever touched the temporary directory and its contents. Remove it once you are done:
rm -rf -- "$work"
test ! -e "$work"
If you need the archive later, copy it to a deliberate location before this cleanup. Building a fresh archive from the same tree is the practical undo for this example; there is no installed package to remove.
Done means
- Package built cleanly. The package was built with normal validation and the expected filename.
- Metadata checked.
--fieldreported the package, version and architecture you supplied. - Payload reviewed.
--contentsshowed only the intended payload paths. - Extraction tested safely. The archive was extracted and tested in a disposable directory, never the live root.
- Trust boundary kept. dpkg-deb stayed separate from installation, and unknown archives were treated as untrusted.