Like a toll booth that accepts pennies, the Linux TCP stack lets remote peers force millions of tiny accounting entries until the system stalls
CVE-2019-11479 is a TCP-layer denial-of-service in the Linux kernel. The effective minimum TCP MSS is hard-coded to 48 bytes, so a remote peer can force the retransmission queue into a huge number of tiny segments — especially when combined with crafted SACK blocks — driving kernel memory and CPU consumption high enough to OOM or soft-lockup the host. Affected kernels are 4.4.x < 4.4.182, 4.9.x < 4.9.182, 4.14.x < 4.14.127, 4.19.x < 4.19.52, and 5.1.x < 5.1.11; older unsupported branches are also affected.
The vendor/NVD rating of High 7.5 is appropriate. The attack is unauthenticated and remote, but it only causes availability loss — no code execution, no privilege escalation, no data disclosure. In practice, public-facing Linux servers and network-adjacent internal hosts are the meaningful target population, and the kernel TCP stack is difficult to shield with application-layer controls. That earns a High, not Critical.
4 steps from start to impact.
Identify a reachable TCP service on a vulnerable Linux host
- Network reachability from attacker to at least one TCP port
- Target runs an affected Linux kernel branch
- Firewall/security groups can restrict exposure to specific source ranges
- Cloud load balancers may hide backend kernel versions
Negotiate a deliberately tiny TCP MSS
- Attacker can complete a TCP handshake
- No inline TCP proxy rewrites or clamps the MSS
- TCP-terminating load balancers or SYN proxies can re-originate connections with a normal MSS
- Some edge firewalls can drop SYNs with suspiciously small MSS option values
Fragment the retransmission queue with crafted SACKs
- Vulnerable Linux kernel with unfixed SACK/retransmit queue logic
- Attacker can generate enough SACK blocks and data to sustain the pattern
- Rate limiting and connection caps can slow the exhaustion rate
- Ingress traffic shaping may reduce throughput but not the fundamental property
Exhaust kernel resources to create host-level DoS
- Attacker can sustain multiple connections
- No kernel live-patch or per-connection memory limits intervene
- Modern kernels with automated OOM tuning may kill only the offending workload
- Containerized workloads may limit blast radius to a single pod if the host kernel remains stable
tcp option maxseg size 1-535 and drop. This stops remote peers from negotiating the tiny MSS that makes the retransmit queue fragment. Deploy within 30 days as a HIGH-severity stopgap.- Application-layer WAF rules — MSS and SACK are negotiated at the TCP layer, below the HTTP payload a WAF inspects.
- FORWARD-chain TCPMSS clamping — that only adjusts forwarded traffic, not locally terminated TCP connections; use nftables INPUT rules or a TCP proxy instead.
- Generic SYN cookies alone — they mitigate SYN floods but do not stop a completed connection from negotiating a tiny MSS and sending crafted SACKs.
The supporting signals.
| In-the-wild status | Not in CISA KEV; no sustained mass exploitation campaign documented. Public DoS PoCs circulated immediately after disclosure. |
|---|---|
| Proof-of-concept availability | Public PoC scripts and packet traces exist. See pocindex.io and GitHub searches for CVE-2019-11479 / SACK DoS reproducers. |
| EPSS | 0.9166 (91.66% 30-day probability; ~99th percentile). Extremely high likelihood model score for unpatched internet-facing Linux. |
| KEV status | Not listed in CISA KEV as of this assessment. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H — network, low complexity, unauthenticated, availability impact only. |
| Affected versions | Linux kernel 4.4.x < 4.4.182, 4.9.x < 4.9.182, 4.14.x < 4.14.127, 4.19.x < 4.19.52, 5.1.x < 5.1.11; older unsupported branches also affected. |
| Fixed versions | 4.4.182, 4.9.182, 4.14.127, 4.19.52, 5.1.11; distro backports in RHEL/CentOS, Ubuntu, Debian, SUSE, and others. |
| Scanning/exposure | Not routinely detectable by Shodan/Censys because kernel version is not exposed; exposure equals any reachable TCP service on a vulnerable host. No broad scanning wave observed at disclosure. |
| Disclosure date / researcher | 2019-06-19; Jonathan Looney, Netflix. |
Sources.
Why this verdict
- Baseline: vendor/NVD 7.5 High is a fair starting point: unauthenticated remote exploitation with low complexity and high availability impact.
- Friction audit: the only hard prerequisite is reachability to any TCP port on a vulnerable Linux host. Load balancers, TCP proxies, and strict firewalls blunt it, but many bare-metal and VM servers still expose TCP directly.
- Role multiplier: Linux is the kernel for hypervisors, databases, edge proxies, Kubernetes nodes, and network appliances. A successful DoS can take a production node or service offline, but the outcome is availability-only — not domain takeover, fleet compromise, or supply-chain pivot.
- EPSS: 0.9166 indicates a high probability of exploitation attempts against internet-facing unpatched Linux hosts, keeping pressure against downgrading to MEDIUM.
Why not higher?
The attack only causes availability loss on the targeted host; it never grants code execution, reads memory, or escalates privileges. The attacker must re-attack each exposed host independently, and the blast radius is bounded per connection — no lateral movement, no data egress, no credential theft.
Why not lower?
The attacker is unauthenticated and remote, requiring no user interaction or credentials. Linux is ubiquitous in servers, cloud workloads, and network appliances, so even a single-host kernel OOM qualifies as a production incident on high-value roles. Public PoCs and very high EPSS argue against MEDIUM for internet-facing footprints.
Crowdsourced verification payload.
Run on each Linux host you suspect may be unpatched. Save the script as check_cve_2019_11479.sh and invoke with bash check_cve_2019_11479.sh. No special privileges are required for kernel version checks; root helps read package changelogs for backport detection.
#!/bin/bash
# CVE-2019-11479 checker - Linux TCP small-MSS DoS (SACK resource exhaustion)
# Usage: bash cve-2019-11479.sh
# Run on the Linux host to be checked; any user can run, root only helps read package changelogs.
set -u
kver="$(uname -r)"
echo "Kernel version: $kver" >&2
# Try distro changelog/backport metadata first.
patched_by_changelog=false
if command -v rpm >/dev/null 2>&1; then
for p in $(rpm -qa 'kernel*' 2>/dev/null); do
if rpm -q --changelog "$p" 2>/dev/null | grep -qi 'CVE-2019-11479'; then
patched_by_changelog=true; break
fi
done
fi
if command -v dpkg >/dev/null 2>&1; then
for cl in /usr/share/doc/linux-image-${kver}/changelog* /usr/share/doc/linux-image-$(uname -r)/changelog*; do
[ -f "$cl" ] || continue
if zgrep -qi 'CVE-2019-11479' "$cl" 2>/dev/null || grep -qi 'CVE-2019-11479' "$cl" 2>/dev/null; then
patched_by_changelog=true; break
fi
done
fi
if $patched_by_changelog; then
echo "PATCHED"; exit 0
fi
kbase="$(echo "$kver" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+' || echo "$kver")"
version_ge() { [ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -1)" = "$2" ]; }
version_lt() { ! version_ge "$1" "$2"; }
# Known mainline fixed versions.
if version_ge "$kbase" "5.1.11"; then echo "PATCHED"; exit 0; fi
if version_ge "$kbase" "4.19.52" && version_lt "$kbase" "4.20"; then echo "PATCHED"; exit 0; fi
if version_ge "$kbase" "4.14.127" && version_lt "$kbase" "4.15"; then echo "PATCHED"; exit 0; fi
if version_ge "$kbase" "4.9.182" && version_lt "$kbase" "4.10"; then echo "PATCHED"; exit 0; fi
if version_ge "$kbase" "4.4.182" && version_lt "$kbase" "4.5"; then echo "PATCHED"; exit 0; fi
# Explicitly vulnerable longterm branches below their fixed version.
if version_ge "$kbase" "4.4" && version_lt "$kbase" "4.5" && version_lt "$kbase" "4.4.182"; then echo "VULNERABLE"; exit 1; fi
if version_ge "$kbase" "4.9" && version_lt "$kbase" "4.10" && version_lt "$kbase" "4.9.182"; then echo "VULNERABLE"; exit 1; fi
if version_ge "$kbase" "4.14" && version_lt "$kbase" "4.15" && version_lt "$kbase" "4.14.127"; then echo "VULNERABLE"; exit 1; fi
if version_ge "$kbase" "4.19" && version_lt "$kbase" "4.20" && version_lt "$kbase" "4.19.52"; then echo "VULNERABLE"; exit 1; fi
if version_ge "$kbase" "5.1" && version_lt "$kbase" "5.2" && version_lt "$kbase" "5.1.11"; then echo "VULNERABLE"; exit 1; fi
# Distro kernels with missing changelog data: cannot confirm.
echo "UNKNOWN"; exit 2