Cookie Jar Overflow: A New Threat to HttpOnly Cookies in XSS Vulnerable Applications

Cross-Site Scripting (XSS) is often considered a beautiful attack due to its elegance and effectiveness in exploiting vulnerabilities within web applications. As security professionals and ethical hackers, we frequently encounter XSS vulnerabilities, and the excitement of discovering one is often paired with the dread of an HttpOnly flag. When we find an XSS vulnerability, one of the primary obstacles we face is the HttpOnly flag. The HttpOnly flag, when set on cookies, restricts access to those cookies from client-side JavaScript, thus adding a layer of protection against attacks that aim to steal session cookies. This makes it significantly harder for attackers to compromise user sessions using XSS alone. So, we generally chain it with CSRF to leverage the impact of XSS.
However, what if I told you that we can still hijack HttpOnly cookies using a basic XSS attack?

Everything has its storage, and cookies are no exception. In the case of Chrome, the cookie jar is limited to 4096 bytes per domain. This means that the total size of all cookies set for a given domain cannot exceed this limit. When a JavaScript function generates more than 500 cookies for the same domain, the browser will begin deleting the oldest cookies in the jar to accommodate new ones, effectively pushing the size of the cookie storage. Now, here’s where an attacker can take advantage of this behavior. In scenarios where an attacker can manipulate cookies or inject additional cookies (for instance, through XSS), the browser’s cookie jar mechanism becomes an opportunity for exploitation. As cookies are automatically deleted to make space for newer ones, the attacker can leverage this process to overflow the cookie jar, leading to potential vulnerabilities that can be exploited. By carefully crafting the cookies and controlling their contents, an attacker could gain access to or interfere with critical session data, making this a powerful avenue for malicious actions.
Consider the following JavaScript snippet:
<img src="x" onerror="for(let i=999;i--;)document.cookie=`c${i}=${i};Secure`;document.cookie='PHPSESSID=1337mickey';">
In this example, the JavaScript generates 999 cookies with random values. After these cookies are set, the last cookie (PHPSESSID=1337mickey
) is manually created, mimicking the session ID of the victim.
Session IDs are typically generated by browsers and later linked to the user’s session by the application. By injecting the victim’s session ID (PHPSESSID
), the attacker can hijack the session, effectively taking over the victim's account.
This attack takes advantage of the cookie jar overflow behavior. Since browsers automatically delete the oldest cookies when the storage limit is reached, the attacker can carefully craft the overflow process to ensure that the last cookie generated is the one containing the victim’s session ID. This opens the door to session fixation and account takeover.
Let’s try to replicate the attack in the lab created by me:

When you log in to the system, the PHP session ID (PHPSESSID
) is stored in your browser’s cookies to maintain the session state. This session ID is crucial for the application to link your authenticated session with your actions.


Before we can exploit this, we need to find a vulnerability in the application. In this case, the search feature on the dashboard page is vulnerable to Reflected XSS. Reflected XSS occurs when user-supplied input is immediately included in the output response, allowing an attacker to inject malicious scripts into the page.
https://example.com/dashboard.php?search=<img src="x" onerror="for(let i=999;i--;)document.cookie=`c${i}=${i};Secure`;document.cookie='PHPSESSID=1337mickey';">
What this payload does is generate a large number of cookies using a loop. After 999 cookies are generated, it sets the session cookie PHPSESSID=1337mickey
. The key part here is that the PHPSESSID
cookie will override the session ID stored in the browser, and the session ID used by the attacker is now set to 1337mickey
.

At this point, the victim may be logged out of the application and might think it’s a glitch or session timeout. They log in again, but now something crucial has happened: the browser has stored the session ID (1337mickey
) in its cookies.
Now, as the attacker, you can use the PHPSESSID=1337mickey
session ID stored in your browser to authenticate as the victim. With this session ID, you effectively have full access to the victim's account, and the attack is complete.

Feel free to suggest and follow!
Your feedback and suggestions are always welcome. If you have any questions or ideas to improve the content, don’t hesitate to reach out.