Ruby's package ecosystem, RubyGems, has a feature called "yanking" that allows gem authors to remove specific versions from the public registry. Once yanked, a gem version can no longer be installed by new users. But the security implications of yanking are poorly understood by most Ruby developers, and the mechanism itself creates attack opportunities.
When a gem is yanked, existing installations are not affected. Projects that already have the gem in their Gemfile.lock will continue to use the yanked version from their local cache or bundler's cache. But any fresh install -- a new developer joining the team, a clean CI/CD build, or a deployment to a new server -- will fail because the yanked version is no longer available.
Why Gems Get Yanked
Gems are yanked for various reasons, and the motivation matters for security assessment:
Accidental publication. A developer publishes a version with embedded credentials, debug code, or incorrect configuration. They yank it to prevent further downloads. But anyone who downloaded it during the window has the exposed credentials.
Security vulnerabilities. Some maintainers yank versions with known security issues rather than publishing a patched version. This breaks builds for anyone still using the yanked version.
Name disputes. When a gem name conflicts with a trademark or another project, it may be yanked as part of a dispute resolution.
Malicious removal. An attacker who gains access to a maintainer's account could yank popular gem versions, causing widespread build failures. This is a denial-of-service vector against the Ruby ecosystem.
Protest or abandonment. In the tradition of the left-pad incident in the npm ecosystem, maintainers occasionally yank gems in protest or when abandoning a project.
The Security Risks
Build failures as attack vectors. When a yanked gem causes build failures, developers scramble to fix the problem. Under pressure, they may accept alternative packages without proper vetting, switch to forks with unknown provenance, or remove version pins to accept whatever version is available.
Name reuse after yanking. While RubyGems.org prevents reuse of yanked version numbers, new versions can still be published under the same gem name. If a maintainer account is compromised after a gem is yanked, the attacker can publish a new version that appears to be a fix for the yanked version.
Transitive dependency gaps. A yanked gem deep in the dependency tree can be hard to identify. When bundle install fails, the error message may not clearly indicate which transitive dependency was yanked.
Cache poisoning via yanked gems. If a build system caches gems locally, a yanked gem remains in the cache indefinitely. This means different build agents may have different versions of the same gem, creating inconsistent and hard-to-debug behavior.
The Gemfile.lock Problem
Bundler's Gemfile.lock records exact versions and source information for all resolved gems. When a yanked gem is in the lock file, Bundler behaves differently depending on the context:
If the yanked gem is already in the local cache, bundle install succeeds silently. The developer has no indication that they are using a yanked (potentially insecure) version.
If the yanked gem is not in the local cache, bundle install fails with an error. This is the "good" failure mode because it forces the developer to address the issue.
The inconsistency between these two scenarios means that yanked gem issues can lurk in projects for months, only surfacing when a new developer or a fresh CI/CD environment tries to build the project.
Defensive Measures
Pin gems with checksums. Use bundle lock --add-platform and consider using the --checksums feature (available in newer Bundler versions) to record cryptographic hashes for all gems. This prevents substitution even if a gem is yanked and re-published.
Mirror gems internally. Use a gem mirror (Gemstash, Artifactory, or Nexus) that caches all downloaded gems. Even if a gem is yanked from RubyGems.org, your mirror retains a copy. This eliminates build failures from yanked gems.
Monitor for yanked dependencies. Regularly check whether any of your dependencies have been yanked. The bundle exec gem list --remote command can help, but automated tooling is more practical for large projects.
Avoid depending on rarely-used gems. Gems with low download counts and single maintainers are more likely to be yanked or abandoned. When possible, prefer well-maintained gems with active communities.
Respond to yanking events carefully. When a yanked gem breaks your build, resist the urge to quickly switch to an alternative. Investigate why the gem was yanked, check whether the replacement is trustworthy, and verify that the replacement does not introduce new dependencies.
Use conservative version constraints. In your Gemfile, use pessimistic version constraints (~>) rather than open-ended constraints. This limits the range of versions that Bundler will consider, reducing exposure to compromised new versions.
Monitoring and Alerting
Set up alerts for changes in your gem dependency landscape. Key events to monitor include:
- A direct or transitive dependency being yanked
- New versions of dependencies being published by different authors
- Changes in gem metadata (homepage, source code URL, author information)
- Gems with sudden spikes or drops in download counts
How Safeguard.sh Helps
Safeguard.sh monitors your Ruby dependency chain for yanked gems, ownership changes, and suspicious version patterns. The platform alerts you when dependencies are yanked before build failures occur, tracks gem provenance across versions, and generates SBOMs that flag gems with known security issues or irregular publishing patterns. This proactive monitoring ensures your Ruby supply chain remains stable and secure.