The go-to resource for upgrading Ruby, Rails, and your dependencies.

Identifying Typosquatting and Brandjacking Risks in Outdated Ruby Gems


In the mid-19th century, before modern food safety regulations, food adulteration was a rampant problem in industrializing cities. Bread was routinely bulked up with alum and chalk, while milk was diluted with water. The primary danger didn’t come from the meals people prepared themselves, but rather from the complex, opaque supply chains they relied upon for their raw ingredients. You could trust your own cooking, but you couldn’t always trust the flour. A solution came in the form of food inspection laws and chemical auditing — independent verification that the ingredients were exactly what they claimed to be.

When we maintain a Ruby application over several years, we face a remarkably similar problem. The Gemfile inevitably grows. Each new feature often brings new dependencies, and those dependencies bring their own transitive requirements. Over time, this creates a complex web of external code. While we typically focus our security efforts heavily on our own application code vulnerabilities, the software supply chain — the third-party libraries we pull in — represents a significant and often overlooked attack vector. As historical bakers needed chemical audits for their flour, modern developers need systematic verification for their dependencies.

Two specific supply chain attacks target this complexity: typosquatting and brandjacking. These attacks rely on human error and the natural lifecycle of open-source projects. For teams managing legacy applications, particularly those delaying a Ruby and Rails upgrade, these vulnerable dependencies can sit unnoticed in production environments for months or years.

In this guide, we will examine how these attacks function practically within the RubyGems ecosystem, how you can identify them, and the steps required to remediate them.

Understanding Typosquatting in RubyGems

Typosquatting targets the manual process of adding a dependency. An attacker publishes a malicious package with a name that is visually similar to a popular, trusted package. They anticipate that a developer will make a typographical error when typing gem install or when adding an entry to a Gemfile.

For example, if you had an application that required the popular rack-cors gem, you might accidentally type:

gem 'rack-cores'

If an attacker has registered rack-cores on RubyGems.org, running bundle install will pull their malicious code into your application.

One may wonder: if a developer installs a malicious gem by mistake, won’t they notice when their application suddenly stops working? The answer is straightforward. The malicious gem typically functions exactly like the legitimate one by silently requiring the real gem in the background. This ensures the application continues to run without immediate errors, while the malicious payload executes unseen. That payload might exfiltrate environment variables, steal database credentials, or open a reverse shell.

Strictly speaking, the RubyGems registry does have mechanisms to detect and remove malicious gems, but there is always a window of time between publication and discovery. During this window, any application that installs the squatted gem is compromised.

The Mechanics of Brandjacking and Abandoned Gems

Brandjacking, though, operates on a slightly different premise. Instead of relying on a typographical error, an attacker attempts to claim the namespace of an abandoned project or creates a package that appears to be the official release for a well-known brand that does not actually maintain a Ruby library. By way of a memory aide, you might think of typosquatting as waiting for someone to enter the wrong room, whereas brandjacking is pretending to be the landlord of an abandoned building.

Consider a scenario where a developer creates a useful utility gem, maintains it for a few years, and then abandons it. The repository remains on GitHub, and the gem remains on RubyGems. If the original author’s domain name expires, or if their RubyGems account is compromised, an attacker can publish a new, malicious version of the gem.

This is particularly dangerous for outdated applications. If your Gemfile uses pessimistic version constraints (e.g., ~> 1.2) on an abandoned gem, a standard bundle update might pull in the attacker’s newly published 1.2.9 version.

This, of course, raises the question of exactly how we can detect these threats before they reach production.

Identifying the Risks in Your Application

Detecting typosquatting and brandjacking requires a systematic approach to auditing your dependencies. We cannot manually review every line of code in every gem our applications use.

There are a number of different approaches to auditing dependencies. The first approach relies on automated scanning against databases of known vulnerabilities. The second approach involves formal security auditing and manual review to catch unlisted threats. Generally speaking, the first option is simpler and should be run continuously in your CI/CD pipeline. The second option, though, requires more effort but provides a much deeper level of assurance.

Using Bundler Audit for Known Vulnerabilities

The first step is checking your Gemfile.lock against advisory databases. The bundler-audit gem is a standard tool for this task. It checks your installed gem versions against the Ruby Advisory Database, which is a community-maintained, free resource that catalogs known security vulnerabilities in Ruby gems. If your organization relies heavily on this database to secure its applications, it is a nice gesture to consider contributing back to the community that maintains it, though of course, such support is entirely optional.

You can run it from your command line. In its simplest form, you install the gem and instruct it to check your environment, updating the local vulnerability database simultaneously:

$ gem install bundler-audit
$ bundle audit check --update

The output might look like this:

