Information disclosure (ENV leakage in test suite)

HIGH
rails/rails
Commit: 8f88c5ea23f3
Affected: 8.1.x prior to this commit (e.g., 8.1.0 - 8.1.2); fixed in this commit for 8.1.3 and later
2026-04-05 12:54 UTC

Description

The commit fixes an information disclosure risk where the test suite could leak the sensitive DATABASE_URL environment variable by manipulating ENV directly in tests without proper scoping. The changes switch from ad-hoc ENV mutations to scoped blocks (with_env) to ensure DATABASE_URL is not leaked to the process environment or inherited by child processes during test execution. This reduces the chance that sensitive database configuration could be exposed via environment leakage in test logs, subprocesses, or interconnected test steps.

Proof of Concept

PoC to reproduce leakage (before fix): # pwned_env_leak_before.rb ENV['DATABASE_URL'] = 'sqlite3:db/leaky.sqlite3' puts "PARENT DATABASE_URL=#{ENV['DATABASE_URL']}" # A child process inherits the parent ENV, which can expose the value system('ruby -e "puts \"CHILD DATABASE_URL=\#{ENV[\'DATABASE_URL\']}\""') # PoC to reproduce with fix (uses with_env to isolate env usage): # pwned_env_leak_after.rb def with_env(vars) saved = {} vars.each do |k, v| saved[k] = ENV[k] ENV[k] = v end yield ensure vars.each do |k, _| ENV[k] = saved[k] end end with_env({ 'DATABASE_URL' => nil }) do # No leakage here; child processes will not see the DATABASE_URL value system('ruby -e "puts \"CHILD DATABASE_URL=\#{ENV[\'DATABASE_URL\']}\""') end # Expected result: # - Before fix: the child prints CHILD DATABASE_URL=sqlite3:db/leaky.sqlite3 # - After fix: the child prints CHILD DATABASE_URL= (empty)

Commit Details

Author: zzak

Date: 2025-12-29 07:27 UTC

Message:

Don't leak DATABASE_URL to env in railties/frameworks_test ``` Failure: ApplicationTests::FrameworksTest#test_active_record_establish_connection_uses_DATABASE_URL_even_if_Rails.env_is_set [/home/zzak/code/rails/tools/support/leak_checker.rb:22]: Environment leak detected! DATABASE_URL bin/test test/application/initializers/frameworks_test.rb:360 ```

Triage Assessment

Vulnerability Type: Information disclosure

Confidence: HIGH

Reasoning:

Commit explicitly aims to prevent leaking the DATABASE_URL environment variable during tests, replacing manual ENV manipulations with scoped with_env blocks to avoid information exposure. This fixes an information disclosure risk (sensitive config exposed via environment in test suite).

Verification Assessment

Vulnerability Type: Information disclosure (ENV leakage in test suite)

Confidence: HIGH

Affected Versions: 8.1.x prior to this commit (e.g., 8.1.0 - 8.1.2); fixed in this commit for 8.1.3 and later

Code Diff

diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index b0e9b0d50f57b..46d71ca8e9385 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -344,32 +344,28 @@ def show test "active record establish_connection uses Rails.env if DATABASE_URL is not set" do app("development") - orig_database_url = ENV.delete("DATABASE_URL") - orig_rails_env, Rails.env = Rails.env, "development" - ActiveRecord::Base.establish_connection - assert ActiveRecord::Base.lease_connection - assert_match(/#{ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: "primary").database}/, ActiveRecord::Base.connection_db_config.database) - db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: "primary") - assert_match(/#{db_config.database}/, ActiveRecord::Base.connection_db_config.database) + with_env DATABASE_URL: nil, RAILS_ENV: "development" do + ActiveRecord::Base.establish_connection + assert ActiveRecord::Base.lease_connection + assert_match(/#{ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: "primary").database}/, ActiveRecord::Base.connection_db_config.database) + db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: "primary") + assert_match(/#{db_config.database}/, ActiveRecord::Base.connection_db_config.database) + end ensure ActiveRecord::Base.remove_connection - ENV["DATABASE_URL"] = orig_database_url if orig_database_url - Rails.env = orig_rails_env if orig_rails_env end test "active record establish_connection uses DATABASE_URL even if Rails.env is set" do app("development") - orig_database_url = ENV.delete("DATABASE_URL") - orig_rails_env, Rails.env = Rails.env, "development" - database_url_db_name = "db/database_url_db.sqlite3" - ENV["DATABASE_URL"] = "sqlite3:#{database_url_db_name}" - ActiveRecord::Base.establish_connection - assert ActiveRecord::Base.lease_connection - assert_match(/#{database_url_db_name}/, ActiveRecord::Base.connection_db_config.database) + with_env DATABASE_URL: nil, RAILS_ENV: "development" do + database_url_db_name = "db/database_url_db.sqlite3" + ENV["DATABASE_URL"] = "sqlite3:#{database_url_db_name}" + ActiveRecord::Base.establish_connection + assert ActiveRecord::Base.lease_connection + assert_match(/#{database_url_db_name}/, ActiveRecord::Base.connection_db_config.database) + end ensure ActiveRecord::Base.remove_connection - ENV["DATABASE_URL"] = orig_database_url if orig_database_url - Rails.env = orig_rails_env if orig_rails_env end test "connections checked out during initialization are returned to the pool" do
← Back to Alerts View on GitHub →