← Back to Feed CACHED · 2026-10-08 21:17:28 · CACHE_KEY CVE-2026-74469
CVE-2026-74469 · CWE-190 · Disclosed 2026-08-15

Linux kernel SCTP peer transport 16-bit counter overflow leading to OOB write in sctp_diag (DiagSpill)

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

Like a parking garage counter that rolls over to zero and lets the next car smash through the gate into the basement

CVE-2026-74469, nicknamed DiagSpill, is an integer-overflow-to-out-of-bounds-write in the Linux kernel's SCTP subsystem. The function sctp_assoc_add_peer() tracks peer transports in a 16-bit transport_count field. When the 65,536th unique peer is added, the counter wraps to zero. A subsequent sctp_diag diagnostic dump (triggered by ss -S or any Netlink SOCK_DIAG request) trusts that wrapped value to size its response buffer, then copies the full transport list — roughly 8 MiB of peer addresses — past the end of the allocated skb, corrupting adjacent kernel memory. The bug was introduced in kernel 4.7 (commit 8f840e47f190) and affects every mainline kernel through the fix commit bd0e9289e264. Fixed stable releases include 5.10.265, 5.15.216, 6.1.183, 6.6.151, 6.12.103, 6.18.44, 7.1.8, and 7.2-rc6. All RHEL versions 6 through 10 are affected.

The vendor-assigned CVSS 8.8 with AV:N overstates the realistic attack surface. The network vector assumes the remote ASCONF/ADD-IP path, which requires net.sctp.addip_enable=1 and either SCTP-AUTH or net.sctp.addip_noauth_enable=1 — both off by default on every major distribution. The practical exploit path is local: an unprivileged user creates an SCTP socket (auto-loading the module on permissive distros), accumulates 65,536 transports, and triggers a diag dump. The resulting 8 MiB heap overwrite is weaponizable for local privilege escalation to root, as demonstrated by two public PoC repositories. A realistic CVSS vector is AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H → 7.8. The severity label remains HIGH, but the score drops by a full point because the network preconditions almost never exist in production.

"Kernel LPE via SCTP counter wrap; vendor AV:N overstates remote reach but local root is real"
02 · The Attack Path

5 steps from start to impact.

STEP 01

Attacker obtains local shell

The attacker has unprivileged local access to a Linux host — via SSH, container breakout staging, compromised application, or insider access. No root, no capabilities, no user-namespace tricks are needed. This is the baseline position for any local privilege escalation chain.
Conditions required:
  • Local unprivileged shell on a Linux host running a vulnerable kernel (4.7 – pre-fix)
Where this breaks in practice:
  • Requires prior access — this is a post-initial-access technique, not an entry vector
Detection/coverage: Standard host-based auth logging (sshd, PAM, auditd) covers the entry event.
STEP 02

SCTP module auto-loads

The attacker opens an AF_INET, SOCK_STREAM, IPPROTO_SCTP socket. On distributions that allow unprivileged module auto-loading (many Ubuntu, Debian, Fedora, and older RHEL configs), the kernel loads sctp.ko on demand. On RHEL 8+ and hardened hosts with install sctp /bin/false in /etc/modprobe.d/, this step fails and the chain is dead.
Conditions required:
  • SCTP kernel module not blacklisted or already loaded
  • Kernel config includes CONFIG_IP_SCTP=m (default on most distro kernels)
Where this breaks in practice:
  • RHEL 8+ blacklists SCTP by default via sctp-blacklist.conf
  • Hardened CIS/STIG builds explicitly block SCTP auto-load
  • Container runtimes may restrict socket family creation via seccomp
Detection/coverage: Module-load audit events (-w /etc/modprobe.d/ -p wa), or auditctl -a always,exit -F arch=b64 -S init_module -S finit_module.
STEP 03

Create 65,536 peer transports

The attacker's PoC (e.g., 0xBlackash/CVE-2026-74469 poc.c) opens an SCTP association and iterates through addresses to add 65,536 unique peer transports to a single association. This wraps the 16-bit transport_count to zero. The operation is I/O-intensive and takes measurable time (seconds to low minutes), generating significant network-stack activity.
Conditions required:
  • Sufficient memory and address space to hold 65,536 transport entries (~8 MiB of kernel structures)
  • No ulimit or cgroup memory cap that kills the process before completion
