
Patrik Nordlén
We're proud to release GardWatch, our solution for verifying the legitimacy of third-party dependencies before they are added to your project. This has so far been a blind spot which has made it possible for threat actors to achieve large-scale compromises, by publishing malicious dependencies that have subsequently been used in thousands of CI/CD pipelines and local development environments without any checks in place.
Last week was a rough one for software supply chain security. Between late February and March 22nd, a threat actor known as TeamPCP managed to compromise Aqua Security's Trivy vulnerability scanner, its GitHub Actions, and over 60 npm packages. Shortly thereafter, Checkmarx's kics tool suffered the same fate. By March 20th, TeamPCP had deployed a self-propagating worm that spread through the pypi and npm ecosystems. The current estimate is over 60,000 compromised servers globally, with credential theft from CI/CD pipelines across thousands of repositories.
This isn't an isolated incident, rather it's part of a pattern we've been seeing more and more of. It's always been important to monitor third-party dependencies but the efforts have largely revolved around managing vulnerabilities in them, with hijacking attacks being more of a theoretical risk than a real one. In the past few years that has changed to the software supply chain becoming a primary target, and we need to talk about why and what we can do about it.
Modern software relies heavily on third-party dependencies. An average npm package pulls in 4.39 other packages as dependencies. The average project uses 86.55 packages. When you install a single npm package, research shows you're implicitly trusting 79 third-party packages and 39 maintainers.
That's for one package!
Most projects have dozens or hundreds of direct dependencies. Sure, there's overlap in the dependency trees, but you're still talking about hundreds or thousands of packages from hundreds or thousands of maintainers. And with AI coding assistants becoming more common, it's easier than ever to just add another dependency without thinking too hard about it.
When you install a package, you're making a bunch of trust assumptions:
You found the right package. Typosquatting has been a problem for years, but now we're also seeing "slopsquatting" where AI agents hallucinate plausible-sounding package names that don't actually exist. Attackers have caught on and started publishing malicious packages with those hallucinated names. We've seen examples like "starlette-reverse-proxy", "requests-httpx", "typesutil", and "pystyle".
The package was written securely. One study found that in-house code typically makes up 10-20% of an enterprise codebase. The other 80-90% is third-party code. To the extent that you enforce security practices in your own code, you now have 4-5 times as much code to apply those standards to.
The package is actively maintained. Maintainers need to respond to security issues, assign CVEs, and release updates. Abandoned packages are a real problem.
The repository and CI/CD pipeline are secure. Almost every package these days is built from a CI/CD pipeline connected to a git repo. You're trusting that setup is locked down so only authorized people can publish new versions.
Maintainers follow security best practices. Their accounts need to be secure. We've seen multiple incidents where attackers compromised maintainer accounts and used them to publish malicious versions.
Maintainers aren't malicious. This one's uncomfortable to think about, but you're ultimately trusting that the people maintaining these packages aren't deliberately putting bad code in them.
Each of these assumptions has been violated in practice:
Attackers publish malicious packages using names AI models hallucinate — like "starlette-reverse-proxy", "requests-httpx", and "pystyle".
Read more →Vulnerabilities in widely-used libraries that were trusted implicitly for years before critical flaws surfaced.
Read more →The hunt for maintainers of a popular Rust library left it vulnerable with no one to fix discovered flaws.
Read more →A "helpful" new maintainer planted a backdoor in xz-utils. The colors.js maintainer intentionally added denial-of-service code.
Read more →18 popular code packages hijacked via a compromised GitHub account, rigged to steal cryptocurrency.
Read more →A progression of CI/CD supply chain attacks from September 2024's Shai-Hulud through to the TeamPCP CanisterWorm campaign.
Read more →Before installing a package, there are things you can and should check:
v1.2.3 suddenly jump to v12.58.99?Sites like scorecard.dev and deps.dev are useful for this kind of metadata analysis.
But you can go deeper. Download the package and look at how it's configured to act during installation. Watch for these red flags:
The problem is, this is a lot to check manually. And you need to do it for every package you install, including all the transitive dependencies. It's not realistic to expect developers to do this consistently, especially when AI agents can spin up code that uses new packages in seconds.
That's why we built GardWatch! It automates these checks and instantly flags if there are package health concerns worthy of your attention.
GardWatch uses a scoring system. Each package starts with a perfect score. Tests remove points based on what they find. Some tests cause immediate failure - if a package appears on a list of known malicious packages, that's it. Others just lower the score - things like low popularity or no recent updates.
GardWatch has two scanning modes:
Metadata scanning is fast. It checks package information from registries and metadata services. This catches hallucinated packages, packages with low trust scores, poor security practices, and suspicious version jumps.
Deep scanning downloads the package and analyzes it with static analysis. This catches malicious install scripts, credential extraction attempts, suspicious system calls, and obfuscated payloads.
For example, when we ran deep scanning on the compromised litellm package from the CanisterWorm campaign, GardWatch correctly identified the malicious .pth file that executes every time you run the Python interpreter.
Fast. Checks package information from registries and metadata services.
Thorough. Downloads the package and performs static analysis.
You can use GardWatch in a few different ways:
Manual checks & CI/CD integration
Monitors lockfiles in real time
Integrates with AI coding assistants
The software supply chain is only as strong as its weakest link.
Don't let your dependencies be that link.
Sources:
Have questions or feedback? Get in touch.