Security
Key points

Key points

  1. 1Treat every dependency bump as a small code review with four checks: changelog, artifact provenance, lockfile diff, and a focused test plan.
  2. 2Read the changelog for breaking changes and security fixes before you read the diff, because the diff tells you what changed and the changelog tells you why it matters.
  3. 3Verify that the published artifact matches expectations (signature or provenance, version, maintainer) so a compromised maintainer account does not slip a malicious release past you.
  4. 4Diff the lockfile to see transitive additions and removals, since most of the code you ship is code you never wrote.

Start with the changelog, not the diff

A dependency pull request usually shows you a version string and a lockfile hunk. That is the least informative part of the review. Open the release notes first, because they tell you whether this bump changes behavior, drops support, or fixes a vulnerability you actually care about.

Read the changelog in three passes. First, scan for the words that signal a break: "removed," "renamed," "deprecated," "no longer," "behavior change," and any note about minimum runtime or peer versions. Second, look for the security fix line. If the release closes a vulnerability, note the advisory identifier so you can confirm later that your deployed code really contains the fixed version. Third, check the release date and the span of changes. A bump across two patch releases is a different review from a bump across two major versions, and you should budget your time accordingly.

The reason this matters is structural. Most applications pull in far more third-party code than first-party code, and a single package can drag in many more beneath it. The UK National Cyber Security Centre points out that ecosystems such as Node.js, Rust, and Python lean heavily on external registries and that a single dependency can introduce a large number of transitive dependencies, so the changelog you read is only one of several that changed in the NCSC guidance on checking dependencies. When you cannot find release notes for a transitive package that moved, that is a finding in itself.

A worked example makes the time budget concrete. Suppose a pull request bumps one direct library and the lockfile shows four transitive packages also changed. You now have five changelogs to read, not one. At two minutes each that is ten minutes of reading, which is cheaper than a single afternoon debugging a behavior change in staging. Make the transitive count visible in the pull request description so the reviewer knows the real scope before opening anything.

Verify you are reviewing the artifact you think you are

The second check is identity: is this release the thing it claims to be, from the people you expect? Supply chain attacks succeed precisely because the malicious code arrives through a trusted channel, and a compromised maintainer account is one of the documented ways attackers push malicious updates into legitimate packages according to Apiiro's overview of software supply chain attacks. If you only read the changelog, you are trusting the same account the attacker may now control.

Check three things. First, the publisher. Look at the package registry page and confirm the maintainer name and signing identity match what you saw on prior releases. Second, the provenance or signature. Many registries now attach a signed attestation that links the published artifact to a specific source repository and build pipeline; if your ecosystem offers this, verify it rather than assuming it. Third, the version and integrity hash. Your lockfile should record a content hash per package, and a restored package can be checked against it. The NuGet ecosystem, for example, records a SHA-512 content hash for each package in its lock file so a restored package can be verified against what was locked as described in this write-up on NuGet version locking.

A recent event shows why this is not theoretical. In a documented npm incident, attackers phished a package maintainer by impersonating registry support and convincing them to "update" their two-factor authentication, then used the stolen access to publish malicious versions of widely used packages, which stayed live for roughly two hours before removal per Palo Alto Networks' analysis of the npm supply chain attack. The changelogs for those releases were not the problem. The identity behind the publish was.

A practical rule: if the publisher identity, signing state, or provenance attestation changed since the last release you approved, stop and escalate. Do not merge a bump that silently changes who signs the artifact, even for a patch version. That is the one signal a human reviewer can catch that automated dependency scanners routinely miss.

Check maintainer and release activity for takeover risk

Abandonware and account takeover are two sides of the same risk. An unmaintained package is a target because nobody is watching it, and a package whose ownership has quietly changed hands is a target because the new owner may not be who they claim. The NCSC names both patterns directly: maintainer account compromise and abandoned package takeover are recurring attacker techniques in open source ecosystems in its dependency guidance.

