Supply Chain Security: Verifying What You Install

Supply Chain Security: Verifying What You Install

Installing software means trusting a chain of people and machines. Some links in that chain are verified cryptographically and some are verified by hope, and the difference is worth knowing per link.

What your package manager already does

When you install from your distribution’s repositories, quite a lot happens automatically.

# APT trusts these keys
ls /etc/apt/keyrings/ /etc/apt/trusted.gpg.d/

# DNF and RPM equivalents
rpm -qa gpg-pubkey* --qf '%{summary}\n'

# verify installed files against the package
debsums -c            # Debian and Ubuntu
rpm -Va               # Fedora and RHEL

The repository metadata is signed, the metadata contains package hashes, and your package manager refuses anything that does not match. This is genuinely strong and it runs without you thinking about it.

Be precise about what it proves: the package was built and signed by the distribution and has not been altered since. It does not prove the software is well written, free of vulnerabilities, or free of something the upstream author introduced deliberately. Provenance and integrity, not safety.

Our packages and repositories guide covers the mechanism.

Third-party repositories move the trust

Adding a PPA or a vendor repository adds a signing key to your system.

# see what you have added
grep -rh '^deb ' /etc/apt/sources.list /etc/apt/sources.list.d/
dnf repolist

That key can sign anything, including a package that replaces a system one. A compromised third-party repository is a compromised system, and repositories accumulate: people add one for a single tool in 2021 and it is still trusted in 2026.

Audit them occasionally. Remove the ones you no longer use.

curl piped to shell

# what projects tell you to do
curl -sSL https://example.com/install.sh | sudo bash

# what to do instead
curl -sSLO https://example.com/install.sh
less install.sh
sudo bash install.sh

The usual objection is that a server can detect a pipe and serve different content, which is true and is not the main problem.

The main problem is that you have nothing to verify and no record of what ran. No signature, no package database entry, no file list, and no way to answer “what did that actually do” three months later when something is wrong.

Downloading first costs ten seconds and gives you an artifact you can read, keep and check.

Language registries are a weaker layer

npm, PyPI, crates.io and the rest are the softest part of most stacks. Anyone can publish, packages pull in transitive dependencies you never chose, and a compromised maintainer account pushes straight into your build.

cargo audit
npm audit
pip-audit

Lock files matter here more than people treat them. Cargo.lock, package-lock.json and poetry.lock pin exact versions and hashes, so a build is reproducible and a swapped package is visible. Committing them is the difference between knowing what you shipped and guessing.

The attack is increasingly social

The Rust project published a warning in September 2026 about a campaign targeting language developers and owners of popular crates. The method was not a technical exploit:

Attackers built plausible company profiles with convincing LinkedIn presences, approached maintainers about a job, contract or collaboration, arranged a video call, and then asked the target to install something, a purportedly missing codec, or to run a command placed on their clipboard.

The maintainer account is the target, because it is a publishing key. Compromise one and you push a malicious version that thousands of projects pull on their next build.

If you publish anything:

  • A LinkedIn profile is not identity evidence
  • Never run a command someone gives you during a call. No legitimate troubleshooting step requires that from a stranger
  • Read your clipboard before it reaches a shell. Paste into an editor first
  • Evaluate unknown code in a VM or container, per our container hardening guide
  • MFA on every publishing account, hardware keys where supported
  • Keep signing keys off your daily machine, as covered in secrets management

Container images and the tag problem

# mutable, can point anywhere tomorrow
docker pull myapp:1.2.3

# immutable, verifiable
docker pull myapp@sha256:abc123...

# what you are actually running
docker inspect --format='{{index .RepoDigests 0}}' myapp:1.2.3

A tag is a pointer, not an artifact. Whoever controls the repository can move 1.2.3 to different content at any time, and latest is worse in every respect.

Pinning by digest is what gives you something fixed. It makes updates deliberate rather than automatic, which is the point.

# scan what is inside
trivy image myapp:1.2.3
grype myapp:1.2.3

An image built six months ago from a current base is now full of known vulnerabilities, because its dependencies aged while it sat still. Rebuilding on a schedule matters as much as scanning does. Our self-hosted registry guide covers running your own, which is also where you enforce these checks.

Signatures beat checksums

# checksum: catches corruption
sha256sum -c SHA256SUMS

# signature: catches substitution
gpg --verify SHA256SUMS.gpg SHA256SUMS

A checksum hosted next to the download proves the file arrived intact. It proves nothing about origin, because anyone who can replace the file can replace the checksum.

A signature verified against a key you obtained independently, from a keyserver, the project’s repository, or a previous release you already trusted, is what establishes that the project produced it.

Get the key from somewhere other than the download page. Otherwise you are verifying a claim against itself.

SBOMs

A software bill of materials is a machine-readable inventory of what is inside an artifact.

syft myapp:1.2.3 -o spdx-json > sbom.json
grype sbom:./sbom.json

It does not make anything more secure. What it changes is response time. When the next widely used library has a critical vulnerability announced on a Friday afternoon, the question is which of your images contain it, and an SBOM turns that from a multi-day audit into a query.

A proportionate approach

Perfect verification is not achievable and pursuing it wastes effort better spent elsewhere.

Worth doing always:

  • Prefer distribution packages over anything else
  • Audit your third-party repositories occasionally
  • Commit lock files
  • Pin container images by digest
  • MFA on anything you can publish from

Worth doing if you publish or run infrastructure:

  • Signature verification on release artifacts
  • Dependency auditing in CI
  • Scheduled image rebuilds rather than only on change
  • Signing keys stored off the machine that uses them

The honest caveat: none of this addresses a malicious upstream author, which is the hardest case and the one where these controls do least. What they defend against is substitution, tampering and account compromise, which is most of what actually happens.

Frequently Asked Questions

What does a distribution package signature actually prove?

That the package was built and signed by the distribution and has not been altered since. It does not prove the software is safe, well written, or free of backdoors introduced upstream. It proves provenance and integrity, which is valuable and narrower than people assume.

Is curl piped to shell actually dangerous?

The real problem is that it gives you nothing to verify and no record of what ran. The server can serve different content to a pipe than to a browser, and you executed it as root with no signature check and no way to audit it afterwards. Download it, read it, then run it.

Are container image tags immutable?

No. A tag is a mutable pointer, so the image behind version 1.2.3 can be replaced at any time by whoever controls the repository. Pinning by digest with the sha256 form is what actually gives you a fixed, verifiable artifact.

What is an SBOM and is it useful?

A software bill of materials is a machine-readable inventory of what is inside an artifact. Its value is answering questions like which of our images contain this vulnerable library in minutes instead of days. It does not make anything more secure by itself, it makes the response faster.

How do attackers compromise package maintainers?

Increasingly through social engineering rather than technical exploits. The pattern documented against Rust crate owners involved fake companies with plausible profiles, a video call about a job or contract, and then a request to install something or run a pasted command. The target performs the compromise themselves.

Should I verify checksums when the download page also hosts them?

A checksum on the same server proves only that the download was not corrupted in transit, because anyone who can change the file can change the checksum. A signature verified against a key you obtained independently is what proves origin. Checksums catch accidents, signatures catch attacks.