As agile software developers, we’re expected to deliver at the speed of the internet. We have to push features and fixes quickly, so we don’t have time to write every piece of our software from scratch.

The good news is that we don’t have to! No matter what programming language we use, we have many open-source libraries and frameworks at our disposal. Open-source tools are a huge productivity win because every line of open-source code we use is a line of code we don’t have to write ourselves. 

It’s not all fun and games, though. We’re not just importing functionality when we pull open-source code into our software projects. We’re also importing risk. The code we write usually goes through multiple rounds of internal code review before reaching production. Our open-source dependencies typically face no such scrutiny. Instead, we’ve depended on trust. 

Unfortunately, it’s now clear that trust isn’t enough. Recent attacks have shown that we shouldn’t blindly trust the libraries and frameworks we use. Even if we could be 100% sure our direct dependencies are trustworthy, most libraries we use have plenty of dependencies, too. 

For example, we might choose to compile our JavaScript with Babel. But when we add Babel to a JavaScript project, we don’t just get Babel. Instead, we get Babel plus 48 other libraries. How can we trust all of them? We certainly don’t have time to check them all for vulnerabilities manually. Every dependency adds risk because each one of them might contain malicious code. After all, most public repositories don’t sign their code, so there’s no guarantee dependencies you import haven’t been compromised.

If that weren’t enough, we should also consider our development tools. We can probably trust Microsoft not to ship anything malicious in Visual Studio Code. But most developers use a dozen or more VS Code plugins, each of which could contain vulnerabilities.

An application’s complete dependency tree — along with any tools we use to develop and deliver the app — collectively form our software supply chain. A software supply chain full of other people’s code leaves us vulnerable to software supply chain attacks. These attacks aim to infiltrate our systems by inserting malicious code into one of our tools or dependencies.

Types of Software Supply Chain Attacks

Now that we understand the nature of software supply chain attacks, let’s explore some common ways they occur.

Typosquatting

Typosquatting happens when an attacker takes a popular framework or library, adds malicious code, and pushes it to a package repository under a name closely resembling the original library.

For instance, in late 2018 a security analyst found a dozen malicious packages in Python’s PyPI repository.  Some of these packages had been up for nearly a year. Four of them impersonated Django with names like Diango, Djanga, Djago, and Dajngo.

In 2020, researchers found more than 700 typosquatting packages in the RubyGems package repository. One of the impersonated packages contained persistent malware that replaced bitcoin wallet addresses with the attacker’s wallet address.

The threat has grown. For example, in March 2021, PyPI had to remove a whopping 3,653 malicious copycat packages from its repository.

Malicious Commits to Open-Source Projects

Open-source software has reduced the barrier-to-entry for new developers, but being open means reliance on the community for maintenance and support. A dedicated community identifies and fixes vulnerabilities quickly. But what if a malicious commit goes unnoticed?

After all, not all reviewers are security experts. Code that appears correct may contain a stealthy vulnerability or trojan the reviewer doesn’t notice. As a result, we can’t rely solely on open-source code reviews to vet the code we use and keep the bad guys in check.

Malicious commits to open-source projects are more complicated than typosquatting. However, their potential impact is far more significant because they can infiltrate dependencies already in widespread use.

Compromised Build and Deployment Tools

We’d like to think we can rely on our build and delivery tools. But that’s not always true. For example, even our compilers can introduce vulnerabilities into our software. Ken Thompson’s classic paper Reflections on Trusting Trust shows us this isn’t a new problem. 

Our deployment tools aren’t immune, either. Common CI/CD tools contain vulnerabilities that could let attacks slip malicious code into our apps before they’re deployed. 

Malicious Developer Tools

Our IDEs can introduce malicious code to our software supply chain, too. For example, Snyk recently uncovered vulnerabilities in widely-used Visual Studio Code extensions. And in 2020, Java developers received an unpleasant surprise when malware began injecting a trojan into projects built with Netbeans. 

Using old-school tools won’t save us either. Both Emacs and Vim contain vulnerabilities that would let attackers infiltrate our software supply chain. 

