The increase in the demand for innovative software has effectively reshaped the software development industry itself. Today, speed and agility are paramount and development teams are pushed to deliver highly advanced applications in record time — which means that writing every single line of code from the ground up is often not a sustainable practice. As the NIST puts it, “This ecosystem has evolved to provide a set of highly refined, cost-effective, reusable ICT solutions.”.
Here’s where open source components, code reuse, and third-party integrations gain unparalleled importance.
Using open source libraries is now the status quo in development. Studies regarding programming language adoption found that the most important selection factor is the existence of open source libraries.
Using open source libraries is now the status quo in development. Studies regarding programming language adoption found that the most important selection factor is the existence of open source libraries.
The evolution of mainstream programming languages such as JavaScript has led to the emergence of libraries and frameworks — two major promoters of development speed.
A typical JavaScript development process is built upon open source components, namely Node Package Manager (npm) packages. In such a scenario, the process often begins by using a JavaScript framework, such as React.js, to create a boilerplate application. This step alone involves downloading more than 1000 total dependencies, just for an application boilerplate.
What this means is that the usual web application starts by reusing over 1000 pieces of third-party code — which is most often open-source and maintained by volunteers. This open-source nature presents a double-edged sword, as it increases the attack surface during the development process.
Besides using open source libraries as dependencies in a development project, another very common practice in web development is to integrate the web application with third-party services, to access services without having to develop them in-house. A typical application can quickly rack up several external scripts to provide this extra functionality with little extra effort.
Analysis of JavaScript applications paints a clear picture: two-thirds of applications’ code are third-party scripts.
One of the most comprehensible examples of integration with a third-party service is an analytics service such as Google Analytics. This integration is achieved by directly loading the external script in the web app’s client-side, with a single code snippet. As so, the web app can directly communicate with the third-party service, load its code, and grant it explicit access to webpage events that are triggered by the end-users (button onclick, mouseover, form submit, among others).
It’s clear that both for code dependencies and third-party scripts are a crucial part of today’s web and mobile applications. But what happens when their third-party developers or providers are attacked?
Amidst this rush to make the software development process as swift as possible and to easily integrate external services, security has remained an afterthought.
Open source projects are all about collaboration: projects are developed and maintained by volunteers who have full control to modify their code. This should raise no concerns when we consider small-scale projects. But what happens when a contributor with malicious purposes compromises a code dependency in a major framework such as React.js? If this was to happen, it would inherently compromise thousands of projects which are using the framework.
While a compromise of a direct dependency to a major project would likely be detected and fixed quickly, a compromise of a dependency’s dependency (and so on), might fly under the radar. Instead of directly compromising a direct end-product dependency, an attacker can trace a series of dependencies to a smaller, not-so-well-maintained project and exploit it. The ensuing effects manifest themselves downstream, reaching their targets. We have seen something very similar happen recently in the Copay event-stream incident, where the attacked company released versions of their product that contained malicious code and were able to steal user credentials.
The same goes for when we consider integrating third-party scripts. This integration process enables a swift, plug and play approach to extend an application’s functionalities. However, if the third-party script provider gets breached by attackers who inject malicious code, all applications that load this script will directly start serving this malicious code to their end-users.
When we think about widely used scripts such as Google Analytics, which come from large companies, we don’t expect attackers to be able to compromise them. However, most available third-party scripts come from small companies or individual developers whose security systems can be very simple or even non-existent.
Most third-party code providers don’t have enterprise-grade security systems. In light of this, attackers have been able to breach thousands of high-profile companies in a single attack, without ever having to breach their servers or code.
The holy grail of cyber attacks is now to target code dependencies or third-party scripts. And this has led to this rapidly growing global threat we have come to know as supply chain attacks.