One line, unbounded consequence
"dependencies": {
+ "date-fns-tz-utils": "^1.2.0",That is a nine-word diff and it is the largest change in the pull request. Adding a dependency means executing somebody else’s code, with your permissions, in your build, plus everything that package depends on, plus everything those depend on, for as long as the package remains installed and every time it updates.
Dependency lines get less review attention than any other line in a diff, and they always did. Two things changed. Suggestions to install a package now arrive constantly and casually. And the package suggested may not exist, which is a failure mode the ecosystem never had before and which attackers have already industrialised: register the plausible name a model keeps inventing, wait for installs. The practice picked up the name slopsquatting.
The two-minute check
Before any new dependency lands, answer six questions. It takes two minutes and it is the highest return per minute available in review.
Does it exist, and is it the one you think? Open the registry page. Not the search result, the page. Check the exact spelling: python-dateutil and dateutil, crossenv and cross-env, singular and plural forms, hyphens and underscores. Typosquatting predates all of this and remains the most common attack.
Who publishes it, and since when? A package first published three weeks ago with 40,000 weekly downloads is a signal, not a recommendation. So is a package whose only maintainer account was created the same month.
How many transitive dependencies come with it?
npm view <pkg> dependencies
npm ls --all <pkg> | wc -l # after install, in a scratch clone
pipdeptree -p <pkg> # Python
go mod graph | grep <module> # GoA utility that pulls in sixty packages to format a date is a decision about your whole supply chain, made to avoid writing nine lines.
Does it run code at install time? npm install executes preinstall, install and postinstall scripts by default. This is the most direct path from a malicious package to your laptop and your CI credentials.
npm view <pkg> scripts
npm ci --ignore-scripts # and see whether anything actually breaksWhat licence is it, and does that matter here? Copyleft licences in a distributed product, and licences that changed at version 4, are the two that catch teams out.
Is it maintained? Last release, open issue count, number of people with commit rights. A single-maintainer package is not disqualifying (many essential ones are) but it is a fact you should know rather than discover during an incident.
Read the lockfile diff, at least the shape of it
A one-line change to package.json can produce two thousand lines in package-lock.json, and nobody reads those. You do not have to. You have to look at the summary:
# how many packages were added, and which are new to the tree?
git diff --stat -- package-lock.json
npm ls --all --json | jq -r '..|.name?//empty' | sort -u > after.txt
# compare against the same list from mainWhat you are looking for is a count. Adding one direct dependency and 200 transitive ones is a thing the reviewer should know before approving, and it is invisible in the human-readable part of the diff.
Free tooling, which is most of it
npm audit,pip-audit,govulncheck,cargo audit: vulnerability scans, all free, all runnable in CI in one line.- OSV (osv.dev) and deps.dev: free databases of known vulnerabilities and dependency graphs, queryable from a browser or an API, no account.
- Dependabot and Renovate: free automated update pull requests. Renovate runs self-hosted if you cannot use the hosted one.
npm ci --ignore-scriptsand, in Python, installing only from wheels, both reduce install-time execution.- A lockfile, committed, with
npm cirather thannpm installin the pipeline. This is the single most effective free control on this list and many teams still do not have it.
The question that resolves most cases
Before adding anything, ask: what would this look like if we wrote it ourselves?
For a date-formatting helper the answer is often twelve lines and no supply chain at all. For a cryptography library, a database driver, or an HTTP client, the answer is that writing it yourself would be far worse, and you should absolutely take the dependency.
The rule is not “fewer dependencies”. It is that the trade is between code you maintain and code you trust, and that trade should be made deliberately rather than as a side effect of a suggestion you accepted without reading.
Every lesson here is open. Your progress is recorded once you pass the AI at Work exam.
Check your understanding
A pull request adds a package that the registry shows was first published eleven days ago, has one maintainer, and installs cleanly with the expected API. What is the strongest reason to pause before approving?
Pick the one you would defend. Your answer stays private.
Stuck on something?Ask Larissa, your AI tutor
