Code. All of us depend on it, some of us write it. A lot of it is reused, usually in the form of libraries which are included in our code as dependencies either directly (by us) or transiently (as part of another dependency), and most of the time we have very little idea who is responsible for writing or maintaining these libraries. We have no idea of their motivations, their political affiliations, anything about them in fact. To put it another way, we are putting a large amount of trust (that their code does what we expect it to and nothing more) in mostly complete strangers.
Is this wise?
Recent events suggest not. Last week it emerged that the developer of a popular NPM library ‘tweaked’ the code so that it would detect the IP address of the machine it was running on. If the IP was in a known Russian or Belarusian range the code would attempt to delete all the files on the machine. This code was published to NPM as the latest version of the library and is also included in many other libraries, further details here.
A few months ago the developer of different, but also popular NPM libraries intentionally introduced code changes which caused infinite loops and the printing of gibberish as a protest over the fact that they were not getting any financial compensation even though these libraries were being used by many profitable organisations.
Of course, developers maliciously changing their own code to make a point is nothing new - many years ago I heard a (possibly apocryphal) story about a mailshot to customers being doctored so that the richest received a letter with the salutation: “Dear Rich Bastard”. The important difference, though, is the impact these malicious changes have: the blast radius can be massive with unintended and unforeseen consequences. Given these examples (and no doubt there are others) the only possible conclusion is that you can’t and shouldn’t trust any 3rd-party code that you use. Obviously this applies to both open and closed source code, but given the ubiquity of open source the risks and consequences are much more likely.
The benefits of open source software are indisputable, though, and we all want to continue to enjoy them. So, how can we acknowledge the inherent untrustworthiness of 3rd-party code whilst still reaping the benefits? There are actions you can take which will mitigate the risks and minimise the blast radius if any malicious changes are introduced to your dependencies by their legitimate developers, and I’ve summarised what these are in the points below:
If possible do some due diligence on the developers behind the libraries you are using. Have they any kind of reputation, good or bad? Are they backed by a widely respected and known OSS organisation (CNCF, Apache, The Linux Foundation etc) or a company active in the open source community? If so, the risks of malicious code being introduced are considerably lower than if it is a lone developer making a point.
Run your code in an environment that obeys the principle of least privilege. In other words, only give it the permissions it needs to carry out its function. For example, if there is no reason for the code to access Internet endpoints don’t allow it external access.
Use the lock file feature provided by your chosen package manager. This file contains the exact version of each dependency you have imported, so even if a range of versions for a dependency have been specified any updates will not be automatically picked up when your code is rebuilt. This helps prevent the accidental inclusion of versions you might not want.
When considering what programming language to use for your next project take into account its package manager ecosystem and the philosophy behind how dependencies are used. NPM, for example, seems to have taken the “do not repeat yourself” mantra to an extreme, meaning that there are packages for the most trivial functions. The consequence of this is a dependency tree so large that it is impossible to audit.
Use static and dynamic application security tools (SAST and DAST) against your code and take urgent notice of any critical or high CVEs that are reported.
- 3rd-party code is untrustworthy
- Lock down your dependencies
- Use SAST and DAST tooling
- Run your code with the minimum required privileges
- Perform due diligence on the maintainers of your dependencies, especially the critical ones
- Think carefully about whether to use a dependency or write the code yourself. Obviously don’t reinvent the wheel but using a dependency instead of writing a few lines of code; really?
Jetstack is already working with a number of organisations to help them manage and reduce the risks of using 3rd-party code. If you would like to know more on how to address these particular issues you can set up a discussion by contacting us here.
Cover photo by David Leveque on Unsplash