RubyGems extension builds and plugins run code on install by default; four data-exfiltrating gems found still live
Aikido Security found that RubyGems can execute a gem's code without a dedicated install script, through two little-reviewed mechanisms: native extension build scripts (e.g. extconf.rb, mkrf_conf.rb, Rakefile, CMake, Cargo) that run during gem install, and RubyGems plugins (rubygems_plugin.rb) that load at the end of install and again on every later gem command, including read-only ones like gem list or gem -v. Stable RubyGems/Bundler 4.0.x has no way to disable either behavior; only the 4.1 prereleases (tested on 4.1.0.beta3) add opt-out flags, and they are off by default. While testing detection rules, Aikido also found four gems published on RubyGems between 2013 and 2015 — xmastree, ancient-city-ruby, hacky, and et_phone_home — that exfiltrate the installer's username, take a silent macOS screenshot, or send a simple network beacon to a remote server; all four were still installable as of November 4, 2026. Aikido reported the design issue and the four gems to the RubyGems security team in October 2026.
Detalhes técnicos
A gem can declare extensions in its gemspec; if an extconf.rb or mkrf_conf.rb build script is listed, RubyGems executes that Ruby file during installation and then runs the resulting Makefile or rake, meaning arbitrary attacker code runs the same way node-gyp runs native builds for npm. Separately, a file named rubygems_plugin.rb at the root of a gem's require path is installed as a RubyGems plugin: it runs once at the end of gem install, and RubyGems then loads every installed plugin on every subsequent gem command — including gem list, gem search, and commands about unrelated gems — for as long as the gem stays installed, and plugin load failures are only reported as warnings. Aikido reviewed the top ~1,000 gems by downloads on bestgems.org (October 26, 2026) and found 74 of 997 (about 1 in 13), including widely used gems like bcrypt, bigdecimal, bootsnap, bson, and debug, declare native extension builds, and 2 of 997 (rdoc, yard) ship a rubygems_plugin.rb, showing how normal these install-time mechanisms look to a reviewer even though attackers could abuse them at any time. The post draws a parallel to the Miasma npm campaign, where attackers hid an execution trigger in binding.gyp rather than package.json, prompting npm 12 to make all install scripts, including native builds, opt-in, and notes that Ruby developers have already been targeted in the separate SleeperGem campaign via malicious gem versions published from compromised dormant maintainer accounts.
Remediação
Defenders should search lockfiles for the four named gems, uninstall any found with gem uninstall GEM_NAME --all --executables, remove them from the Gemfile, and review what data may have been exfiltrated. Teams should inventory installed RubyGems plugins and remove unneeded ones, and where possible upgrade to RubyGems/Bundler 4.1.0.beta3 to pass --no-build-extension --no-install-plugin to gem install or set bundle config set --global no_build_extension true / no_install_plugin true (and the equivalent BUNDLE_NO_BUILD_EXTENSION / BUNDLE_NO_INSTALL_PLUGIN environment variables in CI), noting these settings only block code execution at install time, not when the app or tests later load the gem, and that gems with skipped extensions will fail to load until gem pristine <gem> --extensions is run after review. Aikido customers can check their feed for flagged malware issues and use Aikido Device Protection to block known malicious gems at gem install/bundle install time.
Linha do tempo
-
RubyGems extension builds and plugins run code on install by default; four data-exfiltrating gems found still live
ler a análise desta fonte ocultar
Aikido Security found that RubyGems can execute a gem's code without a dedicated install script, through two little-reviewed mechanisms: native extension build scripts (e.g.
extconf.rb,mkrf_conf.rb, Rakefile, CMake, Cargo) that run duringgem install, and RubyGems plugins (rubygems_plugin.rb) that load at the end of install and again on every latergemcommand, including read-only ones likegem listorgem -v. Stable RubyGems/Bundler 4.0.x has no way to disable either behavior; only the 4.1 prereleases (tested on 4.1.0.beta3) add opt-out flags, and they are off by default. While testing detection rules, Aikido also found four gems published on RubyGems between 2013 and 2015 — xmastree, ancient-city-ruby, hacky, and et_phone_home — that exfiltrate the installer's username, take a silent macOS screenshot, or send a simple network beacon to a remote server; all four were still installable as of November 4, 2026. Aikido reported the design issue and the four gems to the RubyGems security team in October 2026.Technical Details
A gem can declare extensions in its gemspec; if an
extconf.rbormkrf_conf.rbbuild script is listed, RubyGems executes that Ruby file during installation and then runs the resulting Makefile orrake, meaning arbitrary attacker code runs the same waynode-gypruns native builds for npm. Separately, a file namedrubygems_plugin.rbat the root of a gem's require path is installed as a RubyGems plugin: it runs once at the end ofgem install, and RubyGems then loads every installed plugin on every subsequentgemcommand — includinggem list,gem search, and commands about unrelated gems — for as long as the gem stays installed, and plugin load failures are only reported as warnings. Aikido reviewed the top ~1,000 gems by downloads on bestgems.org (October 26, 2026) and found 74 of 997 (about 1 in 13), including widely used gems like bcrypt, bigdecimal, bootsnap, bson, and debug, declare native extension builds, and 2 of 997 (rdoc, yard) ship arubygems_plugin.rb, showing how normal these install-time mechanisms look to a reviewer even though attackers could abuse them at any time. The post draws a parallel to the Miasma npm campaign, where attackers hid an execution trigger inbinding.gyprather thanpackage.json, prompting npm 12 to make all install scripts, including native builds, opt-in, and notes that Ruby developers have already been targeted in the separate SleeperGem campaign via malicious gem versions published from compromised dormant maintainer accounts.Remediation
Defenders should search lockfiles for the four named gems, uninstall any found with
gem uninstall GEM_NAME --all --executables, remove them from the Gemfile, and review what data may have been exfiltrated. Teams should inventory installed RubyGems plugins and remove unneeded ones, and where possible upgrade to RubyGems/Bundler 4.1.0.beta3 to pass--no-build-extension --no-install-plugintogem installor setbundle config set --global no_build_extension true/no_install_plugin true(and the equivalentBUNDLE_NO_BUILD_EXTENSION/BUNDLE_NO_INSTALL_PLUGINenvironment variables in CI), noting these settings only block code execution at install time, not when the app or tests later load the gem, and that gems with skipped extensions will fail to load untilgem pristine <gem> --extensionsis run after review. Aikido customers can check their feed for flagged malware issues and use Aikido Device Protection to block known malicious gems atgem install/bundle installtime.