A typical application contains a small amount of code written by your team and a very large amount written by strangers. Each dependency brings its own dependencies, and the resulting tree routinely runs to hundreds of packages that execute with your application's privileges. Supply chain attacks target that trust, because compromising one widely used component reaches everyone downstream at once.
The forms these attacks take
- Compromised package — a legitimate library is modified to include malicious behaviour, either by attacking the maintainer's account or by a maintainer acting maliciously.
- Typosquatting — a package published under a name closely resembling a popular one, catching typos and careless copy-paste.
- Dependency confusion — a public package published under the name of an internal one, exploiting resolvers configured to prefer the public registry.
- Build system compromise — the source stays clean while the build injects the malicious code, which makes source review alone insufficient.
- Compromised update channel — malicious code signed and distributed through a legitimate vendor mechanism, which is what makes this class so damaging.
- Malicious install scripts — code that executes at install time, before any application code runs, frequently on a developer machine or CI runner with broad access.
Why they work so well
Dependencies are trusted implicitly. Their code executes with the same privileges as yours, and almost nobody reviews the source of a transitive dependency four levels deep.
Automation compounds it. Continuous integration pulls the latest matching version, builds and deploys, sometimes without a human seeing what changed. A compromise upstream can therefore propagate into production quickly and quietly. And because the resulting artefact is signed by your own pipeline, downstream consumers have every reason to trust it.
Protecting the build pipeline
The pipeline deserves the same protection as production, because it can write to production.
- Treat CI credentials as production credentials — scope them tightly and rotate them.
- Prevent pipeline definitions from being modified without review, and require review for changes to build steps as well as application code.
- Isolate build runners so one compromised job cannot reach another, and prefer ephemeral runners that do not persist state between builds.
- Restrict outbound network access from build environments, which limits both exfiltration and the fetching of additional payloads.
- Log build activity and alert on unexpected changes to the build process itself.
- Store artefacts in a registry with access control, and sign them so downstream consumers can verify origin.
Managing dependencies deliberately
- Pin versions with a lockfile so builds are reproducible and an upstream change cannot arrive unnoticed.
- Generate a software bill of materials, so that when a vulnerability is announced you can answer "are we affected" in minutes rather than days.
- Configure package resolution to prevent dependency confusion, ensuring internal names resolve internally.
- Review new dependencies before adoption — maintenance status, maintainer count and how much transitive weight they add.
- Reduce the tree where practical. A dependency added for one small function is a permanent liability.
- Automate vulnerability alerts on dependencies, but triage by reachability rather than treating every advisory as urgent.
- Disable install scripts where your tooling allows it, or vet them explicitly.
Assume something will get through
No dependency programme catches everything, so runtime containment matters. An application that runs with least privilege, cannot reach arbitrary internet destinations and is monitored for unexpected process or network behaviour limits what a malicious package can accomplish.
This is also why the earlier egress-filtering advice appears repeatedly: a compromised dependency that cannot phone home is substantially less useful to its author.
Related from TechBiz Security
Sources & further reading
- CISA — Supply Chain Security
- NIST — Secure Software Development Framework (SSDF)
- SLSA — Supply-chain Levels for Software Artifacts
- OWASP — Software Component Verification Standard
0 comments
Leave a comment