Can You Trust Your Own Code Anymore?

If we went around and asked C-level execs about the code that sits behind their web and mobile applications, most of them would likely believe that their company is in full control of it. After all, it’s their own product, but those familiar with the web development ecosystem know that this is far from actual reality.

A company’s code is in fact composed of chunks of internally-developed code and several pieces of external code. On average, modern web applications have over 1,000 of these pieces of externally sourced code, more commonly referred to as modules or code dependencies.

Within the current paradigm of web development, this means that product development is significantly faster. Development teams can rely on community-built and reviewed (open-source) code like JavaScript frameworks that provide the solid ground on top of which applications can be built.

Then there’s the matter of who owns the code. The hundreds of modules that companies use are completely out of their control. They can, of course, manage versions and updates and can even vet each of these modules thoroughly, but this is often infeasible and development teams end up trusting the maintainers of most of these modules - both trusting their reliability and also their security.

This leads us to the main issue: the lack of privilege separation in the JavaScript ecosystem. In a distinct fashion to what happens with other programming ecosystems, in JavaScript, both first-party and third-party code have the full privileges of the application. In other words, third-party code can access the most sensitive parts of the application, such as the network or file system. So, should we even trust this code?

The dangerous web supply chain

Before answering this question, we need to understand the so-called web supply chain. Within the web, we have applications using pieces that are sourced from external suppliers (such as the JavaScript modules mentioned). These modules, in turn, can rely on third-party code themselves, and so on. We end up with a very complex chain of code dependencies, which easily number in the thousands.

In theory, if attackers somehow manage to gain control of one of these dependencies, they have full control to be able to insert malicious code - let’s say something like a Magecart credit card skimmer - and then release a new version of the dependency, just as if it were a normal update.

Applications using this dependency could accept the update without properly analyzing the code and start serving this skimmer to their end-users without even being aware.

This scenario has happened more than once. One of the most notorious cases happened in November 2018, when an attacker managed to gain control of the event-stream dependency. This enabled the attacker to add a new dependency that contained malicious code which, in turn, harvested the credentials and private keys of users of the cryptocurrency wallet, Copay. Developers from Copay failed to detect the malicious code and released several builds of the application containing the malicious code. This and subsequent incidents have shown that the web supply chain contains too many weak links that can be exploited.

A breach in 20 accounts could trigger a global attack

Recent research by a team of researchers from the Technical University of Darmstadt shows that the reach of these web supply chain attacks is much higher than commonly perceived. By analyzing the number of module maintainers and the reach of dependencies, these researchers found that when developers install an average module, they are implicitly trusting 80 other packages that constitute dependencies.

With modern web apps trusting over a thousand of these modules, things quickly rack up. A breach in a single one of these could mean a serious security threat to several companies - depending on the package reach.

Whilst studying the reach of modules and their actual maintainers, something much more concerning was uncovered - as of today, there are 20 maintainer accounts that between them reach more than half of the ecosystem.

In other words, if attackers could somehow gain control of these accounts, they could potentially launch a global web supply chain attack to infect thousands of companies in one hit.

Of course, we don’t actually know how such a scenario would unfold. Perhaps such high-profile account takeovers could quickly be notified to NPM - the organization that manages the whole ecosystem - and taken down. Or perhaps the new Security Insights API provided by NPM would help developers understand that something is wrong with the module and reject it.

The error margin is still too large. In all likeliness, several companies would unsuspectingly accept the update and bundle malicious code into new versions of their application - as has been witnessed in the past. Amongst all of these would be applications used by millions of people whose data would be stolen.

This leads us to a more pressing question: how can companies reduce this error margin and actually achieve some level of security?

Responsible code use - active application monitoring

As mentioned before, there are some solid initiatives in motion to plug some of the ecosystem’s security gaps - namely undertaken by NPM. Going back to the study by the Darmstadt team, researchers highlight the need to educate developers about web supply chain risk - each new dependency should be seen as a substantial increase to the attack surface of the application.

Additionally, they point out the need to train and vet the most significant maintainers of the ecosystem, to reduce the risk of attacks with global reach. However, most of these efforts are only just starting out, leaving companies facing a lot of uncertainty. Halting the use of third-party code completely is out of the question. Vetting external modules is highly encouraged but is too burdensome to be done manually.

There are too many ways in. We have got to a point where it seems impossible to guarantee that no third-party will eventually start injecting malicious code.

Using code responsibly only partially answers the question. To effectively prevent web supply chain attacks, it must be coupled with some type of application monitoring. With this, security teams should be able to detect any sort of injected malicious code in real-time, so that they can stop the attack at its inception.

We’re certainly heading in the right direction to secure the web supply chain. By using external code responsibly and gaining full, real-time visibility of malicious code, companies can put themselves several steps ahead of attackers to ensure that their users and data remain safe.

What’s Hot on Infosecurity Magazine?