Here is the combined list of vulnerabilities, formatted as markdown:
This document outlines identified vulnerabilities in the provided project, detailing their descriptions, impacts, mitigations, and steps for exploitation and testing.
-
Description:
- An attacker sends an HTTP request to an application wrapped by
WsgiToAsgi
. - The attacker includes HTTP headers named
Content-Length
and/orContent-Type
in their request. - The
WsgiToAsgi.build_environ
function processes these headers. - Due to direct assignment in
build_environ
, the attacker-controlled values forContent-Length
andContent-Type
headers are directly injected into the WSGI environment (environ
) without sanitization or validation. - The wrapped WSGI application receives this modified
environ
dictionary. - If the WSGI application relies on
CONTENT_LENGTH
orCONTENT_TYPE
from the environment for security checks, request parsing, or any other critical logic, it will be using attacker-controlled values.
- An attacker sends an HTTP request to an application wrapped by
-
Impact: The impact of this vulnerability depends on how the wrapped WSGI application uses the
CONTENT_LENGTH
andCONTENT_TYPE
environment variables. Potential impacts include:- Bypass security checks: If the WSGI application uses
CONTENT_LENGTH
to validate the request body size for security reasons, an attacker could bypass these checks by injecting a smallerCONTENT_LENGTH
value than the actual body size. - Request smuggling/desync: In certain WSGI application setups or when interacting with other components that also process the request based on
CONTENT_LENGTH
, manipulating this header could lead to request smuggling or desync issues. - Unexpected application behavior: If the WSGI application uses
CONTENT_TYPE
for content parsing or routing, an attacker could influence this behavior by injecting a different content type. - Information disclosure or other application-specific vulnerabilities: Depending on the WSGI application's logic, manipulating these headers might expose other vulnerabilities or lead to information disclosure.
- Bypass security checks: If the WSGI application uses
-
Vulnerability Rank: High
-
Currently implemented mitigations: No mitigations are implemented in the provided code. The
WsgiToAsgi.build_environ
function directly injects the header values into the WSGI environment. -
Missing mitigations: Input validation and sanitization for
Content-Length
andContent-Type
headers inWsgiToAsgi.build_environ
are missing. The application should either:- Ignore
Content-Length
andContent-Type
headers from the ASGI scope and rely on its own parsing or predefined values if needed. - Sanitize or validate the values of
Content-Length
andContent-Type
headers to ensure they are within expected bounds and formats before including them in the WSGI environment.
- Ignore
-
Preconditions:
- The application must be using
asgiref.wsgi.WsgiToAsgi
to wrap a WSGI application. - The wrapped WSGI application must rely on the
CONTENT_LENGTH
orCONTENT_TYPE
environment variables for security-sensitive or critical operations.
- The application must be using
-
Source code analysis:
File: /code/asgiref/wsgi.py Content: ... def build_environ(self, scope, body): ... for name, value in self.scope.get("headers", []): name = name.decode("latin1") if name == "content-length": corrected_name = "CONTENT_LENGTH" elif name == "content-type": corrected_name = "CONTENT_TYPE" else: corrected_name = "HTTP_%s" % name.upper().replace("-", "_") # HTTPbis say only ASCII chars are allowed in headers, but we latin1 just in case value = value.decode("latin1") if corrected_name in environ: value = environ[corrected_name] + "," + value # Potential header merging issue, but not main vulnerability environ[corrected_name] = value # <--- Vulnerable line: direct assignment of header value to environ return environ ...
The code iterates through the headers in the ASGI scope. When it encounters a header named "content-length" or "content-type", it directly assigns the header's value to the corresponding
CONTENT_LENGTH
orCONTENT_TYPE
key in theenviron
dictionary. There is no validation or sanitization of thevalue
before assignment. This allows an attacker to inject arbitrary values for these critical environment variables. -
Security test case:
- Set up a simple WSGI application that reads and prints the
CONTENT_LENGTH
environment variable.# test_wsgi_app.py def application(environ, start_response): content_length = environ.get('CONTENT_LENGTH', 'Not Set') status = '200 OK' headers = [('Content-type', 'text/plain')] start_response(status, headers) return [f"Content-Length: {content_length}".encode()]
- Wrap this WSGI application with
WsgiToAsgi
.from asgiref.wsgi import WsgiToAsgi from test_wsgi_app import application asgi_app = WsgiToAsgi(application)
- Use
ApplicationCommunicator
to send a crafted HTTP request with a maliciousContent-Length
header.import asyncio from asgiref.testing import ApplicationCommunicator from asgi_wrapper import asgi_app # Assuming the wrapper from step 2 is in asgi_wrapper.py async def test_header_injection(): instance = ApplicationCommunicator( asgi_app, { "type": "http", "http_version": "1.0", "method": "GET", "path": "/", "query_string": b"", "headers": [ [b"Content-Length", b"999999"] # Malicious Content-Length header ], }, ) await instance.send_input({"type": "http.request"}) response_start = await instance.receive_output(1) response_body = await instance.receive_output(1) decoded_body = response_body['body'].decode() assert "Content-Length: 999999" in decoded_body # Verify injected value is present in WSGI app's output print(f"WSGI App Output: {decoded_body}") asyncio.run(test_header_injection())
- Run the test case. Observe that the WSGI application's output shows
Content-Length: 999999
, demonstrating that the attacker-providedContent-Length
header was successfully injected into the WSGI environment.
- Set up a simple WSGI application that reads and prints the
-
Description: The test server (implemented in the
Server
class in the filetests/test_server.py
) listens for UDP messages and processes them based solely on plaintext command prefixes (e.g. “Register” and “To”). No authentication, authorization, or input validation is performed on the incoming data. An attacker who can reach the server’s UDP port can craft UDP packets that register arbitrary user names or inject messages into an application instance. Step-by-step triggering:- Find the UDP port on which the server is listening (note: by default the server binds to 127.0.0.1, but if the binding is misconfigured to 0.0.0.0 or is otherwise exposed by the deployment, the UDP port becomes reachable from external sources).
- Using a UDP client or tool (for example, netcat in UDP mode), send a packet with the payload:
Register victimUser
This packet causes the server to create (or reinitialize) an application instance for the username “victimUser”. - Next, send another UDP packet with the payload:
To victimUser UnauthorizedMessage
The server splits the command and places the message on the input queue for the “victimUser” application instance—even though the sender is not an authenticated client.
-
Impact: An attacker exploiting this vulnerability can impersonate legitimate clients or inject arbitrary messages into the application state. This can lead to unauthorized manipulation of the system’s behavior (for example, triggering actions on behalf of another user), potential information leakage, and disruption of the expected communication flow. In a production setup where such a UDP server might be deployed on an externally accessible interface, the impact could be severe.
-
Vulnerability Rank: Critical
-
Currently Implemented Mitigations:
- In the provided test code the server binds to
"127.0.0.1"
, which restricts access to the local machine. - The code assumes a trusted testing environment and does not expect messages from untrusted external sources.
- In the provided test code the server binds to
-
Missing Mitigations:
- No authentication or authorization mechanism is in place to verify the sender’s identity.
- There is no input validation or integrity checking on the received UDP messages.
- No enforcement of a secure binding (for example, ensuring the UDP socket is not exposed on public interfaces) is implemented.
-
Preconditions:
- The UDP server must be deployed so that its bound port is accessible from external networks (e.g. if misconfigured to bind on 0.0.0.0).
- The attacker must have network access to the server’s UDP port and be capable of sending spoofed UDP packets.
-
Source Code Analysis:
- In
tests/test_server.py
, theServer
class’s initializer creates a UDP socket with nonblocking mode and binds it to("127.0.0.1", 0)
. - The
handle
method usesawait sock_recvfrom(self._sock, 4096)
to receive data and immediately decodes it from UTF-8 without further sanitation. - The code then checks whether the decoded data starts with
"Register"
or"To"
. In each case, it splits the string by spaces and uses the provided username as the key to get or create an application instance viaget_or_create_application_instance(usr_name, addr)
. - Because there is no mechanism to verify that the sender is truly the legitimate owner of the username or that the message conforms to an expected format (other than a simple prefix check), an attacker can easily forge messages that manipulate the server’s internal state.
- In
-
Security Test Case:
- Deployment: Configure and deploy the UDP server in a controlled test environment such that its UDP port is bound to an externally reachable interface (for example, using 0.0.0.0 instead of 127.0.0.1).
- Registration Injection:
- Use a UDP client (e.g., netcat in UDP mode) to send the following packet to the server’s IP and port:
Register victimUser
- Verify (for example, by monitoring logs or the behavior of a client session) that an application instance for “victimUser” was created and that the server associates the instance with the sender’s IP address rather than a trusted client.
- Use a UDP client (e.g., netcat in UDP mode) to send the following packet to the server’s IP and port:
- Message Injection:
- Next, send a UDP packet with the payload:
To victimUser UnauthorizedMessage
- Confirm that the application instance for “victimUser” receives the message “UnauthorizedMessage” without any authentication or further validation.
- This demonstrates that an attacker can inject messages or potentially hijack communications.
- Next, send a UDP packet with the payload:
- Assessment:
- Record that the lack of authentication and input validation allows arbitrary message injection, validating the critical severity of the vulnerability.
Implementing robust authentication, input validation, and ensuring that the server binds only to secure interfaces (or is otherwise protected by a firewall) are critical to mitigating this vulnerability if the UDP server code were ever used in a publicly available context.