← Voltar ao feed
medium

RubyGems extension builds and plugins run code on install by default; four data-exfiltrating gems found still live

1 fonte(s) · 1 atualização(ões) · publicado 05/11/2026 17:30 · coletado há 1 hora

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

  1. aikido.dev ↗ · pub. 05/11/2026 17:30 · coletado 05/11 20:01 primeiro registro

    RubyGems extension builds and plugins run code on install by default; four data-exfiltrating gems found still live

    ler a análise desta fonte

    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.

    Technical Details

    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.

    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-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.