My good friend Cormac Brady beat me to the punch with his post this week, discussing the risks of upstream changes to libraries we rely on. Log4J, faker.js and color.js being two recent examples.
While the issues in the two were different (with Log4J it was a long standing vulnerability, faker.js and color.js explicit sabotage by the maintainers), the end result is the same: a loss of control and expensive fire-drill to remediate.
What to do? At one end of the spectrum you can choose not to depend on anything. A quick moment of introspection should persuade you that way leads to insanity. Do you trust your operating system? Compiler? Silicon? For most of us, building from the ground up isn’t viable or desirable. Advocating for that will have you laughed out of the boardroom.
Taking the tin-foil hat off, here are some concrete steps for dealing with your dependencies.
In most package management languages, one can declare a dependent library as either exact version number match or greater or equal to. For example, in NPM, prefixing the verison number with
>= says ‘this version or anything subsequent’. While that might reduce maintenance, it increases risk of introducing undesirable changes.
Use static code analysis in your CI chain
Code analysis tools are not a panacea, but they can catch some types of vulnerabilities. Making them part of the your build and ensuring the output is reviewed, prioritized and added to backlog can only help.
Locally host browser dependencies
For anything browser based it’s tempting to rely on other sites to host dependent JS libraries, fonts, etc. Doing this carries some risk: how comfortable are you that the site won’t be corrupted or blocked for the client? Safer to download those dependent files and configuration manage them yourself.
Ensure testing is covering dependencies
Do both automated and smoke testing have sufficient cover of dependent libraries or do they treat them as more than a black box?
Make it easy for your team to submit pull requests
You’re reliant on Open Source Software so you should play it forward. Put clear policies and simple management approval in place for your team to contribute pull requests to upstream libraries for fixes and improvements. Don’t just be a consumer!
By now, you’ve probably seen the XKCD on dependencies: too many core libraries are maintained by too few people. If you’re a corporation that depends on the library, you can do something about it. Whether by employing a maintainer, sponsoring a project or giving your own team time to contribute. The more eyes on a project, the less likely it will either die or be corrupted.
Worst case a library corruption makes it into your code. Depending on your architecture and deployment style, blast radius can be contained by deploying first to a sandbox or, for larger applications, a subset of users. Couple this with a solid roll-back plan and you might catch the issue before too much damage is done.