Feb 19, 2026·6 min read·30 visits
BlackSheep's HTTP Client failed to sanitize user input before writing it to the network socket. By injecting '\r\n' sequences, attackers can break out of header fields and forge new requests. Fixed in version 2.4.6.
A classic CRLF injection vulnerability (CWE-113) resurrected in the modern asynchronous BlackSheep framework. Specifically affecting the HTTP Client implementation, this flaw allows attackers to inject arbitrary HTTP headers or split requests entirely by manipulating unsanitized input used in connection serialization. This creates a vector for HTTP Request Smuggling and SSRF escalation.
There is something almost poetic about finding a vulnerability as ancient as CRLF Injection in a framework designed to be the bleeding edge of modern Python. BlackSheep is an asynchronous web framework known for its speed, heavily utilizing Cython to squeeze every microsecond of latency out of the request-response cycle. It's the kind of tool you use when you want your API to scream.
But speed has a price. When you are writing low-level serialization logic to avoid the overhead of safer, slower libraries, you often strip away the guardrails. You stop asking, "Is this input safe?" and start asking, "How fast can I put these bytes on the wire?" In the case of CVE-2026-22779, the answer was: extremely fast, and completely unchecked.
The vulnerability doesn't lie in the server component—which delegates to an ASGI server like Uvicorn—but in ClientSession, the built-in HTTP client. This means if you are using BlackSheep to build a proxy, a webhook dispatcher, or a microservice that talks to other microservices based on user input, you just handed your attackers a loaded gun. They aren't just manipulating data; they are rewriting the HTTP protocol stream itself.
At its core, HTTP is a text-based protocol. It relies on specific character sequences—specifically the Carriage Return (\r, 0x0D) and Line Feed (\n, 0x0A)—to delimit headers and body content. If a library treats these control characters as just another part of a string, the protocol breaks. The browser or server on the receiving end can't tell the difference between a header the developer wrote and a header the attacker injected.
The flaw in BlackSheep is located in the blacksheep.scribe module. This module is the scribe (pun intended) responsible for taking a high-level Request object and translating it into the raw bytes sent over the TCP socket.
Prior to version 2.4.6, the scribe logic performed what we call "naive concatenation." It took the method, the path, and the headers, and glued them together with bytes. It assumed that the Request object was immutable or trusted. But in the real world, developers constantly shove dirty user input into User-Agent strings, custom X-Trace-ID headers, or dynamic URL paths. BlackSheep accepted this input verbatim, including the deadly \r\n sequence.
Let's look at the actual code. The vulnerability exists in the Cython implementation (blacksheep/scribe.pyx) and its pure Python fallback. Here is a simplified view of how headers were being written before the patch.
# pseudo-code of the vulnerable logic in blacksheep/scribe.py
def write_header(header_name: bytes, header_value: bytes):
# Direct concatenation of name + separator + value + CRLF
return header_name + b": " + header_value + b"\r\n"There is zero validation here. If header_value is b"innocent\r\nInjected: malicious", the output is:
Header-Name: innocent
Injected: maliciousThe patch introduced by Roberto Prevato is simple but effective. It introduces a helper, _nocrlf, and enforces regex validation on the HTTP method.
# The sanitizer
def _nocrlf(value: bytes) -> bytes:
if b"\r" in value or b"\n" in value:
return value.replace(b"\r", b"").replace(b"\n", b"")
return value
# The patched write_header
def write_header(header_name: bytes, header_value: bytes):
# Now stripping control characters before writing
return header_name + b": " + _nocrlf(header_value) + b"\r\n"They also added a strict regex check for the HTTP method, ensuring you can't inject garbage into the verb itself (e.g., GET / HTTP/1.1\r\n... as a method name).
if not re.match(r'^[!#$%&\'*+\-.0-9A-Z^_`a-z|~]+$', request.method):
raise ValueError(f"Invalid HTTP method: {request.method!r}")To exploit this, we need a scenario where the application takes input from us and uses it in an outgoing request. A classic example is a "Webhooks" feature where the user can specify a custom X-Source-ID to track their requests.
The vulnerable code might look like this:
async def trigger_webhook(user_id, target_url):
# user_id comes from a database, originally set by the user
async with ClientSession() as client:
# Vulnerable header injection
await client.post(target_url, headers=[(b"X-User-ID", user_id.encode())])If the attacker sets their user_id to:
bob\r\nContent-Length: 0\r\n\r\nPOST /admin/delete_user HTTP/1.1\r\nHost: internal-api\r\nX-Ignore:
BlackSheep will serialize this into a single TCP stream that looks like two separate requests to the upstream server:
POST /webhook HTTP/1.1
Host: target.com
X-User-ID: bob
Content-Length: 0
POST /admin/delete_user HTTP/1.1
Host: internal-api
X-Ignore:
...The first request (POST /webhook) is terminated early by the injected Content-Length: 0. The upstream server (e.g., a reverse proxy or the destination API) processes it, then sees the leftovers in the buffer as a second, completely valid request.
We have effectively forged a request to /admin/delete_user that appears to come from the trusted internal backend logic. This is HTTP Request Splitting, and it bypasses internal authentication checks, WAFs, and logic barriers.
You might think, "CVSS 5.3? Medium? I'll patch it next month." That would be a mistake. The CVSS score here is misleadingly low because it assumes a generic configuration. In specific architectural patterns—like microservices or gateway architectures—this is a critical flaw.
This is not just an "Input Validation Error." It is a breach of the contract between the application and the network protocol.
The remediation is straightforward, but mandatory.
Option 1: Upgrade (Recommended)
Upgrade blacksheep to version 2.4.6 or higher immediately. This version includes the _nocrlf sanitizer and the method regex validator.
pip install blacksheep>=2.4.6Option 2: Monkey Patching (Desperate Measures)
If you are stuck on an older version for legacy reasons, you must manually sanitize every single variable that touches ClientSession. This is error-prone and not recommended. You are better off monkey-patching the scribe module yourself, but seriously, just upgrade.
> [!NOTE] > Remember: Input sanitization is defense-in-depth. Even with the patch, you should generally avoid putting unchecked user input directly into HTTP headers. It's just bad hygiene.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
BlackSheep Neoteroi | < 2.4.6 | 2.4.6 |
| Attribute | Detail |
|---|---|
| CWE | CWE-113 (Improper Neutralization of CRLF Sequences) |
| CVSS v3.1 | 5.3 (Medium) |
| Attack Vector | Network (Input via HTTP) |
| Impact | HTTP Request Splitting / Header Injection |
| Exploit Status | PoC Available (in tests) |
| Affected Component | blacksheep.scribe (ClientSession) |
The software includes data in an HTTP response header, but it does not neutralize or incorrectly neutralizes CR and LF characters, allowing the header to be split or new headers to be injected.
Januscape (CVE-2026-53359) is a critical Use-After-Free vulnerability in the x86 Shadow MMU component of the Linux Kernel's KVM subsystem. A logic error in shadow page tracking permits unauthorized page reuse without validating architectural execution roles, leading to dangling pointers in reverse mapping (rmap) tracking entries during guest memory teardown.
CVE-2026-48282 is a critical unauthenticated path traversal and arbitrary file write vulnerability in the Remote Development Services (RDS) component of Adobe ColdFusion. The vulnerability allows a remote, unauthenticated attacker to bypass directory boundaries and write arbitrary files, including CFML-based web shells, onto the host server. This flaw is actively exploited in the wild and enables full unauthenticated remote code execution under the privileges of the ColdFusion service account.
An information disclosure vulnerability exists in the web-auth/webauthn-lib PHP library when using the default SimpleFakeCredentialGenerator without a configured secret. This allows unauthenticated remote attackers to determine if a username exists on the target application.
A Stored and Reflected Cross-Site Scripting (XSS) vulnerability was identified in the Rust web service library 'rama' prior to version 0.3.0-rc.1. When serving directories using DirectoryServeMode::HtmlFileList, the library improperly escapes directory names, filenames, and request path components before injecting them into dynamically generated HTML files. This allows attackers to execute malicious scripts inside user browser sessions.
The ha-mcp add-on for Home Assistant exposes its settings and security policy routes without authentication at the bare root path of TCP port 9583. This exposure allows unauthorized adjacent network clients to reconfigure tools, alter policies, and bypass human-in-the-loop approval gates. The vulnerability has been addressed in development build 7.6.0.dev393 and subsequent releases by restricting access to root-mounted routes exclusively to the Supervisor Ingress IP.
An authentication freshness bypass vulnerability exists in the WebAuthn re-authentication path of Flask-Security-Too versions 5.8.0 and 5.8.1. The flaw allows an authenticated attacker to elevate the freshness status of a victim session using their own WebAuthn credential, bypassing re-authentication constraints.