Typical JS project: hundreds of dependencies. Each runs with full trust.
Supply chain attacks
- event-stream (2018) - new maintainer added crypto theft
- ua-parser-js (2021) - 8M downloads, compromised
- xz-utils (2024) - multi-year social engineering backdoor
Fundamentals
Lock files: Pin exact versions. Commit them. Use npm ci not npm install.
Minimise: Can you write it in 20 lines? How many transitive deps? One maintainer?
Audit:
npm audit
pip-audit
govulncheck ./...
SBOMs
Software Bill of Materials - inventory of components, versions, licenses.
Why: New CVE drops. With SBOM: instant query. Without: manual searching.
npx @cyclonedx/cyclonedx-npm --output-file sbom.json
syft . -o cyclonedx-json > sbom.json
Updates
Automate: Dependabot, Renovate open PRs for updates. Auto-merge patches with passing tests.
Pin strategy: Ranges in manifest, lock file for exact versions. Update lock regularly.
Registry security
Private registry: Internal packages in npm Enterprise, Artifactory, GitHub Packages. Prevents dependency confusion.
Namespace: Register your org's scope even if not publishing. @yourcompany/ blocks attackers from claiming it.
Evaluating dependencies
Before adding: Last commit when? How many maintainers? Known vulns? Install scripts? License compatible?
Tools: Socket.dev, Snyk Advisor.
The takeaway
Lock files. Audit regularly. Generate SBOMs. Automate updates. Private registries. Minimise what you depend on.
