Feb 10, 2026·6 min read·33 visits
Emmett < 1.3.11 crashes when parsing malformed cookies. An attacker can send a request with a cookie key containing characters like '(' or '[' to trigger an unhandled `CookieError`, resulting in a 500 Internal Server Error. Trivial to exploit for DoS.
A classic input validation oversight in the Emmett Python web framework allows unauthenticated attackers to trigger unhandled exceptions by sending malformed HTTP Cookie headers. By leveraging the strict parsing logic of Python's standard library `http.cookies`, an attacker can force the application to crash (HTTP 500) on every request containing specific illegal characters. While not a Remote Code Execution (RCE) vector, this vulnerability presents a trivial, low-cost method for Denial of Service (DoS) attacks against any application running affected versions of Emmett.
In the world of Python web frameworks, performance is often a game of "don't compute it until you need it." Emmett, a framework known for its simplicity and speed, follows this philosophy. One of the things it evaluates lazily is the request.cookies property. The framework assumes that until your application logic actually asks for a cookie, there's no need to spend CPU cycles parsing that messy Cookie header string coming from the browser.
But here is the catch: lazy evaluation is a double-edged sword. If the mechanism that parses that data is fragile, and the parsing happens implicitly deep within the framework's request lifecycle, a crash there doesn't just return None or an empty dictionary. It propagates an unhandled exception all the way up the stack.
CVE-2026-25577 is exactly this scenario. It is a reminder that the boundary between your application and the wild, untrusted internet is often thinner than you think. It relies on the interaction between Emmett's wrapper logic and Python's notoriously strict standard library http.cookies. The result? You can take down a request thread with a single character.
The root cause of this vulnerability lies in a mismatch of expectations. Emmett delegates the heavy lifting of cookie parsing to Python's built-in http.cookies.SimpleCookie. Now, if you have ever worked with Python's SimpleCookie, you know it is somewhat of a pedant. It adheres strictly to older cookie specifications.
If you feed SimpleCookie.load() a string that contains characters it deems "illegal" in a key (such as spaces, square brackets [], or parentheses ()), it does not just ignore the bad segment. It screams. It raises a CookieError.
In a robust web server, you expect the framework to act as a blast shield. It should catch the shrapnel coming from the network, filter it, and hand you clean objects. Emmett, in versions prior to 1.3.11, failed to put up that shield. It took the raw Cookie header, split it by semicolons, and fed each chunk directly into the maw of SimpleCookie.load(). Because there was no try...except block wrapping this operation, a single malformed cookie sent by a malicious client would cause the parser to throw an exception that the framework wasn't expecting, leading directly to an HTTP 500 Internal Server Error.
Let's look at the smoking gun in emmett_core/http/wrappers/__init__.py. This is where the framework tries to convert the raw header string into a nice dictionary-like object.
The Vulnerable Code:
# emmett_core/http/wrappers/__init__.py
def cookies(self) -> SimpleCookie:
cookies: SimpleCookie = SimpleCookie()
# Split the header by semicolon and process blindly
for cookie in self.headers.get("cookie", "").split(";"):
cookies.load(cookie) # <--- The Kill Switch
return cookiesIt looks innocent, right? Standard Python. But cookies.load(cookie) is a ticking time bomb if cookie is something like session_id(=123. The ( character is illegal in a cookie key.
The Fix (Commit c126757133e118119a280b58f3bb345b1c9a8a2a):
The maintainers patched this by wrapping the load operation in a try...except block. This is the definition of defensive programming.
# emmett_core/http/wrappers/__init__.py
def cookies(self) -> SimpleCookie:
cookies: SimpleCookie = SimpleCookie()
for cookie in self.headers.get("cookie", "").split(";"):
try:
cookies.load(cookie)
except Exception:
continue # Just skip the bad crumb
return cookiesNow, if a user sends garbage, Emmett simply shrugs, discards the malformed segment, and continues parsing the rest. The application stays alive.
Exploiting this is trivially easy. You don't need shellcode, you don't need memory addresses, and you don't need authentication. You just need curl.
The attack vector relies on sending a header that passes the web server (like Nginx) but fails in the application logic. Most reverse proxies are surprisingly lenient about what characters sit in a Cookie header, passing them through to the backend app.
Here is the attack flow:
Proof of Concept:
curl -v \
-H "Cookie: session=deadbeef; crash_me(=now" \
http://target.emmett-app.local/When the server receives this, the ( in crash_me(=now triggers the exception. The unhandled error propagates, the request handler dies, and the server returns a 500 error. If you put this in a loop, you can flood the server's logs and potentially exhaust worker threads if the error handling is resource-intensive.
It is easy to dismiss this as "just a 500 error." But in a security context, availability is critical. A single attacker with a basic script can effectively take a service offline for all legitimate users.
Consider the implications:
This is a low-skill, high-yield attack for anyone looking to cause disruption.
The remediation is straightforward. If you are using emmett-framework/core, you need to upgrade immediately.
Primary Mitigation:
pip install --upgrade emmett-coreDefense in Depth (WAF):
If you cannot upgrade immediately (perhaps you are stuck in dependency hell), you can mitigate this at the network edge. Configure your WAF or Load Balancer to drop requests containing non-RFC compliant characters in the Cookie header.
For example, an Nginx rule or a Cloudflare WAF rule regex matching Cookie headers with ( or [ can block the attack before it hits the Python code. However, relying on edge filtering is always riskier than patching the code itself.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
emmett-core emmett-framework | < 1.3.11 | 1.3.11 |
| Attribute | Detail |
|---|---|
| CWE | CWE-248 (Uncaught Exception) |
| CVSS v3.1 | 7.5 (High) |
| Attack Vector | Network (Remote) |
| Impact | Denial of Service (DoS) |
| Exploit Complexity | Low (Trivial) |
| Status | Patched |
The software does not correctly catch or handle exceptions, leading to a denial of service or unexpected state.
netfoil, an allowlist-based DNS proxy, failed to sanitize ALPN fields parsed from untrusted DNS-over-HTTPS (DoH) HTTPS Resource Records. This allowed attackers to inject ANSI escape sequences into log files or trigger Denial of Service (DoS) via uncontrolled memory allocations.
An issue was discovered in the tokio-postgres library for Rust prior to version 0.7.18. A trust assumption mismatch between the PostgreSQL protocol messages sent by a server and how they are parsed and indexed by the client-side library allows a rogue or compromised database server to trigger a Denial of Service (DoS) crash via an unhandled out-of-bounds slice indexing panic.
CVE-2026-14669 is a critical heap-based buffer overflow vulnerability in PostgreSQL's date/time formatting function to_char(timestamptz). The flaw arises from unsafe copying of user-controlled timezone abbreviations into a fixed-size internal buffer. An authenticated database user can trigger this issue by setting a long POSIX timezone abbreviation containing custom formatting, allowing them to overwrite adjacent heap structures and hijack execution control to achieve remote code execution (RCE) with the privileges of the 'postgres' operating system user.
An unauthenticated remote denial of service vulnerability exists in the Unleash feature management platform. By submitting a crafted JSON payload containing deeply nested structures to an OpenAPI-validated endpoint, an attacker can trigger uncontrolled recursion within the error formatting module. This leads to a call-stack exhaustion (RangeError: Maximum call stack size exceeded) inside the Node.js runtime, causing the service to crash immediately without recovery.
CVE-2026-63004 is a server-side request forgery (SSRF) vulnerability in the Unleash feature management platform. Authenticated administrators with CREATE_ADDON or UPDATE_ADDON privileges can exploit this vulnerability to initiate requests to loopback addresses, private networks, and cloud metadata endpoints, potentially leading to information disclosure and credential extraction.
Prior to version 8.0.3, Unleash's Markdown event formatter directly mutated the global template-escaping function of the shared mustache Node.js module, resulting in a process-wide security degradation where HTML/Markdown escaping was permanently disabled for the application lifetime.