From 628571fc799b05712204d681549a6b42e009a01a Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Thu, 26 Mar 2026 14:58:06 -0400 Subject: [PATCH 1/4] Don't set public Cache-Control on proxied non-public blobs Rails' ActiveStorage proxy controllers hardcode `http_cache_forever public: true`, which sets `Cache-Control: public, immutable`. For non-public blobs behind auth, this allows CDN caching that serves responses without authorization checks. Override `http_cache_forever` in the Authorize concern to downgrade `public` to `false` for non-public blobs. See https://github.com/basecamp/fizzy/pull/2251 for context --- lib/rails_ext/active_storage_authorization.rb | 4 ++++ test/integration/active_storage_authorization_test.rb | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/rails_ext/active_storage_authorization.rb b/lib/rails_ext/active_storage_authorization.rb index 55d0de3bc..7d6fa8510 100644 --- a/lib/rails_ext/active_storage_authorization.rb +++ b/lib/rails_ext/active_storage_authorization.rb @@ -40,6 +40,10 @@ Rails.application.config.to_prepare do head :forbidden end end + + def http_cache_forever(public: false, &block) + super(public: public && publicly_accessible_blob?, &block) + end end ActiveStorage::Blobs::RedirectController.include ActiveStorage::Authorize diff --git a/test/integration/active_storage_authorization_test.rb b/test/integration/active_storage_authorization_test.rb index 1ebb35feb..3394a9990 100644 --- a/test/integration/active_storage_authorization_test.rb +++ b/test/integration/active_storage_authorization_test.rb @@ -150,6 +150,14 @@ class ActiveStorageAuthorizationTest < ActionDispatch::IntegrationTest assert_match %r{rails/active_storage}, response.location end + test "proxy for non-public blob does not set public Cache-Control" do + sign_in_as :david + + get rails_storage_proxy_path(@blob) + assert_response :success + assert_not_includes response.headers["Cache-Control"], "public" + end + # Account exports test "export owner can download their export" do From 14e6832507fb2981ceb83b49d6c9add70b4f445e Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Thu, 26 Mar 2026 15:22:21 -0400 Subject: [PATCH 2/4] Add regression test for public blob Cache-Control --- test/integration/active_storage_authorization_test.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/integration/active_storage_authorization_test.rb b/test/integration/active_storage_authorization_test.rb index 3394a9990..8964a437f 100644 --- a/test/integration/active_storage_authorization_test.rb +++ b/test/integration/active_storage_authorization_test.rb @@ -158,6 +158,14 @@ class ActiveStorageAuthorizationTest < ActionDispatch::IntegrationTest assert_not_includes response.headers["Cache-Control"], "public" end + test "proxy for publicly accessible blob sets public Cache-Control" do + blob = attach_avatar_to(users(:david)) + + get rails_storage_proxy_path(blob) + assert_response :success + assert_includes response.headers["Cache-Control"], "public" + end + # Account exports test "export owner can download their export" do From e12f3e3917926a47c0803bc7efcfca7e0e7b92e6 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Thu, 26 Mar 2026 15:34:54 -0400 Subject: [PATCH 3/4] Add representation proxy Cache-Control test --- test/integration/active_storage_authorization_test.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/integration/active_storage_authorization_test.rb b/test/integration/active_storage_authorization_test.rb index 8964a437f..98b7abde4 100644 --- a/test/integration/active_storage_authorization_test.rb +++ b/test/integration/active_storage_authorization_test.rb @@ -166,6 +166,14 @@ class ActiveStorageAuthorizationTest < ActionDispatch::IntegrationTest assert_includes response.headers["Cache-Control"], "public" end + test "representation proxy for non-public blob does not set public Cache-Control" do + sign_in_as :david + + get rails_storage_proxy_path(@blob.representation(resize_to_limit: [ 100, 100 ])) + assert_response :success + assert_not_includes response.headers["Cache-Control"], "public" + end + # Account exports test "export owner can download their export" do From 7446eed4e1e81656bcb3fcd89b1aa31fe011ea2c Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Thu, 26 Mar 2026 15:38:27 -0400 Subject: [PATCH 4/4] Add representation proxy public Cache-Control test --- test/integration/active_storage_authorization_test.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/integration/active_storage_authorization_test.rb b/test/integration/active_storage_authorization_test.rb index 98b7abde4..605bc109d 100644 --- a/test/integration/active_storage_authorization_test.rb +++ b/test/integration/active_storage_authorization_test.rb @@ -174,6 +174,14 @@ class ActiveStorageAuthorizationTest < ActionDispatch::IntegrationTest assert_not_includes response.headers["Cache-Control"], "public" end + test "representation proxy for publicly accessible blob sets public Cache-Control" do + blob = attach_avatar_to(users(:david)) + + get rails_storage_proxy_path(blob.representation(resize_to_fill: [ 256, 256 ])) + assert_response :success + assert_includes response.headers["Cache-Control"], "public" + end + # Account exports test "export owner can download their export" do