Dev.to Security 🔐 Cybersecurity 👁 0 📖 3 min read

CVE-2026-126077: CVE-2026-126077: Session Information Leak in Ruby on Rails Action Pack and Active Storage Proxy Mode

CVE-2026-126077: Session Information Leak in Ruby on Rails Action Pack and Active Storage Proxy Mode Vulnerability ID: CVE-2026-126077 CVSS Score: 6.8 Published: 2026-11-12 An information exposure vulnerability in R

CVE-2026-126077: Session Information Leak in Ruby on Rails Action Pack and Active Storage Proxy Mode

Vulnerability ID: CVE-2026-126077
CVSS Score: 6.8
Published: 2026-11-12

An information exposure vulnerability in Ruby on Rails Action Pack allows sensitive session cookies to be attached to public, cacheable responses served by Active Storage proxy controllers. When cookie secret rotation or a hybrid cookie serializer migration is enabled, reading a legacy-format cookie triggers an automatic cookie rewrite that ignores the session-skipping directive. If an intermediate shared cache or CDN caches the resulting response along with its Set-Cookie header, subsequent users requesting the same URL receive the leaked session token.

TL;DR

Action Pack ignores request.session_options[:skip] when automatically upgrading rotated or hybrid-serialized cookies, causing Active Storage proxy endpoints to emit Set-Cookie headers on public cacheable responses. Shared caches storing these headers can distribute user session identifiers to unauthorized third parties.

⚠️ Exploit Status: POC

Technical Details

  • Vulnerability ID: CVE-2026-126077 / GHSA-x6mj-8jx9-qhqv
  • Weakness Class: CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
  • CVSS v3.1 Score: 6.8 Medium (CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N)
  • EPSS Score: 0.415% (36.26th Percentile)
  • Affected Component: ActionDispatch::Cookies & ActiveStorage::Blobs::ProxyController
  • Security Impact: Session Hijacking & Session Fixation via Shared Web Cache
  • Patched Versions: Rails 8.1.4.1 and 8.0.5.2
  • CISA KEV Status: Not Listed

Affected Systems

  • Ruby on Rails (rails)
  • Action Pack (actionpack)
  • Active Storage (activestorage)
  • actionpack / rails: >= 8.1.0, < 8.1.4.1 (Fixed in: 8.1.4.1)
  • actionpack / rails: < 8.0.5.2 (Fixed in: 8.0.5.2)

Code Analysis

Commit: 849a6c3

Don't write upgraded cookies to a response that skips the session (8.1.x branch)

diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 351daf9224167..8550be48944fc 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -324,6 +324,7 @@ def self.build(req, cookies)
       def initialize(request)
         @set_cookies = {}
         @delete_cookies = {}
+        @upgraded_cookies = Set.new
         @request = request
         @cookies = {}
         @committed = false
@@ -386,6 +387,7 @@ def []=(name, options)
         end

         handle_options(options)
+        @upgraded_cookies.delete(name.to_s)

         if @cookies[name.to_s] != value || options[:expires]
           @cookies[name.to_s] = value
@@ -426,8 +428,14 @@ def clear(options = {})
         @cookies.each_key { |k| delete(k, options) }
       end

+      def upgraded(name)
+        @upgraded_cookies << name.to_s
+      end
+
       def write(response)
         @set_cookies.each do |name, value|
+          next if @upgraded_cookies.include?(name) && request.session_options[:skip]
+
           if write_cookie?(value)
             response.set_cookie(name, value)
           end
@@ -533,6 +541,10 @@ def []=(name, options)
         @parent_jar[name] = options
       end

+      def upgraded(name)
+        @parent_jar.upgraded(name)
+      end
+
       protected
         def request; @parent_jar.request; end

@@ -599,7 +611,10 @@ def parse(name, dumped, force_reserialize: false, **)
               return
             end

-            self[name] = { value: value } if force_reserialize || reserialize?(dumped)
+            if force_reserialize || reserialize?(dumped)
+              self[name] = { value: value }
+              upgraded(name)
+            end

             value
           end

Commit: 0e6cf8f

Don't write upgraded cookies to a response that skips the session (8.0.x branch)

Mitigation Strategies

  • Upgrade Ruby on Rails and Action Pack to patched versions 8.1.4.1 or 8.0.5.2.
  • Configure intermediate CDNs and reverse proxies to strip Set-Cookie headers on public Active Storage proxy paths or bypass caching when Set-Cookie is present.
  • Purge existing CDN cache entries for Active Storage proxy endpoints after deploying the patch to evict any previously cached session headers.
  • Switch Active Storage delivery from proxy mode (:rails_storage_proxy) to redirect mode (:rails_storage_redirect) if immediate patching is not possible.
  • Remove completed cookie secret rotations (config.action_dispatch.cookies_rotations) and transition away from the :hybrid cookie serializer once migration periods conclude.

Remediation Steps:

  1. Update your application's Gemfile to specify gem 'rails', '~> 8.1.4.1' or '~> 8.0.5.2'.
  2. Run 'bundle update rails actionpack activestorage' and redeploy the application.
  3. Audit CDN and reverse proxy configurations (Cloudflare, Fastly, CloudFront, Nginx) serving '/rails/active_storage/blobs/proxy/' and '/rails/active_storage/representations/proxy/' to verify Set-Cookie headers are stripped or not cached.
  4. Execute a cache purge across all edge caching nodes for Active Storage proxy URLs.

References

Read the full report for CVE-2026-126077 on our website for more details including interactive diagrams and full exploit analysis.

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.