Where this breaks in practice:
  • Creating 65K transports is noisy and detectable by kernel memory-pressure alerts
  • Some container memory cgroups will OOM-kill the process before the wrap
Detection/coverage: Abnormal SCTP association sizes visible via ss -S or custom eBPF probes on sctp_assoc_add_peer. Spike in kernel slab allocations for sctp_transport objects.
STEP 04

Trigger sctp_diag dump

The attacker triggers a Netlink SOCK_DIAG request for SCTP sockets (equivalent to running ss -S). The sctp_diag module auto-loads if not already present. The diagnostic handler reads the wrapped transport_count (now 0), allocates a near-zero-length payload in the response skb, then copies all 65,536 transport addresses — approximately 8 MiB — past the buffer's tail pointer, causing a massive out-of-bounds heap write.
Conditions required:
  • sctp_diag module loadable or already loaded
  • Netlink SOCK_DIAG accessible to unprivileged users (default on most kernels)
Where this breaks in practice:
  • If sctp_diag is also blacklisted, the dump cannot execute
Detection/coverage: Kernel oops/panic in sctp_diag_dump is the most common detection signal. KASAN-enabled kernels will report the OOB write immediately.
STEP 05

Kernel memory corruption → LPE

The 8 MiB overwrite corrupts adjacent slab objects and page-allocator metadata. Public PoCs from 0xBlackash and HORKimhab demonstrate leveraging this corruption for local privilege escalation under specific heap-layout conditions. The attacker gains a root shell. Reliability depends on kernel version, KASLR, SMAP/SMEP, and heap-grooming success — reported as environment-dependent but achievable with tuning.
Conditions required:
  • Heap layout must be groomed for reliable exploitation (vs. simple kernel panic)
  • KASLR/SMAP/SMEP increase difficulty but do not prevent exploitation
Where this breaks in practice:
  • Unreliable on hardened kernels with full KASAN, CFI, or page-table isolation
  • Kernel panic is the more common outcome than clean LPE on first attempt
  • SELinux/AppArmor in enforcing mode may block post-exploitation pivots
Detection/coverage: Kernel crash dump analysis, dmesg BUG/OOPS messages, EDR agents monitoring for unexpected root transitions from unprivileged processes.
03 · Compensating Control

1
HIGH 7.8→IGNORE 0.0
SEVERITY REDUCED
Blacklist the SCTP kernel module — Add install sctp /bin/false and install sctp_diag /bin/false to /etc/modprobe.d/nosctp.conf, then run update-initramfs -u (Debian/Ubuntu) or dracut -f (RHEL/Fedora). This kills the attack chain at step 2 — without the SCTP module, no association can be created and no transport counter can overflow. Deploy within 30 days per the noisgate mitigation SLA for HIGH. If SCTP is in active use (telecom, SIGTRAN, Diameter), this control is not applicable — proceed directly to patching.
2
HIGH 7.8→IGNORE 0.0
SEVERITY REDUCED
Apply vendor kernel patches — Update to a fixed kernel release (≥5.10.265, 5.15.216, 6.1.183, 6.6.151, 6.12.103, 6.18.44, 7.1.8). For RHEL, apply RHSA-2026:71687 or RHSA-2026:71565. For Debian, apply DSA-6466-1. This is the definitive fix. Deploy within 180 days per the noisgate remediation SLA for HIGH. Prioritize hosts where SCTP is not blacklisted.
3
HIGH 7.8→MEDIUM 5.5
SEVERITY REDUCED
Restrict SCTP socket creation via seccomp — For containerized workloads, ensure the container runtime's seccomp profile blocks socket(AF_INET, *, IPPROTO_SCTP). Docker's default seccomp profile does NOT block this — you must add an explicit rule. Kubernetes Pod Security Standards at restricted level do not cover SCTP socket creation either. This prevents container-to-host escalation via DiagSpill. Deploy within 30 days.
4
HIGH 7.8→MEDIUM 5.3
SEVERITY REDUCED
Deploy KASAN or slab-hardening on critical hosts — On hypervisors and k8s control-plane nodes, enable CONFIG_KASAN=y or use slab_nomerge and init_on_alloc=1 boot parameters. These raise the bar for reliable heap exploitation from the 8 MiB overwrite — the attacker gets a kernel panic instead of a clean root shell. This converts RCE/LPE risk to DoS risk. Deploy within 30 days.
What doesn't work
  • Disabling unprivileged user namespaces — Red Hat explicitly notes this does NOT mitigate DiagSpill, unlike the other three CVEs in the quartet. DiagSpill requires no namespace manipulation.
  • Network segmentation / firewall rules — The primary attack path is local, not network-based. Blocking SCTP at the firewall only addresses the already-unlikely remote ASCONF path.
  • SELinux / AppArmor in enforcing mode — These MAC systems restrict post-exploitation actions but do not prevent the kernel memory corruption itself. The OOB write happens in kernel context before any LSM hook can intervene.
  • ASLR / KASLR alone — Address randomization increases exploitation difficulty but does not prevent the 8 MiB overwrite. The corruption primitive is large enough to be weaponized probabilistically even with full KASLR.
