Version in base suite: 2.1.1-0.1 Base version: ruby-rack-session_2.1.1-0.1 Target version: ruby-rack-session_2.1.1-0.1+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/r/ruby-rack-session/ruby-rack-session_2.1.1-0.1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/r/ruby-rack-session/ruby-rack-session_2.1.1-0.1+deb13u1.dsc changelog | 8 + patches/CVE-2026-39324-reject-unencrypted-fallback.patch | 61 +++++++++++++++ patches/series | 1 3 files changed, 70 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpf3nlmxeu/ruby-rack-session_2.1.1-0.1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpf3nlmxeu/ruby-rack-session_2.1.1-0.1+deb13u1.dsc: no acceptable signature found diff -Nru ruby-rack-session-2.1.1/debian/changelog ruby-rack-session-2.1.1/debian/changelog --- ruby-rack-session-2.1.1/debian/changelog 2025-07-15 11:10:44.000000000 +0000 +++ ruby-rack-session-2.1.1/debian/changelog 2026-09-29 00:49:51.000000000 +0000 @@ -1,3 +1,11 @@ +ruby-rack-session (2.1.1-0.1+deb13u1) trixie-security; urgency=high + + * Team upload. + * CVE-2026-39324: reject a session cookie when decryption fails + instead of accepting it with the unencrypted coder. + + -- Simon Quigley Mon, 28 Sep 2026 19:49:51 -0500 + ruby-rack-session (2.1.1-0.1) unstable; urgency=medium * Non-maintainer upload. diff -Nru ruby-rack-session-2.1.1/debian/patches/CVE-2026-39324-reject-unencrypted-fallback.patch ruby-rack-session-2.1.1/debian/patches/CVE-2026-39324-reject-unencrypted-fallback.patch --- ruby-rack-session-2.1.1/debian/patches/CVE-2026-39324-reject-unencrypted-fallback.patch 1970-01-01 00:00:00.000000000 +0000 +++ ruby-rack-session-2.1.1/debian/patches/CVE-2026-39324-reject-unencrypted-fallback.patch 2026-09-29 00:49:51.000000000 +0000 @@ -0,0 +1,61 @@ +Description: reject session cookies when decryption fails (CVE-2026-39324) + Rack::Session::Cookie configured with secrets: tried each encryptor and, + on failure, decoded the cookie with the unencrypted coder. A cookie that + is only Base64(Marshal) was accepted without the secret. When an encryptor + is configured, leave the session empty instead. +Origin: upstream, https://github.com/rack/rack-session/commit/f43638cb3a4d15c3ecaf59e67a04b47fda08eeac +Bug: https://github.com/rack/rack-session/security/advisories/GHSA-33qg-7wpp-89cq +Bug-Debian: https://bugs.debian.org/1133007 +Author: Samuel Williams +Forwarded: not-needed +Last-Update: 2026-09-28 + +--- a/lib/rack/session/cookie.rb ++++ b/lib/rack/session/cookie.rb +@@ -237,8 +237,10 @@ module Rack + # Decode using legacy HMAC decoder + session_data = @legacy_hmac_coder.decode(session_data) + +- elsif !session_data && coder +- # Use the coder option, which has the potential to be very unsafe ++ elsif !session_data && encryptors.empty? && coder ++ # Use the coder option, which has the potential to be very unsafe. ++ # This path is only reached when no encryptors (secrets:) are configured; ++ # if encryptors are present but decryption failed, the cookie is rejected. + session_data = coder.decode(cookie_data) + end + end +--- a/test/spec_session_cookie.rb ++++ b/test/spec_session_cookie.rb +@@ -365,6 +365,31 @@ describe Rack::Session::Cookie do + response.body.must_equal ({"counter"=>1}.to_s) + end + ++ it 'rejects a forged plain Base64::Marshal cookie when secrets: is configured' do ++ # Construct a forged cookie without knowing the secret: plain Base64-encoded ++ # Marshal payload, identical to what an attacker would send. ++ forged_payload = { 'session_id' => 'attacker-fixed', 'counter' => 999 } ++ forged_cookie = "rack.session=#{Base64.strict_encode64(Marshal.dump(forged_payload))}" ++ ++ app = [incrementor, { secrets: @secret }] ++ ++ # The forged cookie must be rejected; session starts fresh (counter = 1). ++ response = response_for(app: app, cookie: forged_cookie) ++ response.body.must_equal ({"counter" => 1}.to_s) ++ end ++ ++ it 'rejects a forged plain Base64::Marshal cookie when secrets: and serialize_json: true are configured' do ++ # serialize_json: true only affects the encryptor serializer; the coder ++ # fallback must also be suppressed when encryptors are configured. ++ forged_payload = { 'session_id' => 'attacker-fixed', 'counter' => 999 } ++ forged_cookie = "rack.session=#{Base64.strict_encode64(Marshal.dump(forged_payload))}" ++ ++ app = [incrementor, { secrets: @secret, serialize_json: true }] ++ ++ response = response_for(app: app, cookie: forged_cookie) ++ response.body.must_equal ({"counter" => 1}.to_s) ++ end ++ + it 'rejects session cookie with different purpose' do + app = [incrementor, { secrets: @secrets }] + other_app = [incrementor, { secrets: @secrets, key: 'other' }] diff -Nru ruby-rack-session-2.1.1/debian/patches/series ruby-rack-session-2.1.1/debian/patches/series --- ruby-rack-session-2.1.1/debian/patches/series 2025-03-08 15:10:05.000000000 +0000 +++ ruby-rack-session-2.1.1/debian/patches/series 2026-09-29 00:49:51.000000000 +0000 @@ -1 +1,2 @@ avoid-relative-require-to-lib.patch +CVE-2026-39324-reject-unencrypted-fallback.patch