The number of attacks and vulnerabilities popping up every week in npm is becoming ridiculous, and the problem just keeps growing.
Last week, we had a very serious attack where the account of a major maintainer "Qix" was compromised, and today, once again, another important one, an attack on the tiny-color library, potentially affecting more than 180 packages.
And of course, the most common type of attack is a "Supply Chain Attack".
The risks in the JavaScript ecosystem have always been there, especially with the huge number of dependencies whose origins we don’t fully know. But in recent weeks, we’ve seen more and more news of libraries with millions of downloads being compromised.
The problem is that in JavaScript we often rely on hundreds of packages, and it only takes one being contaminated for the attack to reach your project. You may even be using dozens of packages without realizing it, because they are dependencies of dependencies of something else you’re using.
What is a “Supply Chain Attack”?
A "Supply Chain Attack" is like a modern Trojan horse. Instead of attacking your application directly, they compromise a popular library, which then ends up running inside your application with different objectives. It can even reach CI/CD pipelines, production environments, and more, with countless possibilities for damage or exposure of sensitive data.
Why is it so risky in npm?
- High dependency: a single npm install can bring in dozens of indirect libraries you don’t even know about.
- Excessive trust: we blindly assume that everything on npm is safe.
- Dangerous automation: many CI/CD pipelines update dependencies automatically, opening the door for attacks to spread.
What to do?
Lock versions in your package.json
The caret "^" is your worst enemy. It’s better to update dependencies consciously than to let any “Minor” or “Patch” version install automatically.
Following Semantic Versioning, we have MAJOR.MINOR.PATCH
"library-example": "^6.1.0" // installs Minor and Patch versions
With the caret, any version like 6.1.1, 6.1.2, or 6.2.0 will eventually be installed in your project. If one of those versions is compromised, you’ll be using it without knowing.
"library-example": "6.1.0" // installs only that specific version
Audit your dependencies
Don’t fall into the "install and forget" trap. Dependencies must be reviewed periodically, because even very popular libraries can be compromised.
Check what you install and use tools such as:
These tools detect known vulnerabilities and help you prioritize security patches.
Also, it’s good practice to check the state of a library before installing: when was it last updated? is there activity on GitHub? how many maintainers does it have?
A library that’s abandoned or maintained by just one person is far more vulnerable to being taken over by attackers.
Minimize dependencies
Every new library you add is a potential entry point into your application. Many times, we install a package for very simple tasks, it’s often better to write 20 lines of your own code than to bring in yet another unknown dependency.
Fewer dependencies = less attack surface, fewer updates to monitor, and a more predictable project. Not everything has to come from npm.
Conclusion
In npm, trust is delegated far too easily. Be careful with what you bring into your project, your security depends on it.
Top comments (0)