Information disclosure (ENV leakage in test suite)
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