04 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNo confirmed exploitation in the wild. Not listed in CISA KEV. No GreyNoise or Shadowserver tags observed for this CVE as of 2026-10-09. The vuln is part of a disclosure quartet (DirtyAH6, PPPoEject, TUNderflow, DiagSpill) that drew CISA attention for the other three — DiagSpill was notably absent from KEV.
Proof-of-concept availabilityTwo public PoC repositories: 0xBlackash/CVE-2026-74469 (C, poc.c) and HORKimhab/CVE-2026-74469 (DiagSpill-specific). Both indexed on Sploitus. PoCs demonstrate kernel crash and local-root under specific heap conditions.
EPSS0.01083 (≈1.08%) — low exploitation probability. Reflects the local-access requirement and SCTP module dependency that narrow the attacker population.
KEV statusNot listed as of 2026-10-09. Three sibling CVEs from the same disclosure (CVE-2026-80844, CVE-2026-81000, CVE-2026-68121) were added to KEV; DiagSpill was not, likely due to the SCTP module prerequisite.
CVSS vectorVendor: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H (8.8). noisgate-adjusted: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H (7.8). The AV:N assumes remote ASCONF path, which requires non-default options (addip_enable, addip_noauth_enable). Realistic vector is AV:L.
Affected versionsLinux kernel 4.7 through pre-fix mainline. Introduced by commit 8f840e47f190. All RHEL 6–10 affected. Debian Bookworm < 6.1.187, Trixie < 6.12.111.
Fixed versionsStable: 5.10.265, 5.15.216, 6.1.183, 6.6.151, 6.12.103, 6.18.44, 7.1.8, 7.2-rc6. Upstream fix: commit bd0e9289e264. Debian: DSA-6466-1, DLA-4777-1, DLA-4788-1. RHEL: RHSA-2026:71687, RHSA-2026:71565.
Scanning / exposureNot remotely scannable in default configurations. SCTP exposure is minimal on internet-facing hosts — Shodan shows <50,000 hosts with SCTP services globally, a tiny fraction of the Linux installed base. The local-access requirement makes network scanning irrelevant for the primary attack path.
Disclosure timelineDisclosed 2026-08-15 via linux-cve-announce. Public PoCs appeared 2026-09-18 alongside the DirtyAH6/PPPoEject/TUNderflow quartet disclosure on oss-security. ~34 days from disclosure to weaponized PoC.
Researcher / attributionDisclosed through the Linux kernel CVE process. PoC authors: 0xBlackash and HORKimhab (GitHub). Part of the "Linux local-root quartet" research published on oss-security.

Sources.

  1. Red Hat Security Bulletin RHSB-2026-011
  2. Debian Security Tracker — CVE-2026-74469
  3. 0xBlackash PoC — GitHub
  4. HORKimhab DiagSpill PoC — GitHub
  5. Linux local-root quartet disclosure analysis
  6. CISA flags three Linux kernel CVEs (sibling disclosure)
  7. Red Hat CVE page — CVE-2026-74469
  8. CONFIG_INET_SCTP_DIAG kernel config reference
05 · The Call

Final Verdict
= UNCHANGED to HIGH (7.8/10)

