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
References
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-05 |
| Last Updated | 2026-04 |
| Author / Researcher | sm1ee |
| CVE / Advisory | CVE-2026-39324 / GHSA-33qg-7wpp-89cq |
| Category | web |
| Severity | Critical |
| CVSS Score | Not specified in source |
| Status | PoC |
| Tags | ruby, rack, session-forgery, cookie, authentication-bypass, ruby-on-rails-adjacent, cwe-287 |
| Related | N/A |
Affected Target
| Field | Value |
|---|---|
| Software / System | rack-session (RubyGems), Rack::Session::Cookie with secrets: option |
| Versions Affected | <= 2.1.1 (fixed in 2.1.2) |
| Language / Platform | Ruby |
| Authentication Required | No |
| Network Access Required | Yes |
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
- Identify a target using
rack-session<= 2.1.1 withRack::Session::Cookieconfigured via thesecrets:(plural) option. - Forge a plain session payload, e.g.
{"user_id" => 2}, and encode it asBase64(Marshal.dump(payload)). - Send the forged value as the
rack.sessioncookie in a request to a protected endpoint. - 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, andpoc/Gemfilein this folder.
| |
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
Marshaldata without matching any issued encrypted session
Remediation
| Action | Detail |
|---|---|
| Primary fix | Update rack-session to >= 2.1.2, which rejects cookies that fail decryption instead of falling back to the unencrypted coder |
| Interim mitigation | Rotate 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.