Updating ruby-advisory-db ...
ruby-advisory-db: 1234 commits
Name: actionpack
Version: 5.2.4.2
Advisory: CVE-2020-8164
Criticality: High
URL: https://groups.google.com/forum/#!topic/rubyonrails-security/bOWdBcgdrP8
Title: Possible Strong Parameters Bypass in ActionPack
Solution: upgrade to ~> 5.2.4.3

Additionally, note that the exact version numbers you see in your particular output will likely vary depending on your specific dependencies and the current state of the advisory database.

Since this command is run often to ensure application security, many developers integrate it directly into their automated tests or create a shell alias for rapid local checks. For example, you might add something like this to your shell configuration:

alias ba="bundle audit check --update"

While bundler-audit is excellent for finding known code vulnerabilities, it is fundamentally reactive. It may not catch a brand-new typosquatting attack that hasn’t yet been discovered and reported.

Conducting a Formal Security Audit

For a more robust defense, especially in older applications, you should conduct a comprehensive security audit. A formal audit goes beyond automated scanning. It involves reviewing the provenance of your dependencies, checking the maintenance status of your gems, and identifying anomalous code execution patterns.

A thorough security audit will typically highlight:

  • Gems that have not received updates in over two years.
  • Dependencies that have changed ownership recently.
  • Packages with names that closely mimic other popular packages but have a low download count.

You can inspect the source of a gem directly to look for suspicious patterns. For instance, if we suspected a package named rack-cores of typosquatting, we could unpack the gem locally without actually executing its installation process:

$ gem unpack rack-cores
Unpacked gem: '/path/to/project/rack-cores-1.0.0'

Note: Pay attention to the use of the gem unpack command here. We could have used gem install to fetch the code, but that runs the risk of executing a malicious extconf.rb script during the native extension compilation phase. Unpacking it safely extracts the files so we can review the contents without execution. Malicious gems often include obfuscated code or unexpected network requests in their initialization files.

Let’s see what was unpacked and verify that we haven’t inadvertently executed anything:

$ ls -a rack-cores-1.0.0
.  ..  lib  rack-cores.gemspec

As we can see, running gem unpack is a read-only process that safely extracts the gem’s code for analysis without executing it. You also may notice that there is no .git directory; this is because the command fetches the pre-packaged .gem file from the registry, rather than cloning the source repository. This is significant because it allows us to analyze the exact code that would be run in production, which might differ from the open-source repository if an attacker published a modified release.

Responding to a Discovered Attack

If your audit uncovers a typosquatted or brandjacked gem that has already been deployed to your production environment, removing it from your Gemfile is an essential first step, but it is not a complete remediation.

A malicious gem runs with the same permissions as your application process. Therefore, although yanking the gem and redeploying your application is certainly a reasonable action, any exposed credentials — such as database passwords, API keys, or cloud provider tokens present in your environment variables — should be immediately rotated. One must assume they are compromised. It is also wise to review access logs for anomalous behavior that occurred during the window of vulnerability.

Remediation and Best Practices

Once we have identified potential attack vectors, we must secure our application. There are three major approaches to mitigating these risks going forward.

The first approach is to consistently lock down your dependencies. Ensure your Gemfile.lock is always checked into version control. This guarantees that your CI/CD pipeline and production servers use the exact same versions of gems that you tested locally. Without a lockfile, any deployment could inadvertently pull a malicious version if one was recently published.

The second approach is to use precise version constraints in your Gemfile. Pin your dependencies to specific versions, or at least minor versions using the pessimistic version operator, to prevent unexpected updates from pulling in a compromised package.

Tip: The pessimistic version operator (~>) provides an excellent balance between security and maintainability. It allows you to receive backwards-compatible security patches while protecting you from unexpected major or minor version changes that might introduce malicious code or breaking changes.

# Less secure, prone to pulling unexpected major updates
gem 'nokogiri', '>= 1.10'

# More secure, locked to the 1.13.x series
gem 'nokogiri', '~> 1.13.0'

The third option is the most effective long-term strategy: conducting a comprehensive Ruby and Rails upgrade. An upgrade forces an evaluation of every dependency. During this process, developers naturally identify and replace abandoned gems with actively maintained alternatives. This reduces reliance on outdated libraries that are prime targets for brandjacking and ensures the application benefits from the latest security patches provided by the Ruby core team and the Rails framework.

Generally speaking, the first two options are fundamental practices that every team should adopt immediately. The third option, though, provides the most durable protection against a decaying dependency tree.

Maintaining an older codebase requires continuous vigilance. By understanding how typosquatting and brandjacking operate, and by utilizing tools like bundler-audit alongside periodic manual reviews, we can reliably reduce the risk of a supply chain attack compromising our applications.

Sponsored by Durable Programming

Need help maintaining or upgrading your Ruby on Rails application? Durable Programming specializes in keeping Rails apps secure, performant, and up-to-date.

Hire Durable Programming