Why this verdict

  • AV:N → AV:L adjustment (−1.0 score): The vendor CVSS assumes AV:N via the remote ASCONF/ADD-IP SCTP path. This path requires net.sctp.addip_enable=1 AND either SCTP-AUTH or net.sctp.addip_noauth_enable=1 — both disabled by default on every major distribution. The realistic attack vector is local.
  • SCTP module availability narrows population: RHEL 8+ blacklists SCTP by default. CIS/STIG benchmarks for all distros recommend blacklisting. On permissive distros (stock Ubuntu, Debian, Fedora), unprivileged auto-load is possible, but hardened enterprise builds typically block it. Estimated reachable population: 40–60% of enterprise Linux hosts.
  • Local access prerequisite implies post-initial-access: The attacker must already have an unprivileged shell. This is an escalation technique, not an entry vector. Every compensating control for initial access (MFA, SSH hardening, endpoint protection) reduces the population that reaches this step.
  • Public PoC with LPE capability elevates above MEDIUM: Two GitHub repositories demonstrate kernel crash and environment-dependent root escalation. The 8 MiB overwrite is a powerful primitive. Even without 100% reliable LPE, the DoS (kernel panic) impact alone is significant on production hosts.
  • Role multiplier: The Linux kernel spans all deployment roles. (a) *Workstations/dev boxes*: LPE yields root on one host — bounded blast radius. (b) *Application servers*: root access enables lateral movement, data exfiltration — host-scale impact. (c) *KVM hypervisors / Kubernetes nodes*: if SCTP auto-loads (possible on stock Ubuntu/Debian node images), LPE on the host = VM escape / container escape = fleet-scale impact. (d) *Samba AD DCs on Linux*: root = domain compromise. The affected component IS the kernel — canonically high-value — but the SCTP module gate means only a subset of high-value-role hosts are reachable. The floor is HIGH because the chain succeeds on ≥1% of high-value-role deployments (KVM/k8s nodes on non-RHEL distros). Not CRITICAL because the SCTP module dependency prevents universal reachability across the installed base, and the primary path requires local access.

Why not higher?

A CRITICAL rating would require either confirmed in-the-wild exploitation, universal reachability without prerequisites, or a remote unauthenticated attack path. DiagSpill fails all three: it is not KEV-listed, it requires the SCTP module (blacklisted on RHEL 8+ and hardened builds), and the remote path depends on non-default ASCONF options that essentially never exist in production. The LPE reliability is also environment-dependent, with kernel panic being the more common outcome than clean root on first attempt.

Why not lower?

A MEDIUM rating would underweight the kernel-level impact. The 8 MiB OOB write is an exceptionally powerful corruption primitive — it is not a narrow single-byte off-by-one. Public PoCs exist and demonstrate root under specific conditions. The SCTP module auto-loads on stock Ubuntu, Debian, and Fedora, which collectively represent a significant share of enterprise Linux. Any host where the chain succeeds yields root with no capabilities or namespaces required, and the deployment-role floor (KVM, k8s) keeps this firmly at HIGH.

06 · Verification

Crowdsourced verification payload.

Run this script on each target Linux host as any user (no root required for version checks; root recommended for module-status checks). Invoke with: chmod +x diagspill_check.sh && sudo ./diagspill_check.sh. The script checks the running kernel version against known fixed releases and verifies SCTP module availability.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/bin/bash
# diagspill_check.sh — CVE-2026-74469 (DiagSpill) detection
# Checks: (1) kernel version against fixed releases, (2) SCTP module status
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

set -euo pipefail

RESULT="UNKNOWN"
KVER=$(uname -r)
KMAJOR=$(echo "$KVER" | cut -d. -f1)
KMINOR=$(echo "$KVER" | cut -d. -f2)
KPATCH=$(echo "$KVER" | cut -d. -f3 | cut -d- -f1)

echo "[*] CVE-2026-74469 (DiagSpill) check"
echo "[*] Running kernel: $KVER"

# Fixed versions: 5.10.265, 5.15.216, 6.1.183, 6.6.151, 6.12.103, 6.18.44, 7.1.8, 7.2+
version_gte() {
  # Returns 0 if $1.$2.$3 >= $4.$5.$6
  local a1=$1 a2=$2 a3=$3 b1=$4 b2=$5 b3=$6
  if [ "$a1" -gt "$b1" ] 2>/dev/null; then return 0; fi
  if [ "$a1" -lt "$b1" ] 2>/dev/null; then return 1; fi
  if [ "$a2" -gt "$b2" ] 2>/dev/null; then return 0; fi
  if [ "$a2" -lt "$b2" ] 2>/dev/null; then return 1; fi
  if [ "$a3" -ge "$b3" ] 2>/dev/null; then return 0; fi
  return 1
}

