CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2025-61686

Cookie Monster's Crumbs: Breaking React Router Session Storage

Alon Barad
Alon Barad
Software Engineer

Feb 18, 2026·7 min read·121 visits

Executive Summary (TL;DR)

If you aren't signing your session cookies in React Router or Remix, attackers can use `../` sequences in their session ID to traverse the filesystem. This allows arbitrary file writes (session saving) and reads (session loading), potentially leading to system compromise.

A critical path traversal vulnerability in React Router and Remix's `createFileSessionStorage` allows attackers to read and write arbitrary files on the server by manipulating unsigned session cookies.

The Hook: Convenience vs. Security

We all love 'Developer Experience'. It's that warm, fuzzy feeling when a library just works out of the box without requiring you to configure a Redis cluster or a PostgreSQL database just to store a user's dark mode preference. React Router (and by extension, Remix) offers createFileSessionStorage for exactly this reason. It's the 'easy mode' for session management: store the session data as JSON files on the local disk. Simple, right?

Here is the catch: Easy mode often comes with easy exploits. The architecture assumes that the session ID—the key used to locate that JSON file on disk—is a trusted, randomly generated UUID. But in the world of web security, assuming trust is the first step toward a catastrophic incident.

CVE-2025-61686 is the result of that assumption meeting reality. If a developer configures this storage mechanism without enabling cookie signing (a distinct possibility in 'dev' or 'proof-of-concept' environments that inevitably crawl their way into production), the application blindly trusts the cookie provided by the user. And when an application trusts user input to construct file paths, we get to play one of my favorite games: Path Traversal.

The Flaw: Trusting the User's Map

The vulnerability lies deep within packages/react-router-node/sessions/fileStorage.ts. The logic is deceivingly simple: the server receives a cookie containing a session ID, and it needs to find the corresponding file on the disk to read the user's data.

Under normal circumstances, the workflow looks like this:

  1. Server receives Cookie: session=1234-uuid-5678.
  2. Server looks in ./sessions/.
  3. Server reads ./sessions/1234-uuid-5678.

However, the code responsible for generating that path was missing a crucial check. It essentially performed a raw concatenation (or path.join) of the session directory and the session ID. It didn't verify that the resulting path was still inside the intended directory.

If the application is configured with unsigned cookies (i.e., no secrets array provided to the storage factory), the server accepts whatever string the client sends as the session ID. An attacker doesn't send a UUID; they send a directory traversal payload. When the server processes ../../../../tmp/evil, it obediently steps out of the session sandbox and touches the filesystem wherever the attacker points.

The Code: The Smoking Gun

Let's look at the logic that caused the headache. While the actual source code involves a few layers of abstraction, the root cause boils down to how getFile handled the ID.

The Vulnerable Logic: In versions prior to 7.9.4, the code treating the ID was essentially pass-through. It took the dir (the folder where sessions live) and the id (from the cookie) and smashed them together.

// Conceptual vulnerable implementation
function getFile(dir: string, id: string) {
  // No validation that 'id' is just a filename
  return path.join(dir, id);
}

The Fix: The patch introduced in version 7.9.4 (and Remix 2.17.2) doesn't just blindly join paths. It likely validates that the ID does not contain path separators or resolves the path to ensure it's still contained within the root directory. A robust fix usually looks something like this:

// Secure implementation pattern
function getFile(dir: string, id: string) {
  if (id.includes(path.sep) || id.includes("..")) {
     throw new Error("Invalid session ID");
  }
  return path.join(dir, id);
}

The fix forces the application to treat the Session ID as a strictly alphanumeric token, effectively neutralizing the traversal characters.

The Exploit: crafting the crumbs

Exploiting this requires a specific configuration: Unsigned Cookies. If the application uses createCookieSessionStorage with a secrets array, the exploit fails because the server will try to verify the signature of our malicious payload, fail, and discard it before it ever reaches the file system logic. But if secrets is missing... it's game on.

Step 1: The Payload We want to traverse out of the ./sessions directory. Let's say we want to write a file to /tmp/pwned. Our raw Session ID would be: ../../../../tmp/pwned

Step 2: Encoding React Router and Remix don't store raw strings in cookies; they typically Base64 encode them. We need to mimic their encoding scheme (standard Base64 or URL-safe Base64 depending on the exact version/helper used).

# Generate the Base64 payload
# The quotes are important because the cookie value is JSON serialized string
echo -en '"../../../../tmp/pwned"' | base64
# Output: ILi4vLi4vLi4vLi4vdG1wL3B3bmVkIg==

Step 3: The Attack We simply inject this into the browser or curl request.

curl -v http://localhost:3000/login \
  -H "Cookie: session=ILi4vLi4vLi4vLi4vdG1wL3B3bmVkIg=="
  -d "username=admin&password=password"

The Result: When the server processes the login and attempts to set the session data (e.g., { userId: 1 }), it serializes that object to JSON and writes it to the path derived from our ID. The server effectively executes: fs.writeFile('/tmp/pwned', '{"userId":1}')

We have achieved Arbitrary File Write. While we can't easily control the content (it's JSON serialized session data), we can create files or corrupt existing files that the web user has permission to write to.

The Impact: Why 9.1?

You might be thinking, "So I can write a JSON file to /tmp. Big deal." But a CVSS score of 9.1 (Critical) isn't handed out for minor inconveniences. The impact here is surprisingly broad.

1. Arbitrary File Write (Integrity): If the application runs with high privileges (bad practice, but common), an attacker could overwrite critical configuration files. Even with low privileges, an attacker could potentially overwrite files used by other parts of the application, leading to application instability or behavior modification.

2. Denial of Service (Availability): An attacker could script the creation of millions of files (inode exhaustion) or overwrite critical operational locks, crashing the service.

3. Arbitrary File Read (Confidentiality - with caveats): If the attacker points the traversal to a file that happens to be valid JSON (or if the parser is lenient), the application might load that file into the session object. The attacker could then potentially retrieve that data if the application reflects session details back in the UI (e.g., "Welcome, [User Name]"). While less likely than the write vector, it's a valid path for exfiltration.

The Fix: Sign Your Cookies!

The remediation is two-fold. First, update your dependencies. The maintainers patched this in @react-router/node version 7.9.4 and @remix-run/node version 2.17.2. The patch ensures that session IDs are sanitized before hitting the disk.

Second, and more importantly: Never run sessions without signatures.

Even with the patch, unsigned cookies allow clients to pick their own session IDs. This can lead to Session Fixation attacks. Always provide a secrets array when creating your storage:

const { getSession, commitSession, destroySession } = createFileSessionStorage({
  dir: "./sessions",
  cookie: {
    name: "__session",
    // The secret sauce (literally)
    secrets: ["s3cr3t-k3y-that-should-be-in-env"],
    secure: true,
  },
});

When secrets are present, the server signs the cookie value. If an attacker modifies the cookie to include ../../, the signature validation will fail, and the request will be rejected before the file system is ever touched. It's cryptographic access control for your storage layer.

Official Patches

Remix/React RouterOfficial GHSA Advisory

Fix Analysis (1)

Technical Appendix

CVSS Score
9.1/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H
EPSS Probability
0.04%
Top 89% most exploited

Affected Systems

@react-router/node@remix-run/node@remix-run/deno

Affected Versions Detail

Product
Affected Versions
Fixed Version
@react-router/node
Remix
7.0.0 - 7.9.37.9.4
@remix-run/node
Remix
< 2.17.22.17.2
@remix-run/deno
Remix
< 2.17.22.17.2
AttributeDetail
CWE IDCWE-22
CVSS Score9.1 (Critical)
Attack VectorNetwork
Attack ComplexityLow
Privileges RequiredNone
Exploit StatusPoC Available

MITRE ATT&CK Mapping

T1083File and Directory Discovery
Discovery
T1005Data from Local System
Collection
CWE-22
Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.

Known Exploits & Detection

GitHubVendor Advisory and reproduction steps

Vulnerability Timeline

Vulnerability reported to Shopify/Remix team
2026-01-08
CVE-2025-61686 Published
2026-01-10
Patched versions released (7.9.4 / 2.17.2)
2026-01-10

References & Sources

  • [1]GHSA Advisory
  • [2]NIST NVD Entry

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•9 days ago•CVE-2026-87697
8.8

CVE-2026-87697: Untrusted Deserialization in .NET PresentationCore Clipboard Handling

A remote code execution vulnerability exists in Microsoft .NET due to untrusted data deserialization within the PresentationCore component. The flaw stems from implicit auto-conversion flags during clipboard data retrieval operations.

Alon Barad
Alon Barad
30 views•5 min read
•9 days ago•CVE-2026-70007
8.8

CVE-2026-70007: Out-of-Bounds Write Vulnerability in .NET Framework and WPF Subsystem

An out-of-bounds write vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio allows unauthenticated remote attackers to execute arbitrary code via crafted pixel-shader bytecode or auto-converted clipboard payloads.

Amit Schendel
Amit Schendel
18 views•6 min read
•9 days ago•CVE-2026-70186
7.5

CVE-2026-70186: ASP.NET Core Denial of Service Vulnerability via Framework Deadlock

ASP.NET Core contains a thread deadlock vulnerability (CWE-833) that allows an unauthenticated remote attacker to cause a denial of service over the network by exhausting server thread pool resources.

Amit Schendel
Amit Schendel
17 views•5 min read
•9 days ago•CVE-2026-70035
8.8

CVE-2026-70035: Insecure Deserialization Remote Code Execution in Microsoft .NET Framework and .NET Runtime

CVE-2026-70035 is a high-severity Remote Code Execution (RCE) vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio caused by improper handling during the deserialization of untrusted data (CWE-502). An unauthenticated attacker can execute arbitrary code within the context of the affected process by delivering a crafted serialized payload.

Amit Schendel
Amit Schendel
23 views•6 min read
•9 days ago•CVE-2026-70183
7.5

CVE-2026-70183: Elevation of Privilege in ASP.NET Core and Visual Studio via Concurrent Race Condition

An elevation of privilege vulnerability exists in ASP.NET Core and Microsoft Visual Studio due to improper synchronization during concurrent thread execution. Authenticated remote attackers with low privileges can exploit a timing window to manipulate shared resources and assume higher-level execution contexts.

Alon Barad
Alon Barad
20 views•5 min read
•12 days ago•CVE-2026-107844
5.3

CVE-2026-107844: Path Traversal Vulnerability in Contao ImagesController

A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.

Amit Schendel
Amit Schendel
23 views•5 min read