Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Validate Package Provenance and Integrity with APT and Checksums

Hello. In the previous lesson, you learned to predict APT transactions: inspect the candidate version, simulate dependency changes, distinguish manual from automatic packages, and choose deliberately between removal and purge. That work answers, “What will APT change?” This lesson addresses the equally important questions: “Where did this package come from?” and “Has the package or its installed files changed unexpectedly?”

For LFCS practice, treat package validation as three related but distinct checks:

  1. Provenance: which configured repository and release pocket supplied the selected version?
  2. Download integrity: does the downloaded .deb match the hash recorded in trusted repository metadata?
  3. Installed-file integrity: do files presently on disk still match the package database’s recorded baseline?

Policy is selection evidence, not signature evidence

Start with a package that is already installed and normally available from Ubuntu’s official repositories, such as bash:

apt-cache policy bash

Typical output includes:

  • Installed: the version currently on the system.
  • Candidate: the version APT would install now.
  • A Version table showing each known version, its priority, and the repository location that advertised it.

A conceptual example:

bash:
  Installed: 5.2.x
  Candidate: 5.2.x
  Version table:
 *** 5.2.x 500
        500 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages
        100 /var/lib/dpkg/status

This tells you that APT has selected a specific version from a particular archive, suite, component, and architecture. If the candidate unexpectedly comes from a testing repository, PPA, or a lower-priority source than intended, stop there and investigate your source configuration and APT preferences.

However, apt-cache policy does not itself prove that a repository is cryptographically trustworthy. It reports what exists in APT’s local metadata cache. The signature check happens when APT refreshes that metadata:

sudo apt update

During apt update, APT retrieves signed repository release metadata and validates it against the trusted keys configured for each repository. Do not work around signature failures with insecure options such as --allow-unauthenticated, and do not treat a failed update as harmless merely because old package metadata remains cached.

The apt-cache manual page is useful because it makes the purpose and limitation of this tool explicit.

query the APT cache

Read the Ubuntu apt-cache manual page to distinguish cached package metadata from system state, then focus on what policy is designed to reveal.

In the DESCRIPTION section, read the cache overview. Notice that this information is acquired by apt update and can become stale. Then find the command entry named policy and read the policy description. Focus on the distinction between source priorities generally and detailed selection for one named package.

A concise pre-install provenance check is therefore:

sudo apt update
apt-cache policy PACKAGE
apt-get -s install PACKAGE

Read these results together:

Check What it establishes
apt update succeeds without trust errors Current repository metadata passed APT’s configured signature validation
apt-cache policy PACKAGE Which known version is selected and which source advertises it
apt-get -s install PACKAGE What APT would actually install, upgrade, or remove

How APT connects trust to a package file

APT does not normally trust a downloaded .deb simply because it came from an HTTPS URL or has a familiar filename. Instead, Ubuntu’s archive security model binds several pieces of information together.

  1. The repository publishes an InRelease file, signed by the archive key trusted by APT.
  2. That signed file contains hashes of repository index files, including architecture- and component-specific Packages files.
  3. A Packages file lists a package’s relative filename, version, and cryptographic hashes such as SHA-256.
  4. APT downloads the selected .deb and verifies that its contents match the hash recorded in that authenticated Packages file.

This matters because a plain checksum has no useful provenance by itself. If an attacker can replace both a file and the page that tells you its expected hash, a matching checksum proves nothing. APT’s signed metadata prevents an untrusted mirror from silently substituting both the package and its expected digest.

Ubuntu archive integrity verification - Ubuntu security documentation

Read Ubuntu Security’s explanation of the archive-verification process. It connects the command-level checks you perform with the cryptographic chain that makes them meaningful.

First, in Automatic verification, read the recommended process. The operational point is to let APT fetch packages by package name, rather than bypassing repository validation with an arbitrary local package file. Then read the Signature scheme section from the signed metadata chain. Follow the progression from the signed InRelease file to Packages metadata and finally to the downloaded .deb.