check_version() {
  # Kernel < 4.7 is not affected (bug introduced in 4.7)
  if [ "$KMAJOR" -lt 4 ] 2>/dev/null; then
    echo "[+] Kernel predates vulnerable code (introduced in 4.7)"
    RESULT="PATCHED"; return
  fi
  if [ "$KMAJOR" -eq 4 ] && [ "$KMINOR" -lt 7 ] 2>/dev/null; then
    echo "[+] Kernel predates vulnerable code (introduced in 4.7)"
    RESULT="PATCHED"; return
  fi

  # Check against fixed stable branches
  if [ "$KMAJOR" -eq 5 ] && [ "$KMINOR" -eq 10 ]; then
    if version_gte $KMAJOR $KMINOR $KPATCH 5 10 265; then
      RESULT="PATCHED"; echo "[+] Fixed in 5.10.265, running $KVER"; return
    fi
  elif [ "$KMAJOR" -eq 5 ] && [ "$KMINOR" -eq 15 ]; then
    if version_gte $KMAJOR $KMINOR $KPATCH 5 15 216; then
      RESULT="PATCHED"; echo "[+] Fixed in 5.15.216, running $KVER"; return
    fi
  elif [ "$KMAJOR" -eq 6 ] && [ "$KMINOR" -eq 1 ]; then
    if version_gte $KMAJOR $KMINOR $KPATCH 6 1 183; then
      RESULT="PATCHED"; echo "[+] Fixed in 6.1.183, running $KVER"; return
    fi
  elif [ "$KMAJOR" -eq 6 ] && [ "$KMINOR" -eq 6 ]; then
    if version_gte $KMAJOR $KMINOR $KPATCH 6 6 151; then
      RESULT="PATCHED"; echo "[+] Fixed in 6.6.151, running $KVER"; return
    fi
  elif [ "$KMAJOR" -eq 6 ] && [ "$KMINOR" -eq 12 ]; then
    if version_gte $KMAJOR $KMINOR $KPATCH 6 12 103; then
      RESULT="PATCHED"; echo "[+] Fixed in 6.12.103, running $KVER"; return
    fi
  elif [ "$KMAJOR" -eq 6 ] && [ "$KMINOR" -eq 18 ]; then
    if version_gte $KMAJOR $KMINOR $KPATCH 6 18 44; then
      RESULT="PATCHED"; echo "[+] Fixed in 6.18.44, running $KVER"; return
    fi
  elif [ "$KMAJOR" -eq 7 ] && [ "$KMINOR" -eq 1 ]; then
    if version_gte $KMAJOR $KMINOR $KPATCH 7 1 8; then
      RESULT="PATCHED"; echo "[+] Fixed in 7.1.8, running $KVER"; return
    fi
  elif [ "$KMAJOR" -ge 8 ] 2>/dev/null; then
    RESULT="PATCHED"; echo "[+] Kernel $KVER is newer than all affected branches"; return
  elif [ "$KMAJOR" -eq 7 ] && [ "$KMINOR" -ge 2 ] 2>/dev/null; then
    RESULT="PATCHED"; echo "[+] Kernel $KVER is >= 7.2 (fixed in 7.2-rc6)"; return
  fi

  # If we're in an affected major.minor but below the fix
  RESULT="VULNERABLE"
  echo "[-] Kernel $KVER appears VULNERABLE (below fix for this branch)"
}

check_version

# Check SCTP module status
echo ""
echo "[*] SCTP module status:"
if lsmod 2>/dev/null | grep -q '^sctp '; then
  echo "[-] sctp module is LOADED — attack surface is active"
elif modprobe -n sctp 2>/dev/null; then
  echo "[!] sctp module is NOT loaded but CAN be auto-loaded"
else
  echo "[+] sctp module is BLOCKED or unavailable — attack surface eliminated"
  if [ "$RESULT" = "VULNERABLE" ]; then
    echo "[*] Kernel is vulnerable but SCTP is blocked — effective risk is mitigated"
  fi
fi

if lsmod 2>/dev/null | grep -q '^sctp_diag '; then
  echo "[-] sctp_diag module is LOADED"
elif modprobe -n sctp_diag 2>/dev/null; then
  echo "[!] sctp_diag module can be auto-loaded"
else
  echo "[+] sctp_diag module is BLOCKED or unavailable"
fi

echo ""
echo "=== RESULT: $RESULT ==="
case "$RESULT" in
  PATCHED)    exit 0 ;;
  VULNERABLE) exit 1 ;;
  *)          exit 2 ;;
esac