Information Disclosure / Middleware Misconfiguration
Description
The commit changes the default middleware stack to only insert Rack::Sendfile when x_sendfile_header is configured. Previously Rack::Sendfile could be added to the stack with a nil header, which risks misconfiguration and potential information disclosure or exposure of internal file handling details. The fix ensures Rack::Sendfile is not in the stack unless a valid x_sendfile_header is set, reducing the chance of unintended file serving or exposure of internal paths.
Commit Details
Author: Jean Boussier
Date: 2026-03-02 11:14 UTC
Message:
Merge pull request #56915 from byroot/skip-sendfile
Don't add Rack::Sendfile to the stack if `x_sendfile_header` is `nil`
Triage Assessment
Vulnerability Type: Information Disclosure / Misconfiguration
Confidence: MEDIUM
Reasoning:
The commit changes middleware stack behavior to only include Rack::Sendfile when x_sendfile_header is configured. This prevents potential exposure of internal file paths or unintended file serving when the header is not set, addressing a possible information disclosure risk and misconfiguration related to sendfile handling.
Verification Assessment
Vulnerability Type: Information Disclosure / Middleware Misconfiguration
Confidence: MEDIUM
Affected Versions: Rails 8.1.x before 8.1.3 (e.g., 8.1.0 through 8.1.2)
Code Diff
diff --git a/railties/lib/rails/application/default_middleware_stack.rb b/railties/lib/rails/application/default_middleware_stack.rb
index a1e2d00bba300..adaccf35a6014 100644
--- a/railties/lib/rails/application/default_middleware_stack.rb
+++ b/railties/lib/rails/application/default_middleware_stack.rb
@@ -26,7 +26,9 @@ def build_stack
ssl_default_redirect_status: config.action_dispatch.ssl_default_redirect_status
end
- middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header
+ if config.action_dispatch.x_sendfile_header
+ middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header
+ end
if config.public_file_server.enabled
headers = config.public_file_server.headers || {}
diff --git a/railties/test/commands/middleware_test.rb b/railties/test/commands/middleware_test.rb
index c7a3fc613e163..7243313130b56 100644
--- a/railties/test/commands/middleware_test.rb
+++ b/railties/test/commands/middleware_test.rb
@@ -27,7 +27,6 @@ def app
assert_equal [
"ActionDispatch::HostAuthorization",
- "Rack::Sendfile",
"ActionDispatch::Static",
"Propshaft::Server",
"ActionDispatch::Executor",
@@ -63,7 +62,6 @@ def app
assert_equal [
"ActionDispatch::HostAuthorization",
- "Rack::Sendfile",
"ActionDispatch::Static",
"Propshaft::Server",
"ActionDispatch::Executor",
@@ -98,7 +96,6 @@ def app
assert_equal [
"ActionDispatch::HostAuthorization",
- "Rack::Sendfile",
"ActionDispatch::Static",
"Propshaft::Server",
"ActionDispatch::Executor",
@@ -137,7 +134,7 @@ def app
%w(ActionDispatch::Reloader ActionDispatch::ShowExceptions ActionDispatch::DebugExceptions),
# Outright dependencies
- %w(ActionDispatch::Static Rack::Sendfile),
+ %w(ActionDispatch::Static),
%w(ActionDispatch::Flash ActionDispatch::Session::CookieStore),
%w(ActionDispatch::Session::CookieStore ActionDispatch::Cookies),
]
@@ -303,9 +300,9 @@ def app
end
test "insert middleware after" do
- add_to_config "config.middleware.insert_after Rack::Sendfile, Rack::Config"
+ add_to_config "config.middleware.insert_after Rack::Runtime, Rack::Config"
boot!
- assert_equal "Rack::Config", middleware.third
+ assert_equal middleware.index("Rack::Runtime") + 1, middleware.index("Rack::Config")
end
test "unshift middleware" do
@@ -317,20 +314,20 @@ def app
test "Rails.cache does not respond to middleware" do
add_to_config "config.cache_store = :file_store, '/tmp/cache'"
boot!
- assert_equal "Rack::Runtime", middleware[5]
+ assert_equal "Rack::Runtime", middleware[4]
assert_instance_of ActiveSupport::Cache::FileStore, Rails.cache
end
test "Rails.cache does respond to middleware" do
boot!
- assert_equal "ActiveSupport::Cache::Strategy::LocalCache", middleware[5]
- assert_equal "Rack::Runtime", middleware[6]
+ assert_equal "ActiveSupport::Cache::Strategy::LocalCache", middleware[4]
+ assert_equal "Rack::Runtime", middleware[5]
end
test "insert middleware before" do
- add_to_config "config.middleware.insert_before Rack::Sendfile, Rack::Config"
+ add_to_config "config.middleware.insert_before Rack::Runtime, Rack::Config"
boot!
- assert_equal "Rack::Config", middleware.second
+ assert_operator middleware.index("Rack::Runtime"), :>, middleware.index("Rack::Config")
end
test "can't change middleware after it's built" do