This also clarifies a practical distinction:

  • apt install PACKAGE is the normal, safe administration path. APT downloads and validates the package as part of the transaction.
  • dpkg -i some-file.deb installs a local file directly. dpkg can manage the package contents and dependencies only imperfectly, but it does not perform APT’s repository metadata validation for that file.
  • A manually downloaded .deb is not automatically trustworthy merely because its filename resembles an official package.

Use local package files only when there is a deliberate offline or controlled-package workflow, and validate their origin and hash beforehand.


Inspecting the expected package checksum

APT performs checksum verification automatically when it downloads from a trusted configured repository. Nevertheless, manually comparing a package file’s SHA-256 digest with APT metadata is a valuable diagnostic and certification skill. It demonstrates what APT is checking on your behalf.

The following lab downloads bash without installing or changing it.

1. Confirm the selected version and source

pkg=bash

sudo apt update
apt-cache policy "$pkg"

Record the candidate version. Then display metadata for that version:

ver=$(apt-cache policy "$pkg" | awk '/Candidate:/ {print $2}')

apt-cache show "$pkg=$ver" |
  awk '/^(Package|Version|Architecture|Filename|SHA256):/ {print}'

The relevant metadata fields are:

  • Version: the precise package version.
  • Architecture: the architecture of the binary package.
  • Filename: its archive-relative location.
  • SHA256: the expected SHA-256 digest.

If the command displays more than one record, inspect the stanzas carefully. Match the version and architecture to the package you intend to download. Multiple repositories can advertise a package, and two records with a similar version string are not automatically equivalent provenance.

2. Download through APT, without installing

Work in an ordinary writable directory rather than a system directory:

