RubyGems Extensions and Plugins Can Execute Code During Installation

Summary
Aikido reports that RubyGems extensions and plugins can execute code during installation, and plugins can run on later gem commands. It found four gems sending data; opt-out controls are available in RubyGems and Bundler 4.1 prereleases, not stable 4.0.x.
Key points
- RubyGems runs extension build scripts during installation. It also loads installed plugins at the end of installation and on later gem commands, including read-only commands.
- Aikido says it found four gems published between 2013 and 2015—xmastree, ancient-city-ruby, hacky, and et_phone_home—that send an installer username, a macOS screenshot, or a beacon. They were still installable on November 4, 2026.
- In a review of gemspecs for 997 popular gems, Aikido found that 74 declared native extension build steps and two shipped RubyGems plugin files. The article notes this measures prevalence, not risk.
- Stable RubyGems and Bundler 4.0.x have no settings to disable these behaviors. RubyGems and Bundler 4.1.0.beta3 add opt-outs, but they are off by default.
- The recommended checks include searching project lockfiles for the four gems, reviewing installed plugins, and inspecting build and plugin files before installing unfamiliar gems.
- Disabling extension builds or plugin installation limits execution during install-only steps; it does not prevent a gem's code from running when an application or tests load it.
Article Details
- Attack Vectors
- A gem’s Rakefile, run as an extension build step, can execute code during installation.
- A RubyGems plugin can run immediately after installation and on later gem commands, including read-only commands.
- The reported gems sent installer username output, a silent macOS screenshot, or a beacon to remote endpoints.
- Defensive Notes
- Check project lockfiles and installed gem directories for xmastree, ancient-city-ruby, hacky, and et_phone_home; inspect each Ruby version managed by rbenv or another version manager.
- If an affected gem was installed, stop processes it started, uninstall it, remove it from project dependencies, and assess potential data exposure.
- Review and remove unneeded RubyGems plugins.
- RubyGems and Bundler 4.1.0.beta3 add opt-out controls: use --no-build-extension and --no-install-plugin for gem install, or set no_build_extension and no_install_plugin in Bundler. The settings are off by default, and the article says stable 4.0.x has no equivalent controls.
- In CI, set BUNDLE_NO_BUILD_EXTENSION=true and BUNDLE_NO_INSTALL_PLUGIN=true for install-and-audit jobs that do not need to load the application.
- Inspect new or recently updated gems in a clean environment, including their extconf.rb, mkrf_conf.rb, Rakefile, CMake files, and lib/rubygems_plugin.rb.
Indicators of compromise
| Type | Indicator | Context |
|---|---|---|
| URL | hxxp[:]//176[.]31[.]142[.]25/ruby_no_way_you_got_here_randomly | Endpoint et_phone_home contacts with a GET request during installation. |
| URL | hxxp[:]//appfolio[.]herokuapp[.]com/upload | Destination used by hacky to upload a silent macOS screenshot during installation. |
| URL | hxxp[:]//cryptic-ocean-8847[.]herokuapp[.]com/usernames | Destination to which xmastree 0.0.2 POSTs whoami output during installation. |
| URL | hxxp[:]//stark-samurai-8122[.]herokuapp[.]com/logs | Destination to which ancient-city-ruby POSTs whoami output during installation. |
MITRE ATT&CK
T1033 · System Owner/User Discoveryxmastree and ancient-city-ruby run whoami and send its output to a remote endpoint.T1059 · Command and Scripting InterpreterMalicious Ruby code in gem extension build files runs during gem installation.T1113 · Screen Capturehacky takes a silent screenshot on macOS and uploads it during installation.
Malware
ancient-city-rubygrep -rE '^ +(xmastree|ancient-city-ruby|hacky|et_phone_home) \(' --include=Gemfile.lock .To check installed gems without running a gem command (which would load plugins), run:et_phone_homegrep -rE '^ +(xmastree|ancient-city-ruby|hacky|et_phone_home) \(' --include=Gemfile.lock .To check installed gems without running a gem command (which would load plugins), run:hackygrep -rE '^ +(xmastree|ancient-city-ruby|hacky|et_phone_home) \(' --include=Gemfile.lock .To check installed gems without running a gem command (which would load plugins), run:xmastreegrep -rE '^ +(xmastree|ancient-city-ruby|hacky|et_phone_home) \(' --include=Gemfile.lock .To check installed gems without running a gem command (which would load plugins), run:
Vendors
Products
Aikido Device ProtectionTo stop known malicious gems before they reach a developer’s machine, use Aikido Device Protection. It checks gem install and bundle install on Ruby 3 and later against Aikido Intel, and blocks known malware before itBundlerStable RubyGems and Bundler 4.0.x have no way to turn either behavior off. The 4.1 prereleases add opt-out settings, but they’re off by default, so you have to turn them on yourself.npmnpm already addresses this issue. npm 12 made install scripts opt-in, including native builds. RubyGems still runs extension builds and plugins by default.RubyGemsyour machine without an install script. Here’s how to check for four data-exfiltrating gems we found on RubyGems, turn this behavior off with new settings, and see what Aikido flags in your feed.