You do not need a tool for the basic version of this check. Spend two minutes on the package's repository and registry page:

  • When was the last release, and when was the one before it? A sudden gap followed by a burst of releases warrants a closer look at who authored them.
  • Did the maintainer list, owner, or signing key change since the last release you approved?
  • Is the repository archived, or does the README point to a new home?
  • Do the release notes describe changes that match the diff, or do they look rushed and generic?

A decision rule helps here. If a package you depend on has had no release in a long stretch, treat any new release as a major review regardless of its version number, and read the diff of install scripts and entry points specifically. The reason is mechanical: Node.js and Python allow scripts that execute at install time, so a malicious package can run code immediately, without human approval, through an automated pipeline per the same NCSC guidance.

Diff the lockfile to see what actually ships

The lockfile is the honest record of what your build resolves. Direct dependencies are the ones you typed; transitive dependencies are everything else, and they are the majority of what executes in production. Diffing the lockfile turns an opaque resolution step into a reviewable list.

The table below maps what each kind of lockfile change should trigger in your review.

Lockfile changeWhat it usually meansReview action
Direct version changedThe bump you intendedRead that package's changelog, then test the calls your code makes into it
Transitive addedA new package entered your graph, possibly via the bumped direct dependencyLook up the new package: publisher, release history, install scripts
Transitive version changedAn upstream constraint movedRead the changelog for the transitive package too, not just the direct one
Transitive removedA dependency was droppedConfirm nothing still imports what was removed
Integrity hash changed for the same versionThe artifact was republished under an existing versionTreat as a red flag and investigate before merging
Lockfile unchanged but manifest changedResolution did not actually changeConfirm the manifest edit is intentional

The integrity hash row deserves emphasis. Republishing the same version with different content defeats the purpose of pinning, because your pin now points at something new. Registries generally discourage or prohibit it, but the check costs nothing: compare the hashes in the diff.

Lockfiles also make the review repeatable across machines. If your build resolves versions at restore time rather than from a locked file, the same commit can produce different binaries on different days, because a transitive package three levels down shipped a patch over the weekend as the NuGet locking article explains. Locked-mode restores fix that by either reproducing the locked versions exactly or failing, so a drift never reaches a build nobody reviewed.

Here is a compact way to surface the lockfile diff in a pull request comment, using a generic diff against the merge base:

git diff --unified=0 origin/main -- '**/package-lock.json' '**/poetry.lock' '**/packages.lock.json' \
  | grep -E '^\+|^-' \
  | grep -vE '^(\+\+\+|---)' \
  | grep -E '"(version|resolved|integrity|contentHash)"' \
  | head -n 80

Adjust the paths and key names for your ecosystem. The point is to print version, source, and hash lines in one place so the reviewer reads the actual resolution rather than scrolling a thousand-line JSON file.

Run a focused test plan before merge

A dependency bump is a change to code you did not write, running in a process you do control. The test plan should target the surface where your code touches the package, not the entire suite again for the sake of it.

A four-part plan covers most bumps:

  1. Unit tests for the modules that import the package. If coverage marks those modules as untested, add at least one test that exercises the public calls you rely on before merging.
  2. The integration paths that cross the package boundary: serialization, HTTP clients, parsers, date handling, anything where behavior changes are plausible.
  3. A smoke test in a staging environment that mirrors production configuration, because peer dependency and runtime version checks only fail in a real install.
  4. A rollback check: confirm you can revert the lockfile and redeploy without a data migration problem.

The NIST Secure Software Development Framework provides a language for placing this inside a broader process. It groups practices into four areas: prepare the organization, protect the software, produce well-secured software, and respond to vulnerabilities as summarized by NIST's SSDF project page. A dependency review that verifies publisher identity and artifact integrity sits squarely in protecting the software, and the test plan plus rollback check sits in responding to vulnerabilities. If you need a documented control for an audit, mapping your pull request checklist to those four groups makes the conversation easier; CISA publishes the same framework for reference via CISA's SSDF page.

