CVE-2026-24489

Gakido: When 'Performance First' Means 'Security Optional' (CVE-2026-24489)

Amit Schendel
Amit Schendel
Senior Security Researcher

Jan 26, 2026·4 min read·3 visits

Executive Summary (TL;DR)

Gakido, a 'performance-first' Python HTTP client, forgot that HTTP is a text protocol delimited by newlines. By injecting CRLF sequences (`\r\n`) into header values, attackers can break the protocol framing, leading to Request Smuggling or Header Injection. Patched in v0.1.1 by stripping control characters.

A classic CRLF injection vulnerability in the Gakido HTTP client allows attackers to inject arbitrary HTTP headers or manipulate request bodies via unsanitized input.

The Hook: Speed Kills (Safety)

In the world of Python HTTP clients, everyone wants to be faster than requests. Enter Gakido, a library explicitly marketing itself as a "performance-first" CPython HTTP client. Whenever I see "performance-first" in a README, my ears perk up. Usually, that translates to "we removed all the boring safety checks that were slowing us down."

True to form, Gakido managed to resurrect one of the oldest bugs in the web security handbook: CRLF Injection. It’s almost nostalgic. While modern libraries like httpx or aiohttp have spent years battle-hardening their parsers against protocol deviation, Gakido decided to trust user input implicitly.

The vulnerability is simple yet devastating: the library treated HTTP headers as simple strings to be concatenated, rather than structured data requiring strict serialization rules. This allowed users (and by extension, attackers) to rewrite the HTTP request envelope from the inside out.

The Flaw: Trusting the Carriage Return

HTTP/1.1 is, at its core, a text-based conversation. It relies on specific delimiters to understand where a header name ends, where a value begins, and where the headers stop and the body starts. The magic sequence is \r\n (Carriage Return + Line Feed).

The logic flaw in Gakido was located in gakido/headers.py, specifically within the canonicalize_headers function. This function's job is to merge default headers (like User-Agent) with user-supplied headers.

A robust client would validate that a header name or value does not contain control characters. Gakido, however, took the naive approach: it simply took the strings provided by the user and prepared them for the socket. If a user provided a value containing \r\n, the underlying socket writer would blindly transmit it, tricking the receiving server into thinking a new header (or a new request) had started.

The Code: The Smoking Gun

Let's look at the crime scene. Before the patch, the code simply iterated over headers and merged them. There were zero checks for forbidden characters.

The fix, applied in commit 369c67e67c63da510c8a9ab021e54a92ccf1f788, introduced a sanitizer. Here is the before-and-after logic:

The Vulnerable Logic (Conceptual)

# pseudo-code of the vulnerable state
for name, value in user_headers.items():
    # No validation!
    merged_headers[name] = value

The Fix

The developer introduced a _sanitize_header helper that acts as a bouncer, stripping out the bad characters before they hit the club.

def _sanitize_header(name: str, value: str) -> tuple[str, str]:
    """
    Sanitize header name and value to prevent HTTP header injection (CRLF injection).
    Strips CR, LF, and null bytes from both name and value.
    """
    # Look at this aggressive stripping strategy
    clean_name = name.replace("\r", "").replace("\n", "").replace("\x00", "")
    clean_value = value.replace("\r", "").replace("\n", "").replace("\x00", "")
    return clean_name, clean_value

> [!NOTE] > Researcher Note: The fix uses a sanitize (strip) approach rather than a validate (reject) approach. This is risky. If I send Ad\rmin, Gakido changes it to Admin. This could potentially be abused to bypass string-matching filters in the application layer that look for "Admin" before the HTTP client is called.

The Exploit: Smuggling Headers

Exploiting this is trivial if you control any string that ends up in a header. Let's assume the application takes a query parameter client_id and uses it in a custom header X-Client-ID for backend tracking.

The Setup

Attacker sends input: guineapig\r\nCookie: session_id=admin_token

The Execution

The vulnerable code constructs the raw HTTP message:

GET /resource HTTP/1.1
Host: internal-api
X-Client-ID: guineapig
Cookie: session_id=admin_token
User-Agent: Gakido/0.1.0

The Result

The backend server parses X-Client-ID as just guineapig. It then sees a newline and parses Cookie: session_id=admin_token as a completely valid, separate header.

We have successfully injected a session cookie, effectively hijacking the request context. If we inject two CRLFs (\r\n\r\n), we can terminate the headers entirely and start writing a fake request body or a second request (Request Smuggling), which is catastrophic in microservices environments.

The Fix & Limitations

The remediation is straightforward: Upgrade to Gakido v0.1.1. The patch sanitizes inputs by removing the offending bytes.

However, security teams should remain skeptical.

  1. The Native Bypass: Gakido uses C extensions for speed. If the C-level transport logic (_gakido_native) bypasses the Python-level canonicalize_headers function, the vulnerability might still exist in the compiled binary.
  2. Unicode weirdness: The patch strips standard ASCII control characters. It does not appear to handle Unicode line separators like U+2028, which some eccentric backend parsers might treat as newlines.

For now, the bleeding has stopped, but you should treat this library like a loaded gun: handle with extreme care.

Fix Analysis (1)

Technical Appendix

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

Affected Systems

Python applications using Gakido < v0.1.1Microservices relying on Gakido for internal HTTP calls

Affected Versions Detail

Product
Affected Versions
Fixed Version
Gakido
HappyHackingSpace
< 0.1.10.1.1
AttributeDetail
CWE IDCWE-113
Attack VectorNetwork
CVSS7.5 (High)
ImpactRequest Smuggling / Header Injection
Affected Componentgakido/headers.py
Patch Commit369c67e67c63da510c8a9ab021e54a92ccf1f788
CWE-113
HTTP Response Splitting

Improper Neutralization of CRLF Sequences in HTTP Headers ('HTTP Response Splitting')

Vulnerability Timeline

Patch Committed (369c67e)
2026-01-25
v0.1.1 Released
2026-01-25

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.