No chain is stronger than its weakest link, and this rule carries into software. The continually connected and updated nature of modern software has dramatically expanded its supply chain and, with it, potential security risks. The Sunburst hack is a glaring example of what that risk entails and how even the most sophisticated organizations are vulnerable when a software provider is attacked. One weak link in the software supply chain, and even the Pentagon can be hacked.
But software supply chain attacks didn’t begin with Sunburst – they’ve been around for a while. In 2017, MEDoc, a Ukrainian accounting software package, was hacked in a supply chain attack, and the malicious NotPetya code caused more than $10bn in damage, disrupting the operations of multinationals including FedEx, Maersk and Merck. In 2013, US retailer Target was attacked via its heating and ventilation supplier, with the hackers gaining access to 40 million debit and credit card accounts. In 2016, a Panama-based law firm was victim to a supply chain attack that leaked 2.6 terabytes of sensitive client data.
The Mechanics of an Attack
The premise of a supply chain attack is simple. Malicious actors go after third-party software components created and maintained by individuals other than the primary software builder and commonly live in a centralized registry. They exploit design flaws and weaknesses within these third-party components to introduce malicious code (either directly into the consumed source or indirectly through a dependency tree constraint), and this allows them to gain access to internal systems and end-users. It’s not just centralized sources that are vulnerable: decentralized sources of third-party components can be attacked, too.
Software supply chain attacks are highly dangerous and highly effective. Just as attacking a public cloud gives malicious actors the potential to hit multiple organizations at once, targeting a software supply chain allows them to compromise a wide range of organizations in one hit.
Although these attacks are not a recent phenomenon, their risk is growing. That’s because, in trying to maintain a rapid development pace, software developers have increasingly shifted from coding functionality solely by themselves to assembling applications via a combination of proprietary and open-source code. Today’s code repositories are very different from the repositories of even a few years ago, commonly consisting of proprietary code and open source packages, containers, infrastructure as code and even build configurations. Each of these is a potential attack vector in the software supply chain.
How Developers Can Build in Resistance
The risk may be increasing, but developers can code in resistance to software supply chain attacks.
The first step is to defend against dependency confusion attacks: a process in which malware is deployed within an organization’s network by overriding privately-used packages with malicious, public packages that use the same name. As part of the software supply chain, developers automatically pull open-source packages using package managers and build tools. If these are not configured only to pull packages from the private registry, packages with the same name can be pulled in from a public code repository. This design flaw means all an attacker needs to do is scan an organization’s public repository for private package names and upload a malicious package with an identical name. Automated build processes will do the rest and pull in the malicious package instead of the intended, internally-created one.
To protect against this, developers should be using scoped namescapes in their work. Scoped packages lock the namespace of the package and map it to a specific user or organization, preventing package substitution. Another tactic is to use repo-specific configuration for explicit upstream registry definition, to give package managers like pip and npm explicit guidance so they don’t start looking up the public registry to find a newer version of the package and accidentally pull in a malicious package.
Another step developers should take is disabling arbitrary install commands by open-source packages. By default, some package managers, like npm, allow any package that is being installed or uninstalled to execute arbitrary commands. This leaves organizations wide open to typosquatting attacks or hidden backdoor mechanisms. The solution is to ensure packages are strictly vetted before installation and aren’t added blindly or via wildly insecure copy and paste. Developers should then add the –ignore-scripts command-line argument to the npm install command to disable the execution of arbitrary commands by packages. It is worth considering adding ignore-scripts to a .npmrc configuration file to disable arbitrary command execution across team projects.
Two-factor authentication (2FA) is also crucial. Although 2FA is a critical yet straightforward way to protect accounts that access registries and ecosystems, in January 2020, it was reported that fewer than 10% of developers on npmjs had 2FA enabled – despite this feature being available since the end of 2017. All developers must enable this feature as in the open-source community, security extends beyond individual concerns and impacts others.
Collective safety concerns are also a vital issue when openly collaborating on and engaging with open-source software. These actions increase the risk of accidentally leaking or sharing confidential information that is then exposed to the public eye. To avoid this potential data exposure, developers should not be storing sensitive information in a repository, in config or code. They should also avoid publishing packages or Docker images with potentially sensitive information, which could end up in public registries.
Software supply chains enable our current rapid development rate, but the speed they offer comes at a price. Third-party software components are attractive attack vectors for malicious actors and, without a careful protection plan, developers can leave their organizations incredibly vulnerable to attack. While the developers can’t stop people from hacking and exploiting their systems, they can stop them from finding success. By identifying and fixing supply chain weaknesses and practicing the highest levels of security hygiene, developers can protect themselves and the broader developer community.