CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-PW6J-QG29-8W7F

GHSA-pw6j-qg29-8w7f: State Persistence and Sensitive Credential Leakage in Tornado CurlAsyncHTTPClient

Amit Schendel
Amit Schendel
Senior Security Researcher

Jun 16, 2026·7 min read·16 visits

Executive Summary (TL;DR)

Tornado's CurlAsyncHTTPClient reuses pycurl handles without resetting configuration state, leading to client certificate and proxy credential leakage to unintended destinations.

A state persistence vulnerability exists in Tornado's CurlAsyncHTTPClient component where pooled pycurl.Curl handles are reused across asynchronous requests without a complete state reset. Consequently, sensitive per-request configurations, such as client TLS certificates or proxy basic authentication credentials, persist on the shared handle. This behavior leads to subsequent requests leaking these credentials to unauthorized remote servers.

Vulnerability Overview

The Tornado web framework provides multiple backends for handling asynchronous HTTP requests. The CurlAsyncHTTPClient is an advanced backend designed as a wrapper around pycurl, the Python bindings for the C-based libcurl library. This backend is frequently selected in performance-critical environments because of its speed, multi-socket scheduling capabilities, and support for complex network topologies. To achieve high request throughput, CurlAsyncHTTPClient maintains a internal pool of pycurl.Curl easy handles that are checked out of an idle queue, configured for a specific request, and then checked back into the queue upon execution completion.

However, this optimization creates a significant attack surface if security states are not strictly isolated between consecutive execution threads. The client fails to wipe the internal configuration history of these reusable easy handles. When a handle is returned to the free list, any configuration set during the lifetime of the previous request remains active unless explicitly overwritten. Consequently, a request designed with strict security parameters (such as client-side certificates or proxy credentials) will unintentionally pass those configuration values down to any subsequent request scheduled on the same handle.

This structural logic flaw results in two distinct data leakage vectors. The first vector leaks client-side TLS certificates (configured via SSLCERT and SSLKEY) to arbitrary public servers. The second vector leaks proxy authentication credentials to unauthorized intermediate proxy servers. This vulnerability exposes organizations using mutual TLS (mTLS) or credentialed proxy configurations to unauthorized credential harvesting and identity impersonation.

Root Cause Analysis

