# Even gem list can run someone else's code

RubyGems runs native extension build scripts and rubygems_plugin.rb on install and every later gem command, letting malicious gems execute code and exfiltrate data.

- Payout: Research
- Severity: medium
- Program: RubyGems
- Write-up by: Aikido Security
- Disclosed: 2026-11-05
- Write-up quality: 6/10
- Original: https://www.aikido.dev/blog/gem-list-runs-someone-elses-code
- Library page: https://bugbountylibrary.com/r/blog%3Aaikido-dev-blog-gem-list-runs-someone-elses-code
- Tags: area:oss domain:oss impact:data-leak impact:integrity kind:research platform:threat-intel sev:medium tech:ruby technique:source-review vuln:rce vuln:secrets-leak

**Target:** RubyGems package manager / gem install and bundle install
**Root cause:** RubyGems executes gem-declared extension build scripts (extconf.rb, mkrf_conf.rb, Rakefile) during install and auto-loads any lib/rubygems_plugin.rb on every gem command, with no opt-out in stable 4.0.x.
**Steps:**
1. Publish a gem with `spec.extensions = ["ext/foo/extconf.rb"]` containing arbitrary Ruby, or a file at `lib/rubygems_plugin.rb`.
2. Victim runs `gem install <gem>` or `bundle install`; RubyGems runs the extconf.rb Ruby script and generated Makefile.
3. Plugin variant: RubyGems writes a loader into its plugins dir and loads it at end of install and on every later gem command, including `gem list`, `gem search`, `gem -v`.
4. Payload exfiltrates data (e.g. `whoami` output POSTed to attacker URL) then deletes itself.
**How found:** Researchers read published gemspecs of top ~1,000 gems to see how common extensions/plugins are, then tested detection rules and found four gems from 2013-2015 that run code on install.
**Exploitation:** Attacker publishes a gem with a malicious extconf.rb/Rakefile extension or rubygems_plugin.rb; install alone executes the payload, exfiltrating username, screenshots, or beacons to remote servers. Four PoC gems (xmastree, ancient-city-ruby, hacky, et_phone_home) demonstrated this.
**Insight:** Install-time execution surfaces aren't limited to explicit 'scripts' sections: in RubyGems, gemspec `extensions` entries and a specially-named `lib/rubygems_plugin.rb` are implicit execution hooks that run on install and even read-only commands like `gem list` — audit those files, not just lifecycle scripts.

## Proof of concept (copied exactly from the original report)

**grep lockfiles for four malicious gems**

```
grep -rE '^ +(xmastree|ancient-city-ruby|hacky|et_phone_home) \(' --include=Gemfile.lock .
```

**List installed gems without loading plugins**

```
ruby -e 'Gem.path.each { |p| puts Dir.glob("#{p}/gems/*") }' | grep -E '/(xmastree|ancient-city-ruby|hacky|et_phone_home)-[0-9]'
```

**List RubyGems plugin directories**

```
ruby -e 'Gem.path.each { |p| puts Gem.plugindir(p) }'
```

