Jan 26, 2026·4 min read·24 visits
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.
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.
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.
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:
# pseudo-code of the vulnerable state
for name, value in user_headers.items():
# No validation!
merged_headers[name] = valueThe 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.
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.
Attacker sends input: guineapig\r\nCookie: session_id=admin_token
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.0The 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 remediation is straightforward: Upgrade to Gakido v0.1.1. The patch sanitizes inputs by removing the offending bytes.
However, security teams should remain skeptical.
_gakido_native) bypasses the Python-level canonicalize_headers function, the vulnerability might still exist in the compiled binary.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.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Gakido HappyHackingSpace | < 0.1.1 | 0.1.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-113 |
| Attack Vector | Network |
| CVSS | 7.5 (High) |
| Impact | Request Smuggling / Header Injection |
| Affected Component | gakido/headers.py |
| Patch Commit | 369c67e67c63da510c8a9ab021e54a92ccf1f788 |
Improper Neutralization of CRLF Sequences in HTTP Headers ('HTTP Response Splitting')
A security feature bypass vulnerability in the Falco k8saudit plugin (and its cloud-specific variants) allowed privileged workloads to run undetected. This bypass occurred because the plugin's default extraction logic and rules only evaluated standard containers, completely omitting initContainers and ephemeralContainers.
nginx-ignition is a web-based user interface for managing the Nginx web server. In versions 2.33.0 through 2.35.0, the application is vulnerable to an improper authentication flaw (CWE-287) in its Multi-Factor Authentication (MFA) implementation. The stateless validation of Time-Based One-Time Passwords (TOTP) allows an attacker to reuse a captured, active verification code multiple times within the standard 30-second validity window, successfully bypassing secondary authentication checks if primary credentials are known.
A vulnerability exists in the i18n middleware of nginx-ignition, enabling CPU amplification attacks. By transmitting a crafted Accept-Language header containing malformed tags separated by underscores, an unauthenticated remote attacker can bypass the length-guard threshold of the underlying Go parsing library. Normalization of underscores to hyphens occurs after the initial validation checks, forcing the parser into expensive quadratic-time loops that consume 100% of available CPU resources. This leads to a complete denial of service for the administrative API and potentially degrades the availability of the hosting system. This vulnerability has been resolved in version 2.40.1.
Nginx Ignition prior to version 2.41.1 contains a Time-of-Check to Time-of-Use (TOCTOU) race condition in its unauthenticated onboarding API endpoint. This flaw allows remote, unauthenticated attackers to register an administrative account by sending concurrent HTTP requests during the initial system configuration phase, bypassing the check meant to restrict onboarding to a single initial administrator.
A logic error in Hatchet's OAuth state validation mechanism allows unauthenticated remote attackers to bypass state parameter verification. By submitting an empty state parameter, attackers can exploit an equality collision with cleared session keys, facilitating Login Cross-Site Request Forgery (Login CSRF) or Session Fixation.
A high-severity access control vulnerability in ToolHive CLI before v0.30.1 and ToolHive Studio before v0.38.0 allows local containerized MCP servers to bypass network isolation. This enables malicious workloads to establish TCP/IP connections to administrative and control plane endpoints exposed on the host loopback interface.