CVE-2026-22809

The Infinite Loop in Your Cookie Jar: Analyzing CVE-2026-22809

Alon Barad
Alon Barad
Software Engineer

Jan 14, 2026·6 min read

Executive Summary (TL;DR)

Tarteaucitron.js < 1.29.0 contains a ReDoS vulnerability in its Issuu service integration. A greedy regex pattern `/d=(.*)&u=(.*)/` allows attackers to trigger exponential processing time via crafted inputs, causing a Denial of Service. The fix involves anchoring the regex and removing the greedy capture groups, though the remediation strategy introduces a potential secondary XSS risk.

A deep dive into a Regular Expression Denial of Service (ReDoS) vulnerability in tarteaucitron.js, a popular cookie consent manager. The flaw allows malicious configuration strings to trigger catastrophic backtracking, potentially freezing the end-user's browser.

The Hook: When Cookies Bite Back

We all hate cookie banners. They are the digital mosquitoes of the modern web—buzzing in your face, demanding attention, and generally ruining the user experience in the name of 'compliance.' But there is one thing worse than a banner that covers half your screen: a banner that freezes your browser entirely.

Enter tarteaucitron.js. It’s one of the heavy hitters in the GDPR compliance world—accessible, open-source, and widely deployed. It manages those little toggles that let users pretend they have privacy. However, prior to version 1.29.0, it harbored a nasty little surprise in its service integration module. Specifically, the integration for 'Issuu' (a digital publishing platform) contained a logic bomb waiting for the right input to detonate.

This isn't a complex memory corruption bug or a buffer overflow in C. This is a classic Regular Expression Denial of Service (ReDoS). It’s what happens when you ask a regex engine to find a needle in a haystack, but you construct the request in such a poorly optimized way that the engine decides to check every individual atom of every stalk of hay, forever. For a site administrator or a malicious actor with access to the banner's configuration, this flaw turns the user's CPU into a space heater.

The Flaw: Greedy by Nature

The root of all evil in the world of Regular Expressions is often the dot-star: .*. It means 'match any character, as many times as possible.' It is greedy. It is gluttonous. And when you put two of them in the same line without strict boundaries, you are inviting chaos.

The vulnerability lies in tarteaucitron.services.js. When the library tries to parse an issuu_id, it runs the input through a gauntlet of if-statements. Here is the offender:

} else if (issuu_id.match(/d=(.*)&u=(.*)/)) {
    issuu_embed = '?' + issuu_id;
}

Let’s dissect why /d=(.*)&u=(.*)/ is a disaster waiting to happen. The regex engine reads d=. Then it hits the first (.*). Because it's greedy, it consumes the entire rest of the string to the end of the line. Then, it realizes, 'Oh wait, I still need to match &u='. So it backtracks, one character at a time, giving back characters from the first capture group to see if it can find the &u sequence.

If you provide a string that starts with d= but never contains &u=, the engine has to iterate through a massive number of permutations. It splits the string at every possible point, trying to force a match. With a long enough input string, the number of steps required grows exponentially. This is catastrophic backtracking. The JavaScript engine (running on the main thread) locks up, the UI freezes, and the user is forced to kill the tab.

The Code: The Smoking Gun

Let's look at the fix, which gives us a perfect 'Before and After' picture of the developer's realization. The patch was applied in commit f0bbdac2fdf3cd24a325fc0928c0d34abf1b7b52.

The Vulnerable Logic: The code attempts to loosely match an ID format. Note the lack of anchors (^ or $).

// OLD CODE
if (issuu_id.match(/\d+\/\d+/)) { 
    issuu_embed = '#' + issuu_id; 
} else if (issuu_id.match(/d=(.*)&u=(.*)/)) { 
    // ^-- The ReDoS Monster lives here
    issuu_embed = '?' + issuu_id; 
}

The Patched Logic: The fix does two things: it strictly anchors the numeric check and completely removes the dangerous regex. Instead of trying to parse the complex query string with regex, it simply defaults to a 'fail-open' state.

// NEW CODE
if (issuu_id.match(/^\d+\/\d+$/)) { 
    // Anchored! Safe and fast.
    issuu_embed = '#' + issuu_id; 
} else { 
    // No regex at all. Just string concatenation.
    issuu_embed = '?' + issuu_id; 
}

The removal of the else if condition eliminates the ReDoS vector entirely. By checking for the strict numeric format first (^\d+\/\d+$), they ensure that the only expensive operation (regex matching) is done on a very specific, bounded pattern. Everything else falls through to the else block.

The Exploit: Bringing the Browser to its Knees

Exploiting this requires control over the issuu_id. In a typical deployment, this ID might be set in the website's HTML source or a configuration object. If an attacker can inject values into this configuration (perhaps via a stored XSS elsewhere, or if the ID is reflected from a URL parameter), they can trigger the DoS.

Here is how we craft the poison pill:

  1. Start with the trigger: d=
  2. Add the padding: A massive sequence of characters that are valid for . but do not contain &.
  3. Ensure no match: Do not include the &u= sequence.

The Payload:

var vulnerable_id = "d=" + "A".repeat(50000);
tarteaucitron.user.issuu_id = vulnerable_id;
// When the service loads, the regex engine enters an infinite loop.

When the library processes this, the browser tab will immediately become unresponsive. There is no network traffic generated, no error logs in the console (because the console is frozen too). Just silence and a spinning wheel of death.

The Twist: Out of the Frying Pan, Into the Fire?

Here is where things get cynical. Security is often a game of whack-a-mole. While analyzing the patch, I noticed something interesting about the remediation strategy. Look at the else block again:

} else { 
    issuu_embed = '?' + issuu_id; 
}

They removed the ReDoS, yes. But they also removed the validation. Previously, the code at least checked that the input looked like d=...&u=.... Now, anything that isn't a number gets prepended with ? and passed along. Later in the code, this variable is used to construct an iframe URL:

'<iframe ... src="//e.issuu.com/embed.html' + issuu_embed + '"></iframe>'

If issuu_id is tainted, we might have just traded a Denial of Service for a Cross-Site Scripting (XSS) vulnerability. An attacker could potentially inject "><script>alert(1)</script> or break out of the src attribute. While the ReDoS is fixed, the input sanitization here remains... optimistic at best. It's a reminder that 'fixing' a bug often just means 'changing the bug class'.

Fix Analysis (1)

Technical Appendix

CVSS Score
4.4/ 10
CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H

Affected Systems

tarteaucitron.js < 1.29.0

Affected Versions Detail

Product
Affected Versions
Fixed Version
tarteaucitron.js
AmauriC
< 1.29.01.29.0
AttributeDetail
CWE IDCWE-1333 (ReDoS)
CVSS v3.14.4 (Medium)
Attack VectorLocal / Config-based
ImpactHigh Availability (Browser Hang)
Exploit StatusPoC Available
Patch Commitf0bbdac2fdf3cd24a325fc0928c0d34abf1b7b52
CWE-1333
Inefficient Regular Expression Complexity

The software uses a regular expression that can be made to process input in exponential time, leading to a denial of service.

Vulnerability Timeline

Patch Committed (v1.29.0)
2026-01-12
GitHub Advisory Published
2026-01-13
CVE Assigned
2026-01-13

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.