Dependency selection
Dependency selection is the check you make before adding an open source package: whether you need it, whether it is the real package, who maintains and publishes it, and what it runs when installed. The decision is recorded in the pull request, and the exact version is pinned in a lockfile.
Every package you add runs with your application's privileges, and some run code on developer machines and CI runners as soon as they install. Adding is the cheapest point to say no. In September 2025 the Shai-Hulud worm used stolen npm credentials to publish malicious versions of over 500 packages. Vulnerability scanners later report known CVEs; they cannot tell you a package was the wrong choice.
- Who
- The developer adding the package, with a reviewer or code owner approving every change to manifests and lockfiles
- When
- Before a new direct dependency or a new major version is merged
- How often
- On every pull request that adds a dependency, and again when a package's maintainers, publishers or provenance change
- You end up with
- A short intake note in the pull request, a lockfile entry with an integrity hash, and a named owner for updates
Do this
Ask whether you need it
Check whether the standard library, your framework or a package you already use does the job. The OpenSSF Concise Guide for Evaluating Open Source Software starts here, and warns that every new dependency is a potential support problem or supply chain attack. Look at what the package pulls in too, and at whether development-only packages end up in production.
Confirm it is the package you meant
Check the exact name on the registry, look for a more popular look-alike that would signal typosquatting, and confirm the project it claims to come from. Take extra care with names an AI assistant suggested: a USENIX Security 2025 study of 576,000 generated code samples found that models suggest packages that do not exist, and an attacker can register such a name.
Check maintenance and security practices
Look for commits and a release in the last 12 months, more than one maintainer, instructions for reporting vulnerabilities, and no long-known unfixed vulnerabilities in the version you will use. Read the individual OpenSSF Scorecard checks on deps.dev, such as Code-Review, Maintained and Dangerous-Workflow, rather than the total. OSV dependency lookup checks exact versions against OSV.
Check who publishes it and what runs at install
List the publishers, for example with
npm view <package> maintainers, and check whether the version has provenance that links it to a source commit, as deps.dev shows for npm packages. Read anypreinstall,installorpostinstallscript before allowing it: npm 12 blocks dependency install scripts by default until you approve them, and pnpm runs only builds listed inallowBuilds.Pin it in a committed lockfile
Commit the lockfile with the manifest and install from it in CI.
npm ciexits with an error ifpackage.jsonand the lockfile disagree and never rewrites the lockfile; pip's hash-checking mode requires every requirement pinned with==and a hash for every dependency. Review the lockfile diff in the pull request, because that is where unexpected transitive packages show up.Install only from the registry you intend
Give each internal package name one source: an npm scope mapped to your registry (
@acme:registry=...), a single pip index that proxies PyPI instead of--extra-index-url, a uv index markedexplicit = true, or NuGetpackageSourceMapping. Otherwise a public package with the same name and a higher version can win. OWASP ASVS 5.0 V15.2.4 (level 3) requires this.Record the decision and an owner
Write the intake in the pull request: why this package, the exact version, what you checked, any gap you accepted and who owns its updates. Route manifest and lockfile changes to a code owner, and reopen the decision when maintainers or publishers change, a release loses provenance its predecessors had, or a new major version adds native code or network access.
Done when
New dependencies are reviewed in the pull request, and the lockfile pins every one.
Mark it in the gap checkCommon mistakes
- Choosing by stars, downloads or one score. A Scorecard total combines unrelated checks; Scorecard itself says a low score is not proof of risk, so read the checks that matter for how you will use the package.
- Treating the repository link on the registry page as proof of origin. It is often unverified metadata; only provenance binds a published version to a source commit.
- Reaching internal packages with pip's
--extra-index-url. pip searches every index together and installs the highest version, so a public look-alike with a higher version number wins. - Installing an AI-suggested package without checking that it exists and is the one you meant, which is exactly the name an attacker may have registered.
- Approving a package once and never looking again. A new maintainer or owner can turn trusted code hostile, as in Case study: event-stream and ua-parser-js, two npm package takeovers and Case study: the polyfill.io CDN takeover (2024).
What each signal tells you, and what it does not
No single signal decides intake. Collect several, record them in the pull request, and weigh them against how the package will be used: a parser for untrusted uploads deserves more scrutiny than a development formatter.
| Signal | Where to look | What it does not prove |
|---|---|---|
| Maintenance | Commits and a release in the last 12 months; the Scorecard Maintained check | A quiet project may be stable or abandoned; activity alone cannot tell |
| Maintainers and publishers | More than one maintainer, ideally from different organizations; npm view <package> maintainers | A newly added maintainer can mean better continuity or a takeover |
| Provenance | Verified SLSA provenance on deps.dev or the registry | That the code is safe; only which source and build produced the package |
| Scorecard checks | deps.dev or the Scorecard API: Code-Review, Maintained, Dangerous-Workflow, Signed-Releases | A guarantee: checks see only what they can detect automatically |
| Known vulnerabilities | OSV, through deps.dev or OSV dependency lookup | Anything about flaws nobody has reported yet |
| Install scripts | preinstall, install and postinstall in the package's package.json | What the package does once your code imports it |
Tools and guides
- Tool: OSV dependency lookup
- Tool: SBOM checker
- Practice: Dependency patching
- Review dependency health without treating a score as a guarantee
Combine security practices, maintenance, licensing and product exposure into a recorded adoption or replacement decision.
- Stop dependency confusion and typosquatting at install time
Pin every internal package name to its real source, verify installed bytes against a lockfile, and delay or gate install scripts so a public look-alike cannot replace a private dependency.
- Adopt the OpenSSF S2C2F as a consumer: the eight practices, the four maturity levels and a staged plan with evidence
Assess how your organization takes in open source against the Secure Supply Chain Consumption Framework's 25 requirements, then reach each maturity level in turn with evidence an assessor can check.
- Case study: the Shai-Hulud npm worm (2025-2026)
How a self-replicating npm worm turned stolen tokens into hundreds of infected packages in 2025, how its 2026 successors hijacked release pipelines and trusted publishing, what npm and GitHub changed in response, and the publishing, install and response practices that stop it.
Standards
- NIST SSDF 1.1
- PW.4 Reuse Existing, Well-Secured Software When Feasible Instead of Duplicating Functionality
- OWASP SAMM 2
- Secure BuildSecure Architecture
Sources
- OpenSSF: Concise Guide for Evaluating Open Source Software
- OpenSSF Scorecard: checks documentation
- OWASP Top 10:2025 A03 Software Supply Chain Failures
- OWASP ASVS 5.0.0: V15 Secure Coding and Architecture (V15.2.4). Version 5.0.0.
- CISA: Widespread supply chain compromise impacting npm ecosystem. 23 September 2025.
- Spracklen et al.: We have a package for you! Package hallucinations by code-generating LLMs (USENIX Security 2025)
- npm docs: npm ci. npm v12.
- npm docs: npm install-scripts. npm v12.
- pnpm docs: build settings (allowBuilds, strictDepBuilds)
- pip docs: secure installs (hash-checking mode)
- pip docs: pip install (index options and dependency confusion warning)
- uv docs: package indexes (first-index strategy, explicit indexes)
- npm docs: scope (associating a scope with a registry). npm v12.
- NuGet docs: Package Source Mapping
- deps.dev API v3 (provenance, attestations, Scorecard and advisories)
- OWASP SAMM: Secure Build (Software Dependencies stream)
- NIST SP 800-218: Secure Software Development Framework (SSDF) Version 1.1. February 2022.