For teams that want to measure whether this review is consistent across products rather than existing on one team's goodwill, OWASP SAMM is a maturity model built for exactly that question. It asks not whether a dependency scanner exists but whether it is configured consistently, whether exceptions are risk accepted and documented, and whether remediation times are tracked as Security Boulevard summarizes in its SAMM write-up. The OWASP SAMM project page describes the model as technology and process agnostic and risk driven per the OWASP SAMM project.

A checklist you can paste into the pull request template

The final step is to make the review cheap for the next reviewer. Put the checklist in the template so every dependency pull request arrives with the same slots to fill.

  • Changelog read for every package in the lockfile diff, direct and transitive
  • Breaking changes identified and mapped to call sites in this repository
  • Security fixes noted, with advisory identifiers if any
  • Publisher and signing identity unchanged since the last approved release
  • Provenance or signature verified where the registry provides it
  • Maintainer and release activity checked; no unexplained ownership or key change
  • Lockfile diff reviewed: additions, removals, version changes, hash changes
  • New transitive packages checked for install scripts and recent creation date
  • Unit tests covering the touched modules pass
  • Integration paths crossing the package boundary pass
  • Staging smoke test completed
  • Rollback path confirmed

The maturity-appropriate advice is to start with the rows you can automate and reserve human attention for the rest. Scanners can flag known vulnerabilities and list changed packages; nobody's scanner tells you whether a maintainer's signing key quietly changed. That judgment call is where a reviewer earns their keep.

If your team is building shared tooling around this, a shared credit pool and a private skill library with per-person keys makes it easier to keep review automation consistent across a group rather than one person's laptop see Quanta for Teams. Keep the checklist versioned next to the template so changes to the process are themselves reviewable.

FAQ

FAQ

How much time should a dependency review take?

Budget in proportion to the lockfile diff, not the version number. A single patch bump with no transitive changes takes a few minutes; a bump that touches five packages and introduces new transitive dependencies may take twenty. The estimated reading time is roughly two minutes per changed package's changelog. If the estimate feels too high for a routine release, that usually means you should automate more of the mechanical checks rather than skip the reading.

What if the package has no changelog?

Treat missing release notes as a finding. Read the commit history between the two tags instead, and check whether install scripts or entry points changed. If you can still not establish what changed and why, pin to the prior version and open an issue upstream. For a transitive package that moved without any release notes you can find, ask whether you need that package at all.

Do I need to review patch versions differently from major versions?

Yes, and the difference is about scope rather than trust. A major version bump signals that the maintainers expect breaks, so map the changelog against your call sites before you test. A patch bump is where unexpected behavior fixes and security patches land, so check the security lines carefully. In both cases the identity checks (publisher, signature, hash) are identical and non-negotiable.

How does a lockfile change the review?

It makes the review complete. Without a committed lockfile, your build resolves versions at restore time, and the same commit can produce different dependencies on different days. With one, the pull request diff shows every direct and transitive change plus an integrity hash you can compare, so the reviewer sees the real scope of the change rather than the version string in the manifest.

When should a dependency bump be blocked?

Block when the publisher identity or signing key changed unexpectedly, when the integrity hash changed under an existing version, when a newly added transitive package runs install-time scripts you have not inspected, or when staging fails. Each of these is a signal that the artifact or its supply chain is not what you approved. None require proof of malice to justify a hold; they require explanation before merge.

If your team wants a second pair of eyes on how dependency review, artifact verification, and test plans fit together with your release process, a free discovery call is a reasonable next step: book a Quanta consulting call.

Sources

Sources

  1. Software supply chain attacks: check your dependencies
  2. Software Supply Chain Attacks
  3. NuGet Version Locking and Your Build Becomes Stable
  4. Breakdown: Widespread npm Supply Chain Attack Puts ...
  5. Secure Software Development Framework (SSDF)
  6. NIST SP 800-218, Secure Software Development Framework V1.1 - CISA
  7. Using OWASP SAMM to measure secure development maturity
  8. OWASP SAMM
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles