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-2026-24001

Diffing Dangerously: Infinite Loops and ReDoS in jsdiff

Alon Barad
Alon Barad
Software Engineer

Jan 22, 2026·7 min read·107 visits

Executive Summary (TL;DR)

The `jsdiff` library, used by millions of Node.js applications to compare text, contains a flaw in how it parses patch headers. By injecting obscure Unicode line separators (like `\u2028`) into a filename header, an attacker can cause the parser to enter an infinite loop. This leads to 100% CPU usage and eventual memory exhaustion, crashing the host process. Patched in versions 8.0.3, 5.2.2, and 4.0.4.

A critical Denial of Service vulnerability in the popular `jsdiff` library allows attackers to crash applications by supplying a patch file with specific Unicode line terminators. This triggers an infinite memory-leaking loop or a ReDOS condition.

The Hook: When a Dot Isn't a Dot

In the chaotic world of JavaScript ecosystem, jsdiff is a cornerstone. It's the engine under the hood of your favorite testing frameworks, code review tools, and git UI wrappers. It takes two strings and tells you what changed. Simple, right? But as we often find in security, the most dangerous vulnerabilities hide in the most mundane tasks—like parsing a file header.

CVE-2026-24001 is a classic reminder that relying on Regular Expressions for parsing structured data is like trying to perform surgery with a chainsaw: it might work, but it's going to be messy. The vulnerability exploits a fundamental quirk in JavaScript's Regex engine regarding what constitutes a "character."

The issue specifically targets the parsePatch method. When jsdiff consumes a unified diff (the kind with --- and +++ headers), it has to extract filenames. An attacker can supply a specially crafted string that looks valid enough to enter the parsing logic but invalid enough to break the internal state machine, causing the application to hang indefinitely. It’s a low-complexity, high-annoyance Denial of Service that turns your robust CI/CD pipeline into a paperweight.

The Flaw: The Infinite Loop of Death

To understand the bug, you have to understand the JavaScript Regular Expression dot (.). Most developers assume . matches "any character." But in JS (pre-flag s), the dot is actually a picky eater. It matches anything except line terminators. You know about \n and \r, but did you know about \u2028 (Line Separator) and \u2029 (Paragraph Separator)? Neither did the original regex author.

The vulnerable code uses a regex anchored with $ to match the filename in a patch header. The logic goes something like this:

  1. Look at the current line.
  2. Does it start with --- or +++?
  3. If yes, execute the regex /^(---|\+\+\+)\s+(.*)\r?$/ to extract the filename.
  4. If the regex matches, advance the parser index.

Here is the trap: The code checks if the line starts with --- to decide if it should parse a header. But then it uses the strict regex to actually do the parsing. If you provide a line like --- filename\u2028.js, the initial check says "Yes, this is a header!" But the extraction regex fails because the . stops at \u2028, and the $ anchor can't be reached at the end of the string. The regex returns null.

Because the match failed, the code assumes it didn't successfully consume the line. However, because the line still starts with ---, the loop comes back around, looks at the same line, and says "Hey, looks like a header!" It tries the regex again. It fails again. Infinite loop. Game over.

The Code: The Smoking Gun

Let's look at the vulnerable logic in src/patch/parse.ts. This is a textbook example of logic desynchronization between a condition and an operation.

The Vulnerable Code:

function parseFileHeader(index: Partial<StructuredPatch>) {
  // The loop logic (abstracted) keeps calling this if it sees --- or +++
  // But this regex is too strict:
  const fileHeader = (/^(---|\+\+\+)\s+(.*)\r?$/).exec(diffstr[i]);
  if (fileHeader) {
    // Logic to consume the line and increment 'i'
    // ...
  }
  // If fileHeader is null, 'i' is NEVER incremented,
  // but the parent loop doesn't know that and retries.
}

If exec returns null due to a hidden \u2028, the index i remains static. The fix involves abandoning the regex for the header extraction entirely. Instead of asking a regex to validate the whole line including the end, the developers switched to manual string slicing. This is far more robust because substring and split don't care about line separators.