The fundamental driver of this vulnerability is the state retention model used by the underlying libcurl library. In libcurl, when an option is applied to an easy handle via curl_easy_setopt (wrapped by Python's curl.setopt()), the setting persists on that handle indefinitely. The setting remains active until it is overridden by another setopt call, cleared using curl_easy_unsetopt, or wiped using curl_easy_reset (wrapped by curl.reset()). Tornado's CurlAsyncHTTPClient does not reset handles between operations, opting instead to configure options dynamically on a per-request basis in the _curl_setup_request method.

This design operates on the assumption that _curl_setup_request will comprehensively configure or clear every parameter. This assumption is incorrect. In tornado/curl_httpclient.py (v6.5.6 and earlier), the setup routine implements multiple conditional checks that apply options only when a specific configuration is active, lacking corresponding else branches to clear those parameters when they are absent in subsequent requests.

For example, during mTLS requests, SSLCERT and SSLKEY parameters are bound to the pycurl.Curl instance. If a subsequent request that does not specify client certificates is allocated the same handle, the configuration block is skipped, allowing the previously bound paths to persist. During proxy operations, if the client establishes a request using an authenticated proxy (configuring PROXYUSERPWD) and then issues a subsequent request through an unauthenticated proxy, the code updates the proxy host and port but bypasses the credential update block. Because the unsetting logic is only reachable when proxying is disabled entirely, the previous credentials remain bound and are transmitted to the new proxy server.

Code-Level Flaw Analysis

The vulnerable logic exists in tornado/curl_httpclient.py inside the _curl_setup_request method. The following block displays how client certificates are configured conditionally without cleanup branches:

# Vulnerable code in tornado/curl_httpclient.py (v6.5.6)
if request.client_cert is not None:
    curl.setopt(pycurl.SSLCERT, request.client_cert)
 
if request.client_key is not None:
    curl.setopt(pycurl.SSLKEY, request.client_key)

Because there are no corresponding else conditions, a handle that has request.client_cert configured will continue to hold that reference on all subsequent requests where request.client_cert is None. A similar issue affects proxy credential management:

# Vulnerable proxy credentials logic
if request.proxy_host and request.proxy_port:
    curl.setopt(pycurl.PROXY, request.proxy_host)
    curl.setopt(pycurl.PROXYPORT, request.proxy_port)
    if request.proxy_username:
        assert request.proxy_password is not None
        credentials = httputil.encode_username_password(
            request.proxy_username, request.proxy_password
        )
        curl.setopt(pycurl.PROXYUSERPWD, credentials)
    # Missing 'else' branch to clear PROXYUSERPWD when proxy_username is None
else:
    try:
        curl.unsetopt(pycurl.PROXY)
    except TypeError:
        curl.setopt(pycurl.PROXY, "")
    curl.unsetopt(pycurl.PROXYUSERPWD)

In this block, if request.proxy_host remains true but request.proxy_username is omitted, the code does not reach the outer else block containing curl.unsetopt(pycurl.PROXYUSERPWD). Consequently, the credentials from the prior proxy configuration are reused.

The security patches in Tornado version 6.5.7 resolve these issues by implementing systematic unsetting logic. When optional parameters are omitted from a request, the framework explicitly executes curl.unsetopt() to clear the active state of the handle before execution.

Exploitation and Attack Methodology

Exploiting this vulnerability does not require complex payload construction. It relies instead on scheduling behavior and pool reuse. An attacker does not need direct access to the application's memory or network flow to trigger the leak. Instead, the application itself initiates the leakage when executing sequential requests on behalf of users.

In a multi-tenant or multi-destination environment, an application using CurlAsyncHTTPClient might first process an internal request (Request A) that requires mutual TLS authentication to access a restricted backend service. Once completed, the handle is returned to the pool. When a user subsequently triggers a request (Request B) to an external, untrusted, or attacker-controlled server, the backend scheduler may assign the same handle. Because the handle retains the SSLCERT and SSLKEY parameters, the outgoing connection to the attacker-controlled server will execute an mTLS handshake, automatically presenting the client certificate to the external target.

In proxy scenarios, the process follows a similar flow. An application routes administrative or premium traffic through an authenticated corporate proxy using a high-privilege credential. When the application subsequently routes a standard user request through an unauthenticated public proxy, the active handle retains the Proxy-Authorization header value. The unauthorized proxy captures the header during connection establishment, obtaining the base64-encoded credentials of the primary corporate proxy.

Impact Assessment

The impact of credential leakage is classified as Medium (CVSS 5.9). Although the base CVSS score is moderate due to high attack complexity, the actual consequences in enterprise deployments can be severe.

In modern service architectures, client TLS certificates are frequently used as a primary authentication factor to access protected APIs, internal administrative portals, or sensitive databases. If these certificates are leaked to external servers, an attacker can capture the certificate chain. Depending on the configuration of the certificate authority and the target services, this exposure can allow the attacker to authenticate as the client, leading to unauthorized data access.

Furthermore, client certificates frequently contain metadata within their Subject Common Name (CN) or Alternative Names, such as internal server names, IP addresses, or domain structures. Access to this metadata allows an attacker to map internal network layouts. Similarly, leaked proxy credentials can allow unauthorized users to tunnel traffic through enterprise proxy servers, bypassing access controls and incurring significant routing fees.

Remediation and Defensive Strategies

The primary remediation strategy is upgrading the Tornado installation to version 6.5.7 or later. The update implements code changes that explicitly clear unused parameters during request setup, preventing state persistence across requests.

If upgrading is not immediately possible, you can implement several workarounds to mitigate exposure. The first workaround is switching the application's HTTP client backend from CurlAsyncHTTPClient to Tornado's native python-based client, SimpleAsyncHTTPClient. Because the native client does not use libcurl or pool persistent native handles, it is entirely unaffected by this state leakage flaw.

# Configure Tornado to use the safe native client backend
from tornado.httpclient import AsyncHTTPClient
AsyncHTTPClient.configure("tornado.simple_httpclient.SimpleAsyncHTTPClient")

If your application requires the CurlAsyncHTTPClient for advanced networking features, you can mitigate the risk by isolating client instances based on security context. Instead of using a single global client, instantiate separate client pools for different classes of requests. For example, use one dedicated client instance exclusively for mTLS connections, another for authenticated proxy connections, and a third for standard outbound requests. This isolation ensures that a recycled handle is never reused across different security boundaries.

Technical Appendix

CVSS Score
5.9/ 10
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N

Affected Systems

Tornado Web Framework (CurlAsyncHTTPClient)

Affected Versions Detail

Product
Affected Versions
Fixed Version
tornado
Tornado
<= 6.5.66.5.7
AttributeDetail
CWE IDCWE-200, CWE-672
Attack VectorNetwork (AV:N)
Attack ComplexityHigh (AC:H)
CVSS Score5.9 (Medium)
Exploit StatusPoC (Proof of Concept) Available
KEV StatusNot Listed

MITRE ATT&CK Mapping

T1552Unsecured Credentials
Credential Access
T1552.004Private Keys
Credential Access
T1083File and Directory Discovery
Discovery
CWE-200
Exposure of Sensitive Information to an Unauthorized Actor

The program exposes sensitive information to an actor that is not authorized to have access to that information.

Vulnerability Timeline

Vulnerability details coordinated and published under GHSA-PW6J-QG29-8W7F.
2026-06-15
Official repository security advisory and patch released in Tornado version 6.5.7.
2026-06-15
Public release of Proof of Concept scripts demonstrating credential leakage.
2026-06-15

References & Sources

  • [1]GitHub Security Advisory GHSA-pw6j-qg29-8w7f
  • [2]Tornado Security Advisory
  • [3]Affected Source File (v6.5.6)

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•1 day ago•CVE-2026-54068
5.9

CVE-2026-54068: Unauthenticated Server-Side Template Injection and SQLite Exfiltration in SiYuan PKM

An authentication bypass in the SiYuan personal knowledge management system before version 3.7.0 exposes a dynamic icon rendering endpoint. This endpoint processes client-supplied Go template directives. By submitting a crafted request, an unauthenticated remote attacker can leverage registered database template functions to execute arbitrary read-only SQL queries and exfiltrate workspace contents.

Amit Schendel
Amit Schendel
12 views•5 min read
•1 day ago•CVE-2026-54069
9.1

CVE-2026-54069: Authentication Bypass in SiYuan Note via Origin Header Spoofing

CVE-2026-54069 is a critical authentication bypass vulnerability in the SiYuan Note personal knowledge management system. The flaw is located in the HTTP server's middleware handling API authorization, which unconditionally trusts requests carrying a 'chrome-extension://' scheme in the Origin HTTP header, granting administrative access without validating API tokens.

Alon Barad
Alon Barad
10 views•5 min read
•2 days ago•CVE-2026-54089
9.1

CVE-2026-54089: Authentication Bypass by Spoofing in File Browser

CVE-2026-54089 is a critical authentication bypass vulnerability in File Browser affecting instances configured with proxy-based authentication. An unauthenticated remote attacker with direct network access can impersonate arbitrary users or register new accounts by spoofing configured HTTP headers.

Amit Schendel
Amit Schendel
8 views•7 min read
•2 days ago•GHSA-99J7-FHR2-XFJ4
10.0

GHSA-99J7-FHR2-XFJ4: Malicious Remote Code Execution Payload in 'exploration' Cargo Crate

The malicious Cargo package 'exploration' was uploaded to the crates.io registry. During compilation or package import, the crate executes code designed to establish an outbound TCP/HTTP connection, download an external second-stage binary, and execute the binary locally on the host machine. This creates an unauthenticated remote code execution vector impacting developer environments and continuous integration pipelines.

Amit Schendel
Amit Schendel
11 views•6 min read
•2 days ago•CVE-2026-54088
9.3

CVE-2026-54088: Pre-Authentication Remote Code Execution in File Browser Hook Authentication

CVE-2026-54088 is a critical command injection vulnerability in File Browser prior to version 2.63.6. When Hook Authentication is enabled, the application interpolates unsanitized credentials into a shell command, allowing unauthenticated remote code execution.

Alon Barad
Alon Barad
9 views•6 min read
•2 days ago•GHSA-QV4M-M73M-8HJ7
8.8

GHSA-qv4m-m73m-8hj7: Authenticated Arbitrary File Upload leading to Remote Code Execution in NotrinosERP

An authenticated remote code execution vulnerability exists in NotrinosERP (versions up to and including 1.0.0) within the Human Resource Management (HRM) module. Users with employee management permissions can upload arbitrary file types, including PHP scripts, which are written directly to a web-accessible directory. This allows for arbitrary code execution in the context of the web-server user.

Alon Barad
Alon Barad
8 views•6 min read