How to Mitigate Software Supply Chain Attacks

As developers, we need to view the software development process in the same way a chef bakes a cake. If there is an inappropriate ingredient in the batter or your utensils have been contaminated, there’s not much you can do after the cake is in the oven. In the same way, the best defense that we can put up against a supply chain attack is being conscious of the integrity of our development tools and the security of our dependencies when we design and develop our software.

Use Dependency Scanning Tools

In February 2021, a security researcher, Alex Birsan, demonstrated how dependency confusion can enable supply chain attacks by compromising the codebases of several major players, including Microsoft and Apple. 

Dependency scanning tools like Snyk help us avoid using vulnerable or already compromised packages in codebases. After scanning your package’s manifest files, it builds a dependency tree and flags the packages that it considers vulnerable.

Employ Static Application Security Testing Tools to Scan Source Code

Static application security testing (SAST) tools scanning source code for common vulnerabilities. These tests can provide a real-time understanding of the security of the software that we’re developing. Static analysis can spot common causes of vulnerabilities such as SQL injection, buffer overflows, and use-after-free errors.

We can add static analysis to our IDEs and editors to catch problems in real-time. We can also add them to our CI/CD pipeline to ensure nobody sneaks vulnerable code into our repository. Since it relies on analyzing source code, any SAST tool we choose must support the programming language we use.

Dynamic Analytics Tools Are Our Friends

Dynamic application security testing (DAST), or black-box testing, happens while code is running. Dynamic tests probe software from the outside, trying to find and exploit errors and vulnerabilities. 

DAST may consist of automated tools running in our CI/CD pipeline. Testing teams can also run DAST tooling manually to try to root out tricky vulnerabilities in our software. Since DAST tools test externally, they don’t need to know anything about the programming language used to write the application under test. 

Runtime Application Self-Protection

Runtime application self-protection (RASP) blocks suspicious activities in our application, its open-source dependencies, runtime environment, and servers.

RASP is great as a last line of defense because it can catch vulnerabilities that have evaded our other defenses and ended up in production. It can even prevent potential malware like compromised third-party libraries from establishing network connections to external platforms or having access to sensitive data.

Keep Vulnerable Packages in Check with the ActiveState Platform

The ActiveState Platform is an end-to-end open-source supply chain integrity solution for Python, Perl, and Tcl. It provides cutting-edge protection for most open-source-related vulnerabilities. It does this in several ways:

  • It tells us where our software’s dependencies originate, helping keep us safe from typosquatting and abandoned packages. 
  • It actively scans every dependency we try to use and lets us know if any of them contain vulnerabilities.
  • It builds our language runtimes and any native dependencies from source, so we can be certain they only contain what we want them to contain. For example, if you download a pre-built Python binary — even if it’s from a source like python.org — how can you be certain no malicious code was slipped into the build?
  • It provides checksum verification of all build artifacts, ensuring the final packages you work with haven’t been compromised.

ActiveState creates a safe space for developers outside the reach of malicious actors in the open-source world.

Next Steps

Open-source libraries and frameworks help us reduce our time-to-market, but they leave us open to vulnerabilities that the attackers see all too clearly. Securing our software supply chain isn’t easy. But as we’ve seen, it’s not impossible.

There are dozens of point solutions that can help you identify known open source vulnerabilities and risky proprietary code. But assembling them all into a comprehensive solution can be both time-consuming and resource-intensive. 

In contrast, the ActiveState Platform is an out-of-the-box solution that addresses both the integrity and security of the open source components you use. It can find and fix vulnerabilities in your open source dependencies, leaving you with a more secure software supply chain. If you use Python, Perl or Tcl in your organization, you might want to find out more about how the ActiveState Platform keeps your software secure from supply chain attackers.

Open source security supply chainAnd If you’re not sure where to start, why not give the ActiveState Platform a try? In just a few minutes, you can sign up for a free account and build your own custom language runtime — complete with all the dependencies your application needs!

Recommended Reads

Data Sheet: Shifting Security Left with the ActiveState Platform

3 ways the ActiveState Platform can secure your open source supply chain