mkdir -p ~/package-check
cd ~/package-check
rm -f ./*.deb

apt download "$pkg=$ver"

apt download retrieves the package but does not unpack or install it. Because it is an APT frontend fetching by package name and version, it uses the configured package metadata and its validation rules.

Locate the downloaded package:

ls -lh ./*.deb
sha256sum ./*.deb

Compare the displayed digest with the SHA256 value from the matching apt-cache show stanza. They must match exactly.

For a shell-enforced comparison, after confirming that the directory contains only the intended .deb, use:

expected=$(apt-cache show "$pkg=$ver" |
  awk '/^SHA256:/ {print $2; exit}')

deb=$(find "$PWD" -maxdepth 1 -type f -name '*.deb' -print -quit)

printf '%s  %s\n' "$expected" "$deb" | sha256sum --check

A successful result ends with OK. A failure means the local file does not match that expected digest. Do not install it. Download it again through APT, verify that the source and candidate are the intended ones, and investigate storage or network problems if the mismatch persists.

The checksum video provides a short visual review of calculating a SHA-256 digest and recognizing a failed comparison. Its example uses an ISO rather than a package, but the integrity principle is the same.

VERIFY MD5 / SHA256 Hash or Checksum on Linux - File Security (Ubuntu)

Watch “VERIFY MD5 / SHA256 Hash or Checksum on Linux - File Security (Ubuntu)” by SavvyNik for a compact demonstration of checksum comparison. Apply the technique to a .deb only when the expected digest comes from trusted APT metadata.

Watch the checksum purpose for the integrity model. Then watch the successful comparison, noting how a locally calculated SHA-256 value is compared with an expected one. Finally, watch the failure case to see why one changed character produces a mismatch. For administrative scripts, prefer sha256sum --check over parsing grep output because it gives a clear success or failure status.

The manual checksum step is mainly an audit or troubleshooting technique. Under ordinary conditions, a package installed by apt install PACKAGE has already passed the equivalent repository-hash check. Repeating a hash comparison does not add a second independent trust system; it gives you evidence that you understand and can inspect the first one.


Verifying files after installation

A package can be authentic at installation time and still differ later. Files may change because of:

  • intended local configuration;
  • an interrupted upgrade or storage corruption;
  • an administrator’s manual edit;
  • an application or maintainer script creating runtime state;
  • unauthorized modification.

dpkg stores package metadata locally, including checksums for many packaged files. Use dpkg --verify to compare the current installed files against this recorded baseline.

For bash:

sudo dpkg --verify bash

The short form is equivalent:

sudo dpkg -V bash

A silent result generally means that dpkg found no discrepancies among the files it can verify for that package. It does not mean that every file involved in running the application is pristine, nor does it prove that the entire host is uncompromised.

If dpkg --verify reports a file, interpret it before “fixing” it. In its verification output, a 5 in the status field indicates that the file contents differ from the recorded checksum. The path is the important starting point.

Identify who owns a particular packaged file:

dpkg -S /usr/bin/bash

List the paths that a package declares:

dpkg -L bash

Confirm the installed package state:

dpkg-query -W -f='${db:Status-Abbrev} ${Package} ${Version}\n' bash

These commands answer different questions:

Command Question answered
dpkg -S PATH Which installed package owns this path?
dpkg -L PACKAGE Which paths does this package claim to install?
dpkg -V PACKAGE Which verifiable installed files differ from dpkg’s baseline?
dpkg-query -W ... Is the package installed, and at which version?

Configuration files need judgment

A changed configuration file is often expected. For example, an administrator may intentionally modify a service’s file under /etc. Do not automatically treat every verification difference as corruption.

Inspect package-declared conffiles with:

dpkg-query -W -f='${Conffiles}\n' PACKAGE

For a service package, first determine whether the changed file is:

  • a packaged conffile intentionally edited by administration;
  • a generated file that should not be edited manually;
  • a non-configuration executable or library that should normally be restored;
  • a file outside package ownership, requiring application-specific investigation.

A measured response to an unexpected discrepancy is:

Identify the file and package owner.
Determine whether the change is expected and authorized.
Preserve evidence or back up necessary configuration.
Reinstall the verified package only when restoring its packaged files is appropriate.
Validate the affected service afterward.

For an ordinary non-conffile discrepancy, a controlled restoration might be:

apt-cache policy PACKAGE
apt-get -s install --reinstall PACKAGE
sudo apt install --reinstall PACKAGE
sudo dpkg --verify PACKAGE

Simulate the reinstall first, just as you would any package transaction. For important services, back up configuration and understand the application’s state directories before reinstalling or purging anything.


Limits of installed-file verification

dpkg --verify is useful, but its evidence has a defined scope.

It is strongest for detecting unexpected changes to files that are both:

  1. installed by a Debian package; and
  2. represented by verifiable records in the local dpkg database.

It is not a complete security audit. In particular:

  • It does not validate files created later under locations such as /var/lib, /var/cache, /var/log, or user home directories.
  • It cannot judge whether an intentional configuration edit is correct.
  • It relies on the local dpkg database. A sufficiently privileged attacker could alter both a file and local package metadata.
  • It does not replace incident response when compromise is suspected.

If you suspect a privileged compromise, preserve evidence, isolate the system according to operational policy, and validate from a known-good environment. A clean dpkg --verify result alone is not sufficient grounds to declare the system trustworthy.


A practical validation routine

Before installing or approving an update from an important source:

sudo apt update
apt-cache policy PACKAGE
apt-get -s install PACKAGE

To audit a downloaded package in a lab or troubleshoot a suspected corrupted package archive:

apt-cache show PACKAGE=VERSION
apt download PACKAGE=VERSION
sha256sum PACKAGE_VERSION_ARCH.deb

To audit files after installation:

sudo dpkg --verify PACKAGE
dpkg -S /path/to/file
dpkg-query -W -f='${Conffiles}\n' PACKAGE

The key discipline is to keep the claims separate:

Claim Best evidence
APT selected the intended source and version apt-cache policy PACKAGE
Repository metadata was accepted under configured trust A successful apt update with no signature warnings
A downloaded package matches repository metadata APT’s automatic download check, or SHA-256 comparison against matching APT metadata
Installed packaged files still match their recorded baseline dpkg --verify PACKAGE
The entire host is secure Requires broader system and incident-response evidence; package verification alone is insufficient

You can now validate a package across its lifecycle: identify the selected repository and version, understand the signed-metadata chain that authenticates the download, compare a package archive’s SHA-256 digest when needed, and check installed files against dpkg’s baseline.

Next, you will move from validation to recovery: repairing interrupted APT or dpkg transactions, dependency failures, package locks, and partially configured packages.

Can't find a good explanation? Sign up and we'll make it for you

Sign up