
In March 2024, a maintainer named Jia Tan spent nearly two years quietly building trust in the xz compression project before slipping a backdoor into a library that ships with almost every Linux distribution on Earth. The exploit was caught by a Microsoft engineer who noticed his SSH logins were running half a second slower than usual. Half a second. That is how close we came to a compromise that could have handed remote root access to a huge slice of the internet's servers.
Supply chain attacks like this are not rare edge cases anymore. Sonatype's 2023 State of the Software Supply Chain report counted more than 245,000 malicious packages published to open source registries in a single year, more than double the total of all previous years combined. The average modern application pulls in over a thousand transitive dependencies, and almost nobody reads all of them. That gap between what we install and what we actually inspect is exactly where attackers live.
This guide walks through how to verify open source package integrity in practice, using real commands, real tools, and a repeatable workflow you can apply before you type npm install or pip install again. You will learn how checksums, signatures, provenance, and dependency auditing fit together, and how to spot the warning signs that separate a healthy package from a poisoned one.
Key Takeaways
- Never trust a package name alone. Verify checksums and cryptographic signatures against the maintainer's published values, not the ones bundled in the download.
- Provenance matters more than popularity. A package with SLSA build attestation and a public source-to-artifact trail beats a million-download library with no verifiable origin.
- Automate the boring parts. Lockfiles,
npm audit,pip-audit, and Sigstore verification should run in CI, not just in your head.- Watch the metadata, not just the code. Sudden maintainer changes, typosquatted names, and brand-new publish dates are the loudest red flags in most real attacks.
- Isolate before you trust. Test unfamiliar packages in a sandbox or VM before they touch your production environment.
What a Software Supply Chain Attack Actually Looks Like
A supply chain attack targets the tools and dependencies you rely on rather than your application directly. Instead of breaking down your front door, the attacker poisons the lumber before your house is even built. When you install the compromised package, you invite the malicious code in yourself.
There are four common shapes these attacks take:
- Typosquatting: A package named
reqeustsorpython-dateutil2that imitates a legitimate one and steals credentials on install. - Dependency confusion: An attacker publishes a public package with the same name as your private internal one, and your package manager grabs the wrong one because it has a higher version number.
- Account takeover: A maintainer's registry credentials get phished, and a malicious version ships under a trusted name. This is what hit the
event-streamnpm package in 2018. - Build system compromise: The source code is clean, but the published artifact is not, because the build pipeline itself was tampered with. This was the essence of the SolarWinds breach.
Understanding which shape you are defending against tells you which verification technique matters most. Typosquatting is beaten by checking names carefully. Build compromises are only caught by provenance and reproducible builds. You need layers.
How to Verify Open Source Package Integrity Step by Step
Let me walk through a concrete scenario. Say you want to install a Python library called fastjsonschema for a payment service. It is not one of the top ten downloads, and your code will handle sensitive data, so a quick "it has stars on GitHub" is not enough. Here is the workflow I actually use.
Step 1: Confirm the exact name and source
Go to the official registry page, not a search engine result. For PyPI that is pypi.org/project/fastjsonschema/. Check that the project links to a real repository, that the repository URL matches the homepage, and that the name has no sneaky character swaps. Copy the name from the registry rather than typing it, because a single transposed letter is the entire attack in typosquatting.
Step 2: Pin the version and record the hash
Never install with a floating version like >=2.0 for anything security sensitive. Pin it. In Python you can require hashes explicitly in your requirements file:
- Find the SHA256 hash on the PyPI download page under the file details, for example
sha256: 3d48d...a91f. - Write it as
fastjsonschema==2.19.1 --hash=sha256:3d48d...a91finrequirements.txt. - Install with
pip install --require-hashes -r requirements.txt.
If the downloaded file does not match the recorded hash, pip refuses to install. That single flag defends against a mirror serving you a tampered file.
Step 3: Verify the checksum manually when it matters
For a critical dependency, download the artifact and compute the hash yourself. On Linux or macOS:
- Run
shasum -a 256 fastjsonschema-2.19.1.tar.gz. - Compare the output character by character against the value published on the official page.
On Windows the equivalent is certutil -hashfile file.tar.gz SHA256. If you frequently juggle files, symlinks, and build artifacts across drives during this kind of verification, a focused utility like Windows Symlink Creator Pro can keep your test directories tidy without polluting your real project tree.
Step 4: Verify the cryptographic signature
A checksum proves the file was not corrupted in transit. A signature proves who created it. Modern registries increasingly support Sigstore, which ties artifacts to an identity through short-lived certificates. For npm packages published with provenance, you can run npm audit signatures to confirm the registry signatures are valid. For projects that still use GPG, import the maintainer's public key from a keyserver you trust and run gpg --verify package.tar.gz.asc package.tar.gz.
Step 5: Check provenance and build attestation
Provenance answers the question "was this artifact really built from this source, by this pipeline?" GitHub now publishes signed build attestations for many packages, and the SLSA framework defines levels of assurance. On npm, packages published from a verified CI workflow show a green provenance badge and link back to the exact commit and build log. Prefer these. A package you can trace from source commit to published artifact is far harder to backdoor than one that appeared from an anonymous laptop.
Step 6: Audit the dependency tree
The package you chose may be clean while one of its dependencies is not. Run an automated audit:
- Node:
npm auditandnpm lsto see the full tree. - Python:
pip-audit, which checks installed packages against the PyPI advisory database. - Multi-language:
osv-scannerfrom Google, which cross-references the Open Source Vulnerabilities database.
In our example, pip-audit takes about three seconds and flags any known CVEs. If a transitive dependency has an unpatched critical vulnerability, you stop here and reconsider.
Comparing the Main Verification Methods
Not every method gives you the same guarantee, and they cost different amounts of effort. Here is how the common approaches stack up so you can pick the right layer for the situation.
| Method | Protects against | Effort | Automatable | Confidence |
|---|---|---|---|---|
| SHA256 checksum | Corruption, mirror tampering | Low | Yes | Medium |
| GPG signature | Impersonation, tampering | Medium | Partial | High |
| Sigstore / provenance | Build compromise, impersonation | Low | Yes | Very high |
| Dependency audit (OSV) | Known vulnerabilities | Low | Yes | Medium |
| Manual source review | Novel malicious code | Very high | No | Very high |
The honest tradeoff is that manual review gives the most confidence but does not scale. For most teams the sweet spot is checksums plus provenance plus automated audits in CI, with manual review reserved for a handful of critical or unfamiliar dependencies.
Reading the Metadata: Red Flags Before You Install
Some of the loudest warning signs never touch the code at all. Before you install anything, spend two minutes on the registry and repository pages looking for these signals.
- Publish date versus version history. A package claiming version 8.4 that was first published three days ago is suspicious. Legitimate mature packages have a long release trail.
- Maintainer changes. If the person who published the latest version is different from the historical maintainer, dig into why. The
event-streamattack happened after a new maintainer took over a popular but unmaintained package. - Download spikes with no explanation. A sudden jump can mean automated tooling probing a malicious release.
- Install scripts. In npm, check for
preinstallandpostinstallhooks. Legitimate libraries rarely need to run arbitrary code on install. Malicious ones almost always do. - Obfuscated or minified source in the published package. If the repository is readable but the published artifact contains base64 blobs or eval calls, that mismatch is a serious problem.
This kind of scrutiny is the same discipline we recommend in our guide to vetting WordPress plugins for security before you install, and it applies just as well to browser add-ons, which we cover in our walkthrough on how to audit browser extension permissions for AI data leaks.
Building Verification Into Your Workflow, Not Your Memory
Manual checks are great for a one-off install, but nobody keeps
Cover image: ITU Workshop on Zero Trust and Software Supply Chain Security by Bulexat, licensed under BY-SA 4.0 via Openverse.







