Securing your modern software supply chain
Software supply chain security concerns are more prevalent than ever. The U.S. Pentagon, Department of State, Department of Homeland Security, Microsoft, FireEye – this is just a partial list of the government agencies and companies hacked as a result of the attack on SolarWinds’ proprietary software – the Orion network monitoring program. The scope of the attack and its blast zone, together with the identity of the assumed instigator, ensured the attack occupied the headlines across all major media outlets across the world. For the cybersecurity industry, though, the SolarWinds breach brought to the fore an old-new attack vector by the name of software supply chain attacks.
What is software supply chain security?
With the increasing rise of open-source software adoption, software is largely composed of third-party software components that are created and maintained by individuals other than the primary builder of a given software. These third-party software components live, most commonly, in a centralized registry, and as consumers of them, these registries make up the modern software “supply-chain”. Malicious actors can exploit design flaws and the preversaviness of third-party components to compromise end-users and infiltrate internal systems.
What is a software supply chain attack?
Malicious actors may compromise a centralized or decentralized source of third-party software components, with the aim of introducing malicious code directly in the consumed source or indirectly through a dependency tree constraint.
Software supply chain attacks are not new, and are also not that rare for that matter. At Snyk, we’ve been talking about the risk of developers being the conduit of malware distribution since 2018. The SolarWinds attack is just one example out of many others – the ASUS and event-streams attacks from past years, but also more recently, the dependency confusion and Mimecast incidents, to name just a few.
But what has changed is the way that software is built today. A change that has made the risk of a software supply chain attack all the more dangerous.
Why? To maintain a rapid development pace, software development has increasingly shifted from developers coding functionality themselves to them assembling applications via a combination of proprietary and open source code. A code repository today looks entirely different than what a code repository looked like even just 5 years ago and will most likely consist not only of your proprietary code but also different pieces of open source code from – open source packages, containers, infrastructure as code, and probably also build configurations. Each one of the links in this modern software supply chain is a potential attack vector that can be used, as seen in all the examples mentioned above, to compromise a wide range of organizations in one hit.
In February, a perfect example of how one of the links in the modern software supply chain can be used in an attack was reported. Leveraging a method called dependency or namespace confusion, a security researcher and ethical hacker by the name of Alex Birsan managed to get malicious (but benign) packages uploaded into the codebases of Apple, Microsoft, Uber, Yelp, and a long list of other companies you might have heard of.
Birsan summed the results of his efforts in his revelation blog post, “This type of vulnerability, which I have started calling dependency confusion, was detected inside more than 35 organizations to date, across all three tested programming languages. The vast majority of the affected companies fall into the 1000+ employees category, which most likely reflects the higher prevalence of internal library usage within larger organizations.”
What is dependency confusion?
Put simply, dependency confusion results in the execution of malware within an organization’s network by overriding privately-used packages with malicious, public packages using the same name.
How is this enabled?
As part of the software supply chain, various open source packages are automatically pulled in by developers using package managers and build tools. If the development environment is not configured properly to pull in these packages from the organization’s private registry, packages with the same name can be pulled in from a public code repository.
This design flaw is ideal for attackers – all they have to do is scan an organization’s public repository for private package names and then upload a malicious package with the same exact name to a public registry such as npm or PyPi. The misconfigurations and automated build processes will do all the rest of the work, pulling in the malicious packages instead of the internally-created one.
4 best practices to mitigate software supply chain attacks
Software supply chain attacks – including dependency confusion attacks – can be mitigated! To help you protect yourself, below is a list of key software supply chain security best practices that will enable you and your team to reduce risk and mitigate your attack surface.
- Mitigating dependency confusion attacks
- Disable arbitrary install commands by open-source packages
- Enable multi factor authentication across your software supply chain
- Avoid exposure of sensitive information
1. Mitigating dependency confusion attacks
As expected, Alex Birsan’s dependency confusion attack had the effect of bringing about copycat attacks exploiting the very same weakness in the software supply chain of other companies. Here are some steps to take to ensure you are protected:
- Use a scoped namespace – npmjs as one of the vulnerable ecosystems for this attack provides package scopes. The use of so-called “scoped packages” locks the namespace of the package and maps it to a specific user/organization. This mitigates the dependency confusion attack because there is no substitution of an underlying package from the original intent of the user, and an alternate upstream repository.
- Use repo-specific configuration for explicit upstream registry definition – some package managers, such as pip and npm, do their best to resolve package information look-ups when they aren’t provided with explicit guidance. This results, in these clients, looking up the public registries such as npmjs, and PyPI, to find newer versions of a package, leading to substituting the intended one, with a malicious one. In direct correlation to this issue, when using an internal package repository or proxy, such as Artifactory, or Verdaccio, ensure that you aren’t proxying requests for private packages to public registries.
Isaac Schlueter, co-founder of npmjs, put together some elaborate examples and configuration references for the above mentioned counter-measures to dependency confusion in the npmjs ecosystem.
Similarly, Microsoft also released a whitepaper with guidelines on how to mitigate this kind of concern of software supply chain attacks.
2. Disable arbitrary install commands by open-source packages
By default, some package managers, such as npm, allow any package being installed or uninstalled to execute arbitrary commands.
This attack vector has previously been weaponized by numerous malicious packages, such as getcookies, which implanted a backdoor allowing code injection to a running Node.js application server, disguising as an Express application middleware.
Another attack vector is through employing a typosquatting attack, where either through a dependency tree, or by mistakenly typing a wrong package name in the command line, a victim would install a malicious package. A real case that happened with crossenv.
How confusing can dependency names be? Ask yourself, which one of the following is malicious and which is the real package?
Did you click the links to see if you got it right?
No wonder there’s a lot of dependency confusion, and why we’ve been witnessing hundreds of typosquatting attacks on npmjs, PyPI, RubyGems, among other language ecosystems.
How to disable arbitrary commands of npm packages?
- Don’t install packages blindly, or by reckless copy&paste, without vetting the package first. You can use the Snyk Advisor to assess the package’s health.
- Add the
--ignore-scriptscommand line argument to the npm install command, to disable the execution of arbitrary commands by packages.
- Consider adding
.npmrcconfiguration file to disable arbitrary command execution across team projects.
Example, install npmjs packages without them executing arbitrary commands:
npm install fastify --ignore-scripts
3. Enable multi factor authentication across your software supply chain
We are all citizens of the open-source community – as users, contributors or maintainers. We’re more dependent on each other than ever before, and to ensure others can trust us and the software we maintain, authentication is becoming increasingly important.
We can take a look at the share of developers who enabled 2FA on npmjs as a case study of how we’re progressing as a community of developers in our password hygiene to prevent account takeover attacks.
So, how are we doing? In January 2020, it was publicly reported that less than 10% of developers on npmjs enabled 2FA, despite the fact that this feature existed since the end of 2017.
We highly recommend and urge you to take better security measures in your accounts across registries and ecosystems, such as npmjs, RubyGems, Docker, and GitHub, and enable multi factor authentication.
4. Avoid exposure of sensitive information
As the use of open-source software grows, it is becoming a norm to collaborate and engage with folks in the open. This creates the concern of accidentally leaking or sharing confidential information that is then exposed to the public eye.
To avoid potential data exposure you could follow some practices such as:
- Don’t store sensitive information in a repository, in config or code. We have detailed 10 GitHub security best practices for you to drill-down to each and every security practice.
- Avoid publishing packages or Docker images with potentially sensitive information that can end up in public registries. You can follow the 10 npm security best practices guidelines, on how to configure npm packages with proper
Mitigating software supply chain attacks with Snyk
Snyk can help you bolster your software supply chain by preventing the use of vulnerable and malicious packages that find their way into your codebase, including the open source packages and containers you are pulling in to build your applications.
Open source security
For the open source dependencies you are pulling into your codebase, Snyk actively researches, responsibly discloses and provides protection for malicious packages, in addition to vulnerabilities. In fact in 2020 alone, Snyk detected over 700 malicious packages in open source registries.
Snyk has a track record of discovering, detecting, and helping our customers fix these malicious packages. Examples abound. Such as the electron-native-notify dependency attack on npmjs, and remote code execution in strong_password’s Ruby gem. Snyk’s Security Research team also recently published their findings of the SourMint ad-fraud and data-leak that was impacting thousands of mobile applications through a malicious SDK.
Snyk scans your package manifest files and builds a complete dependency tree that lists all the packages you are pulling into your application, including via transitive dependencies. Your dependencies are then correlated with our Snyk Intel vulnerability database, and if Snyk identifies a reference to a known malicious package, the relevant package is flagged as a vulnerability. Depending on how you’re deploying Snyk in your SDLC, Snyk can also help you automate the prevention of using malicious packages – for example by stopping a build or CI process from passing, sending you a notification, opening a Jira ticket – whatever suits your workflow.
You can quickly test for such packages using the below instructions for the Snyk CLI, or import your git repository to Snyk:
npm install -g snyk snyk test
Secure your open-source software supply-chain
Test your dependencies for known vulnerabilities with Snyk.
Snyk also detects packages that are inside containers – whether inherited in base images or installed by users via popular Linux package managers. If one of these packages or its dependencies were to be compromised, Snyk Container would detect the components using our standard detection mechanisms.
Snyk also has the ability to detect other binaries that get installed outside of the various Linux package managers. If there were a particularly onerous package that found its way into popular container base images, for example, but was not installed via package managers, we could potentially use this detection capability to find these packages. However, this is not a substitute for malware detection.
Testing your containers is nearly as simple as running the Open Source tests above, once you have the Snyk CLI installed:
snyk container test <image name:tag>
Or, if you prefer you can integrate with container registries, CI, or your Kubernetes clusters to scan images at any point along the supply chain. Our newest capabilities even allow you to import a Dockerfile at the same you import code projects from your git repositories and if there are vulnerabilities in the base image you specified in the Dockerfile, Snyk may recommend alternatives and soon will be able to automate the Dockerfile changes via the same Fix PR mechanisms used in Snyk Open Source.
What’s next for software supply chain security?
To successfully mitigate the risk of software supply chain attacks, the first step to take as an organization is to internalize the risk. Understand the changing nature of software development and the new attack vectors that this introduces. Educate both yourself and other developers on the team to ensure the risk is properly understood and that you are taking the correct precautions.
At Synk, we are constantly researching and uncovering malicious packages across ecosystems, and are 100% sure that this security concern is not only not going away but will also become more of a concern as we progress into 2021. Copycat attacks have already imitated Birsan’s dependency confusion attack and it would be a safe bet to assume this trend will continue in the next coming months.
More software will always result in more software risk. We just need to be aware of this and be more cautious.
The above are a compiled list from prior in-depth security cheatsheets we published, such as 10 npm Security Best Practices, 10 GitHub Security Best Practices, and up to date recommendations stemming from the recent Dependency Confusion article’s counter measures.