PoC Archive PoC Archive
Critical CVE-2026-39324 / GHSA-33qg-7wpp-89cq patched

Rack::Session::Cookie Decrypt-Failure Fallback to Unencrypted Cookies (CVE-2026-39324)

by sm1ee · 2026-07-05

Severity
Critical
CVE
CVE-2026-39324 / GHSA-33qg-7wpp-89cq
Category
web
Affected product
rack-session (RubyGems), Rack::Session::Cookie with secrets: option
Affected versions
<= 2.1.1 (fixed in 2.1.2)
Disclosed
2026-07-05
Patch status
patched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-04
Author / Researchersm1ee
CVE / AdvisoryCVE-2026-39324 / GHSA-33qg-7wpp-89cq
Categoryweb
SeverityCritical
CVSS ScoreNot specified in source
StatusPoC
Tagsruby, rack, session-forgery, cookie, authentication-bypass, ruby-on-rails-adjacent, cwe-287
RelatedN/A

Affected Target

FieldValue
Software / Systemrack-session (RubyGems), Rack::Session::Cookie with secrets: option
Versions Affected<= 2.1.1 (fixed in 2.1.2)
Language / PlatformRuby
Authentication RequiredNo
Network Access RequiredYes

Summary

Rack::Session::Cookie, when configured with the secrets: option for encrypted session cookies, is supposed to reject any cookie that fails decryption. Instead, when all configured encryptors fail to decrypt a cookie, the code silently falls through to the default Base64::Marshal coder and accepts the cookie as valid session data. This means an attacker can submit a plain Base64(Marshal.dump(...)) cookie — with no knowledge of any secret — and have the server load it as legitimate session state, enabling full session/data forgery such as forging an admin user_id.


Vulnerability Details

Root Cause

In lib/rack/session/cookie.rb, when all registered encryptors fail to decrypt the incoming cookie, the code does not terminate the request but instead calls coder.decode() on the raw (unencrypted) cookie value, silently accepting attacker-supplied Marshal-serialized data (CWE-287 improper authentication).

Attack Vector

  1. Identify a target using rack-session <= 2.1.1 with Rack::Session::Cookie configured via the secrets: (plural) option.
  2. Forge a plain session payload, e.g. {"user_id" => 2}, and encode it as Base64(Marshal.dump(payload)).
  3. Send the forged value as the rack.session cookie in a request to a protected endpoint.
  4. Both configured encryptors fail HMAC validation, but the fallback coder accepts the cookie anyway, granting the attacker the forged session state (e.g. admin access).

Impact

Full session/authentication bypass — attackers can forge arbitrary session values (such as admin user IDs) without any secret, on any application using the vulnerable secrets:-configured cookie session store.


Environment / Lab Setup

Target:   Ruby app using rack-session <= 2.1.1 with Rack::Session::Cookie secrets: option
Attacker: ruby, bundler (Gemfile provided), curl

Proof of Concept

PoC Script

See poc/server.rb, poc/verify.rb, poc/attack.rb, and poc/Gemfile in this folder.

1
2
3
4
5
6
cd poc
bundle install

ruby server.rb &      # start vulnerable server
ruby verify.rb        # confirm normal behavior
ruby attack.rb         # forge cookie -> admin access

server.rb stands up a Rack app using secrets:-based encrypted cookies with a regular and an admin user; verify.rb confirms baseline (correct) behavior; attack.rb forges a plain Marshal-serialized cookie and demonstrates it being accepted as a valid admin session.


Detection & Indicators of Compromise

Session cookie encryptor error: HMAC is invalid
Session cookie encryptor error: HMAC is invalid

Signs of compromise:

  • Log entries showing HMAC/encryptor failures immediately followed by an authorized request completing successfully
  • Session cookies that decode as valid Marshal data without matching any issued encrypted session

Remediation

ActionDetail
Primary fixUpdate rack-session to >= 2.1.2, which rejects cookies that fail decryption instead of falling back to the unencrypted coder
Interim mitigationRotate session secrets after upgrading, since forged sessions may have been accepted and re-issued prior to patching

References


Notes

Mirrored from https://github.com/sm1ee/CVE-2026-39324 on 2026-07-05.