Is Your Apache Box One HTTP/2 Request Away From Someone Else’s Shell?

CVE-2026-119618 is unauthenticated remote code execution on Apache 2.4.55–2.4.70 with HTTP/2 enabled. The patch shipped yesterday; here's how to audit your fleet tonight and decide who patches first.

No credentials. No phishing email. No user clicking anything. Just a TCP connection to port 443, a protocol negotiation, and a request your server was built to accept, and on the wrong version of Apache, that request runs code as whatever user httpd runs as. That’s the entire kill chain for CVE-2026-119618, and it’s why this one jumped the queue ahead of whatever you had planned for this week.

Here’s the timeline that got us here, and the one thing on it you still control.

The vulnerable versions: Apache 2.4.55 through 2.4.70

HTTP/2 stopped being exotic years ago. By the time Apache 2.4.55 shipped, mod_http2 was the default way serious deployments got multiplexing, header compression and connection reuse, the stuff that makes a page full of assets load without opening thirty connections. If you run Apache in front of anything performance-sensitive, you almost certainly turned it on and forgot about it. That’s the point. Infrastructure you forget about is infrastructure you don’t audit.

The flaw lives in how that module parses and handles HTTP/2 requests. Every version from 2.4.55 through 2.4.70 carries it. The source describes an unauthenticated remote code execution path through HTTP/2 request handling, reachable by anyone who can open a connection and speak the protocol. I’m not going to invent a byte-level root cause the advisory doesn’t publish; what matters operationally is the shape of it, and the shape is ugly: pre-authentication, network-reachable, server-side execution.

The prerequisite isn’t a misconfiguration or a weird edge case. The prerequisite is HTTP/2 being on, which, for a lot of you, is the default you chose on purpose.

November 11, 2026, Apache 2.4.71 lands with the fix

The project released 2.4.71 yesterday with the patch. That’s the fixed line. Anything at or above it is clear; anything in the 2.4.55–2.4.70 band with http2_module loaded is exposed. Clean break, easy to reason about, which is a small mercy when the rest of the news is bad.

One thing to get straight before you panic the whole fleet: not every Apache box is vulnerable. The vulnerable condition is version-in-range and HTTP/2 actually enabled. An Apache instance on an affected version that never loaded mod_http2, or had it compiled out, is not reachable through this path. That distinction is the difference between a two-hour emergency and a controlled rollout, so establish it before you wake anyone up.

November 12, 2026, today, and the only beat you own

The vendor shipped. The vulnerability is public. The gap between those two facts is where you live right now, and the first job isn’t patching, it’s knowing your exposure. You cannot prioritise what you haven’t counted.

Run this on a single host first. It reports; it changes nothing.

run.shbash, zsh
#!/usr/bin/env bash
# Apache HTTP/2 exposure check for CVE-2026-119618, report only.
# Handles both httpd (RHEL family) and apache2 (Debian family).
​
set -euo pipefail
​
BIN=""
for c in httpd apache2ctl apache2; do
  if command -v "$c" >/dev/null 2>&1; then BIN="$c"; break; fi
done
​
if [[ -z "$BIN" ]]; then
  echo "NO_APACHE host=$(hostname)"
  exit 0
fi
​
VER=$("$BIN" -v 2>/dev/null | awk -F'/' '/version/{print $2}' | awk '{print $1}')
# Modules: httpd -M needs root/env on some distros; fall back to -t -D DUMP_MODULES
H2=$("$BIN" -M 2>/dev/null | grep -c 'http2_module' || true)
[[ "$H2" == "0" ]] && H2=$("$BIN" -t -D DUMP_MODULES 2>/dev/null | grep -c 'http2_module' || true)
​
STATE="CLEAR"
# Vulnerable band: 2.4.55 .. 2.4.70 inclusive, AND http2 loaded.
if [[ "$H2" -ge 1 ]]; then
  if printf '%s\n2.4.55\n' "$VER" | sort -V | head -1 | grep -qx '2.4.55' \
     && printf '2.4.70\n%s\n' "$VER" | sort -V | head -1 | grep -qx "$VER"; then
    STATE="EXPOSED"
  fi
fi
​
echo "host=$(hostname) version=${VER:-unknown} http2_loaded=$([[ $H2 -ge 1 ]] && echo yes || echo no) state=$STATE"

Push it across the fleet with whatever you already have, Ansible ad-hoc, a Satellite run, a pssh loop, and grep the output for state=EXPOSED. That list is your work queue, sorted by one more question: is the box internet-facing?

If you only want the two facts by hand on a box you’re logged into:

run.shbash, zsh
httpd -v 2>/dev/null || apache2 -v
httpd -M 2>/dev/null | grep http2_module || apache2ctl -M 2>/dev/null | grep http2_module

A line coming back from the second command means the module is live. Combined with a version in the 55–70 range, that’s an exposed host.

The next 24 hours, fix in priority order, not panic order

Internet-facing Apache with HTTP/2 enabled: immediate. Not next maintenance window, tonight. Unauthenticated RCE with no interaction prerequisite is the category that gets mass-scanned within days of a public advisory, because it’s the category worth scanning for. Upgrade the package to the 2.4.71 line through your distro’s vendor build (RHEL/Rocky/Alma, Debian/Ubuntu backports, or your own compiled tree), then restart the service and re-run the check to confirm version=2.4.71 and state=CLEAR. Don’t assume the restart happened, Apache will happily keep serving old code from memory after a package swap if nobody bounced it.

If you genuinely cannot patch in the next few hours, change freeze, a vendor build that isn’t ready, an appliance you don’t own, disable the module as a compensating control. You lose HTTP/2 performance, not availability; the server falls back to HTTP/1.1 and keeps serving.

run.shbash, zsh
# Debian/Ubuntu
sudo a2dismod http2 && sudo systemctl restart apache2
​
# RHEL family: comment the LoadModule line, then restart
# in /etc/httpd/conf.modules.d/*.conf
#   #LoadModule http2_module modules/mod_http2.so
sudo systemctl restart httpd

Treat disabling the module as a tourniquet, not a cure. It closes the reachable path, but it leaves you running known-vulnerable code with the fix one LoadModule line away from being live again if someone re-enables HTTP/2 in six months without checking. Log the exception, set a date, actually patch.

Internal-only servers with HTTP/2: this week. The network barrier buys you time, not immunity, an attacker with a foothold inside, or a compromised workstation on the same segment, has exactly the same unauthenticated path to your internal Apache. “Behind the firewall” has never meant “unreachable,” and pre-auth RCE is precisely the primitive that turns one compromised laptop into lateral movement.

The beat already on the calendar

The advisory is public and the fix is diffable. That combination has a predictable follow-on: the window between a published patch and working exploit code for a clean, pre-auth RCE is measured in days, not months, because the patch itself hands researchers, and everyone else, a map of exactly what changed. The source cites the vulnerability and the attack, not confirmed exploitation in the wild, and I’m not going to pretend otherwise. But you don’t wait for the proof-of-concept to drop before you patch an unauthenticated RCE. You patch, and then you watch the PoC land on a box that’s already clear.

The version number that protects you is 2.4.71. The only thing standing between your fleet and that number is whether you run the check tonight or read about it on someone else’s status page next week.