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·22 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

•26 minutes ago•CVE-2026-67435
6.0

CVE-2026-67435: Custom Authentication Header Leakage via Cross-Origin Redirects in linuxfabrik-lib

CVE-2026-67435 is a security vulnerability in the linuxfabrik-lib Python library prior to version 6.0.0. When performing HTTP requests with follow_redirects enabled, custom authentication headers (such as X-Auth-Token or X-Api-Key) are forwarded during cross-origin redirects. A malicious or compromised server can leverage this behavior to capture sensitive monitoring and administrative credentials, leading to potential unauthorized access and Server-Side Request Forgery (SSRF).

Amit Schendel
Amit Schendel
2 views•6 min read
•about 1 hour ago•CVE-2026-67429
10.0

CVE-2026-67429: Arbitrary File Write and Path Traversal in Flyto2 Core Modules

CVE-2026-67429 is a critical path traversal vulnerability in Flyto2 Core file-writing modules, including image.download and twelve other modules. By exploiting an insecure validation check that relied on user-controlled parameters, unauthenticated remote attackers can bypass directory confinement and write arbitrary files to the file system, leading to remote code execution.

Alon Barad
Alon Barad
3 views•6 min read
•about 2 hours ago•CVE-2026-67427
8.6

CVE-2026-67427: Host Environment Variable Access Policy Bypass via Template Interpolation in Flyto2 Core

CVE-2026-67427 is a capability bypass vulnerability in the Flyto2 Core workflow execution kernel. Due to a logical inconsistency in how dynamic parameters are resolved, the system evaluates environment variables via template interpolation prior to executing capability filter validation. This permits unprivileged workflow definitions to completely bypass denylist restrictions on the `env.get` module, exfiltrating critical host configurations, API tokens, and credentials via allowed communication channels.

Amit Schendel
Amit Schendel
5 views•5 min read
•about 3 hours ago•CVE-2026-67425
8.6

CVE-2026-67425: Insecure Credential Forwarding in Flyto2 Core

An insecure credential forwarding vulnerability in Flyto2 Core prior to version 2.26.6 allows attackers to exfiltrate operator API keys. This occurs because the system forwards environment-derived API keys to user-controlled custom endpoints, bypassing SSRF guards designed only for private target validation.

Amit Schendel
Amit Schendel
5 views•6 min read
•about 4 hours ago•CVE-2025-4318
9.0

CVE-2025-4318: Remote Code Execution in AWS Amplify codegen-ui

A critical remote code execution (RCE) vulnerability exists in AWS Amplify Studio's code-generation library (@aws-amplify/codegen-ui). An authenticated attacker with permissions to create or modify component schemas can inject malicious JavaScript code into those schemas. When the Amplify CLI or the build environment processes these schemas, the unvalidated expressions are executed within the host Node.js environment, leading to full system compromise.

Alon Barad
Alon Barad
8 views•5 min read
•about 5 hours ago•CVE-2026-67426
9.3

CVE-2026-67426: Unauthenticated Remote Code Execution and Secret Exfiltration in Flyto2 Core

CVE-2026-67426 is a critical vulnerability in Flyto2 Core prior to version 2.26.7. The standalone flyto-verification service binds to all interfaces (0.0.0.0) on port 8344 and exposes an unauthenticated POST /run endpoint. This endpoint accepts an arbitrary client-controlled callback URL and makes an outbound POST request containing the sensitive internal runner secret in the headers. Attackers can exploit this to retrieve the FLYTO_RUNNER_SECRET and perform Server-Side Request Forgery (SSRF) against internal network targets.

Amit Schendel
Amit Schendel
6 views•6 min read