A few weeks ago, Facebook announced the open-source release of Yarn: a new client for the npm registry. While a few folks expressed concern, it appears to be a solid example of open-source development. Facebook, Google, Exponent and Tilde had similar challenges in using the default npm client. Instead of each trying to work on something themselves, they got together and iterated on top of npm. The result is an alternative client that offers some notable improvements without losing the power of the underlying npm registry.
Yarn markets itself as “ultra fast”, “super reliable” and “mega secure”. While it’s true that Yarn is often much faster, and that the new lockfile ensures more consistency when your application is installed, the security claims are a little over-optimistic.
What Yarn Does for Security
When Yarn says they are “mega secure”, what they are referring to is the fact that they use checksums to verify that the package you request is the package you receive, without any modification.
You can see this in action by opening the
yarn.lock file within one of your projects. Here’s an excerpt from one:
The snippet above shows that we’ve requested the
moment package, and the package resolved to the following url:
Of particular interest here is the section after the hash:
This is the checksum of the file, computed using Secure Hash Algorithm 1 (SHA-1). If you download the package at the URL locally, you can verify the checksum in the command line using either the
sha1sum command in Linux, or the
shasum command in Mac OSX.
# On Linux
# On Mac OSX
Those commands will output the SHA-1 hash, which matches the hash in the policy file.
So, let’s say that you request that package, but it differs in some way from what is noted by the checksum in the
yarn.lock file. For example, I added one line to the README.md file, recreated the
.tgz archive and then ran
shasum again. The new hash was:
This new hash is not the same as the hash you were expecting, so you can tell that something has changed: what you requested does not match what you received. This something could be innocuous—perhaps there was an error in the transmission of the file and the file was corrupted in some way. It could also be more malicous—perhaps an attacker got hold of the package and manipulated it in some way. The checksum lets you know something went wrong, enabling you to investigate further.
How can attackers tamper with a package?
While ensuring data integrity is certainly a nice feature, it’s worth asking how an attacker would manipulate a package in the first place.
One way is to modify the package at the source—in the registry that hosts it. Most users download packages from npmjs.com, which—as far as I’m aware—has had no instances of attackers modifying code at the registry level.
The other possibility is to modify the package in transit, while it’s being downloaded. Again, most packages are downloaded from the npm public registry which uses HTTPS. While it’s possible to modify in transit packages over HTTPS, it’s far from trivial.
Checksums become more useful when you’re hosting your own repository. While offerings from Artifactory and Nexus are well secured, if you’re rolling your own, it’s possible that there could be some kinks in the armor enabling packages to be manipulated directly on the registry. And while we (very strongly) advise you not to, we have seen local registries being served over HTTP. In these scenarios, it’s much easier to modify the package, making checksums much more important.
If you’re using the npm public registry, or hosting your own over HTTPS using a commercial offering, the sort of tampering that checksums provide protection against becomes less of an issue. It’s a security feature, but a minor one.
yarn.lock for fixed versions
In addition, the
yarn.lock file itself introduces a wrinkle in your security plans. Like npm shrinkwrap, the purpose of the
yarn.lock file is to lock in specific versions of your dependencies. The advantage of using a lockfile is that if I install a Yarn project on my machine, and tomorrow I install the same application in a production environment, I know that the two installations will use exactly the same dependencies—even if a new version has been released.
It’s great for consistency, but lockfiles are biased towards not updating the packages you use. Unlike using semver rangers, the only way to upgrade to a new version of a dependency is to edit or recreate the lockfile to allow for it. The onus is now on developers to make sure that they keep an eye out for updates that may carry critical vulnerability fixes, even more so than with semver-based approaches like those used in
That’s not to say that you shouldn’t be using lockfiles. By all means do so if the consistency is important for your application, just be aware that you’ll need to have the proper steps in place to ensure that you’re actively reviewing and updating insecure packages.
The missing security link
Checksums provide a layer of security, but they do nothing to ensure that the original package you’re trying to get is itself secure. In the world of open-source development, that’s a much larger issue. While most open-source maintainer’s hearts are in the right place, it’s rare that these packages are being written with security as a core requirement. When we pull these packages into our own projects, we do so blindly—without a firm understanding of all the dependencies that come as a result, and what security issues may be lurking in them.
For example, the
moment package that we looked at earlier includes a regular expression denial of service vulnerability for which there is a patch. Installing the package with Yarn won’t tell us that. Scanning dependencies for known vulnerabilities is a different, and bigger, security issue than the one Yarn solves.
How to actually be mega secure?
Thankfully, Yarn being built on top of npm means that it plays pretty well in the ecosystem. Yarn has a few kinks at the moment, but as those get resolved, existing tools around security should work with minimal changes.
For example, to address known vulnerabilities in npm packages, we currently recommend running
snyk protect as part of the
post-install step in your Node.js applications. If you run
yarn install that still fires so
snyk protect continues to run, scanning your dependencies for known vulnerabilities.
We think Yarn is pretty darn cool and judging by the amount of attention it has received, it seems many would agree. It’s typically faster, and the new lockfiles will be handy for many organizations looking for more consistency in their installations.
But while it’s great to see Yarn trying to bake security in from the beginning, they’re being a little too confident in expressing that they are “mega secure”. The checksums aren’t the problem; the marketing is. Checksums help ensure that the integerity of your data is maintained, but that’s a relatively minor issue in the Node.js ecosystem. Far more critical is ensuring that those dependencies are secure in the first place.