diff --git a/actionpack/lib/action_dispatch/http/content_security_policy.rb b/actionpack/lib/action_dispatch/http/content_security_policy.rb index f544e18e94..9d6aa9bd25 100644 --- a/actionpack/lib/action_dispatch/http/content_security_policy.rb +++ b/actionpack/lib/action_dispatch/http/content_security_policy.rb @@ -33,7 +33,11 @@ def initialize(app) def call(env) request = ActionDispatch::Request.new env - _, headers, _ = response = @app.call(env) + status, headers, _ = response = @app.call(env) + + # Returning CSP headers with a 304 Not Modified is harmful, since nonces in the new + # CSP headers might not match nonces in the cached HTML. + return response if status == 304 return response if policy_present?(headers) diff --git a/actionpack/test/dispatch/content_security_policy_test.rb b/actionpack/test/dispatch/content_security_policy_test.rb index 34e75db2ae..5c32f902f3 100644 --- a/actionpack/test/dispatch/content_security_policy_test.rb +++ b/actionpack/test/dispatch/content_security_policy_test.rb @@ -440,6 +440,10 @@ def api render json: {} end + def not_modified + head :not_modified + end + private def condition? params[:condition] == "true" @@ -457,6 +461,7 @@ def condition? get "/style-src", to: "policy#style_src" get "/no-policy", to: "policy#no_policy" get "/api", to: "policy#api" + get "/not-modified", to: "policy#not_modified" end end @@ -533,6 +538,13 @@ def test_generates_api_security_policy assert_policy "default-src 'none'; frame-ancestors 'none'" end + def test_generates_no_content_security_policy_for_not_modified + get "/not-modified" + + assert_nil response.headers["Content-Security-Policy"] + assert_nil response.headers["Content-Security-Policy-Report-Only"] + end + private def assert_policy(expected, report_only: false) assert_response :success