The Fix (Commit 15a1585230748c8ae6f8274c202e0c87309142f5):

function parseFileHeader(index: Partial<StructuredPatch>) {
  // Relaxed check: just look for the start
  const fileHeaderMatch = (/^(---|\+\+\+)\s+/).exec(diffstr[i]);
  if (fileHeaderMatch) {
    const prefix = fileHeaderMatch[1];
    // Manual parsing > Regex parsing
    const data = diffstr[i].substring(3).trim().split('\t', 2);
    const header = (data[1] || '').trim();
    
    // Forcefully increment index regardless of what garbage follows
    i++; 
    // ...
  }
}

By mechanically splitting the string, the parser guarantees progress through the file, preventing the infinite loop state.

The Exploit: Weaponizing Unicode

Exploiting this is trivially easy if you can feed a patch file to a vulnerable system. Think of a Pull Request bot that parses diffs to check for style violations, or a web-based code viewer.

The Payload:

To trigger the crash, we just need a valid diff header structure with an invalid terminator inside the capture group.

// The poison pill
const payload = '--- a/malicious' + '\u2028' + 'file.js\n+++ b/malicious' + '\u2028' + 'file.js\n@@ -1,1 +1,1 @@\n-foo\n+bar';
 
const jsdiff = require('diff');
// This call will never return and will spike memory usage
jsdiff.parsePatch(payload);

When parsePatch hits that first line, the CPU spikes to 100%. Node.js's single-threaded event loop is blocked immediately. No other requests can be served. Eventually, as the loop (in some variations) accumulates data or just churns, the process may run out of memory or simply stay frozen until the orchestration layer (Kubernetes, etc.) kills it. If this is a serverless function, you're paying for the timeout duration every single time.

Attack Flow:

The Impact: Why Low CVSS is a Lie

The official CVSS score is a measly 2.7. This is misleading. The metrics likely penalized the score because it requires "User Interaction" (someone has to submit the patch) or because the "Availability" impact is listed as Low. Don't be fooled. In the context of a web service that automatically processes diffs (like a CI runner or a git platform), this is a High severity issue.

If you run a service where users supply code patches, this vulnerability allows any authenticated user (or unauthenticated, depending on the endpoint) to take down your parser service. It is an asymmetric attack: minimal effort for the attacker, maximum disruption for the server.

Furthermore, there is a secondary ReDOS (Regular Expression Denial of Service) vector identified in the preamble parsing. Even if the infinite loop doesn't catch you, the cubic complexity $O(n^3)$ of parsing massive headers with mixed terminators can cause CPU exhaustion just as effectively.

The Fix: Stop the Bleeding

The remediation is straightforward: upgrade. The maintainers have released patches for all major release lines.

> [!NOTE] > Action Required: Upgrade jsdiff immediately.

  • v6.x users: Upgrade to 6.0.0 or higher (specifically fixed in 8.0.3 per advisory).
  • v5.x users: Upgrade to 5.2.2.
  • v4.x users: Upgrade to 4.0.4.

If you cannot upgrade immediately (legacy codebases are fun, aren't they?), you must sanitize input before passing it to jsdiff. A simple string replacement can neutralize the exploit:

// Sanitize patch string before parsing
const safePatch = userPatch.replace(/[\u2028\u2029]/g, '');
jsdiff.parsePatch(safePatch);

This strips the dangerous separators, allowing the original regex to either match or fail cleanly without looping.

Official Patches

GitHub AdvisoryOfficial GHSA Advisory
jsdiffFix Commit

Fix Analysis (1)

Technical Appendix

CVSS Score
2.7/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:U

Affected Systems

Node.js applications using `jsdiff`Code review toolsGit web interfacesCI/CD pipelines processing patch filesTest frameworks using diff for assertions

Affected Versions Detail

Product
Affected Versions
Fixed Version
jsdiff
Kevin Decker
>= 6.0.0, < 8.0.38.0.3
jsdiff
Kevin Decker
>= 5.0.0, < 5.2.25.2.2
jsdiff
Kevin Decker
< 4.0.44.0.4
AttributeDetail
CWECWE-400 (Uncontrolled Resource Consumption)
Attack VectorNetwork
CVSS2.7 (Low)
Bug ClassInfinite Loop / Logic Error
Affected ComponentparsePatch function
Exploit ComplexityLow

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
T1499.003Application Exhaustion
Impact
CWE-400
Uncontrolled Resource Consumption

The software does not properly control the allocation and maintenance of a limited resource, allowing an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources.

Known Exploits & Detection

Internal AnalysisThe commit diff reveals the exact mechanism of the bypass and fix.

Vulnerability Timeline

Fix committed to main branch
2026-01-07
CVE-2026-24001 Published
2026-01-22

References & Sources

  • [1]jsdiff Repository

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

•1 minute ago•CVE-2026-56677
8.6

CVE-2026-56677: Unauthenticated Server-Side Request Forgery in 9Router OIDC Test Endpoint

A high-severity security vulnerability exists in 9Router, an AI router and token saver dashboard. When dashboard authentication features are disabled or left in default configurations, the application exposes administrative testing routines directly to the public internet. Unauthenticated network adversaries can exploit the OIDC configuration validation endpoint to initiate arbitrary HTTP requests, routing unauthorized traffic to local loops, adjacent container ports, and cloud resource metadata interfaces.

Amit Schendel
Amit Schendel
0 views•5 min read
•about 1 hour ago•CVE-2026-64849
9.3

CVE-2026-64849: Server-Side Request Forgery (SSRF) in MLflow Webhooks via DNS Rebinding

CVE-2026-64849 is a critical Server-Side Request Forgery (SSRF) vulnerability affecting MLflow tracking servers prior to version 3.15.0. It allows unauthenticated remote attackers to bypass outbound request destination filters using DNS rebinding or HTTP redirects. This exposure risks compromising sensitive cloud infrastructure metadata and internal microservices.

Alon Barad
Alon Barad
2 views•5 min read
•about 2 hours ago•CVE-2026-69146
6.5

CVE-2026-69146: Missing Authorization Bypass in MLflow Basic Authentication Middleware

This technical report details a missing authorization vulnerability (CVE-2026-69146 / GHSA-3p64-6gvh-82v5) affecting the MLflow platform from version 3.13.0 to 3.15.0. When MLflow is configured with the built-in basic-auth plugin, authenticated users can bypass run-level UPDATE authorization checks, enabling unauthorized dataset and model lineage metadata injection.

Alon Barad
Alon Barad
1 views•7 min read
•about 3 hours ago•CVE-2026-69148
7.1

CVE-2026-69148: Broken Object Level Authorization (BOLA) in MLflow Model Registry

MLflow prior to version 3.15.0 fails to perform proper authorization checks when registering model versions, allowing authenticated users with access to a registered model to link and access artifacts from runs and models belonging to other users without authorization.

Amit Schendel
Amit Schendel
4 views•7 min read
•about 4 hours ago•CVE-2026-59893
7.5

CVE-2026-59893: Regular Expression Denial of Service in sqlparse Lexer

A high-severity Regular Expression Denial of Service (ReDoS) vulnerability in the sqlparse Python library prior to version 0.6.0 allows unauthenticated remote attackers to trigger CPU exhaustion and application denial of service via crafted SQL inputs containing unmatched dollar-quoted literals or unclosed multiline comments.

Alon Barad
Alon Barad
4 views•6 min read
•about 5 hours ago•GHSA-FHGH-WQ4Q-R37X
7.8

GHSA-FHGH-WQ4Q-R37X: Remote Code Execution via Sigstore Signature Verification Bypass in uniget CLI

A high-severity logic inversion flaw in the uniget CLI completely bypasses Sigstore cryptographic signature verification on metadata files by default. If an attacker can poison the package metadata cache or repository, they can execute arbitrary OS commands under the privileges of the active user.

Alon Barad
Alon Barad
5 views•5 min read