A critical race condition vulnerability exists within mod_http2, the HTTP/2 protocol module for the Apache HTTP Server. The flaw stems from a concurrency defect where a worker thread executes memory write operations into regions owned by the connection thread, resulting in severe heap corruption and potential remote code execution (RCE). Apache HTTP Server versions 2.4.55 through 2.4.70; standalone mod_h2 versions 2.0.8 through 2.0.42 are affected. Successful exploitation requires successful HTTP/2 protocol negotiation. Good news, this vulnerability has already been resolved in Apache HTTP Server version 2.4.71, released on November 11, 2026. Root cause analysis, detection and other details follow.

CVE-2026-119618 at a glance
This table is the baseline of all information sourced from vendor records, and other high
| Item | Value | Source |
|---|---|---|
| Type | Race condition, CWE-362 | CVE record, NVD |
| Severity | Critical per Apache. No CVSS v4 from anyone. CVSS v3.1 9.8 from Red Hat only | Apache, Red Hat |
| Precondition | The server negotiates HTTP/2, as h2 or h2c | Apache, and my lab |
| Affected | Apache HTTP Server 2.4.55 through 2.4.70. mod_h2 2.0.8 through 2.0.42 | Apache |
| Fixed | 2.4.71, released 11 November 2026. The same release fixes CVE-2026-106023 and CVE-2026-109163 | Apache |
| Vendor workaround | None published | Apache |
| Exploited | No report as of 12 November 2026. Not in CISA KEV catalogVersion 2026.11.10, which predates the disclosure | CISA KEV |
| Credit | Anthropic’s OSS Scanner, then Anthony Weems and Simon Scannell of Google Cloud Vulnerability Research | Apache |
These are my inferences and not the official vendor rating:
Apache 2.4.55 to 2.4.70, HTTP/2 on, reachable from untrusted networks
- No login, no virtual host and no URL gate before the write
- The fix has been readable on GitHub since 8 November
- A public repository reproduces the corruption
- It is a race, so reliability outside a lab is unknown
- No exploitation in the wild reported
Patch now
outcome: Treat as exploitable
outcome: The module version string does not prove the fix
2.4.71, or no h2 and h2c in any Protocols line today
Same versions, HTTP/2 believed to be off
- Lab: with no h2 or h2c in any Protocols line, every probe stayed on HTTP/1.1
- Lab: a second Protocols line that says only http/1.1 changed nothing
- Lab: one virtual host with h2c overrode the server-wide setting
- Lab: prefork refused ALPN and Upgrade but served direct h2c
Prove it, then patch on schedule
outcome: Not reachable only while every probe answers HTTP/1.1
Probe h2, h2c Upgrade and h2c prior knowledge on every listener
What is the root cause of CVE-2026-119618?
The old code wrote a header into a table that two threads share. The fix writes it into the request’s own copy. That is the whole patch: one line in modules/http2/h2_request.c, function assign_headers(), commit 824beab.
if (!cl && apr_table_get(req->headers, "Content-Type")) {
/* If we have a content-type, but already seen eos, no more
* data will come. Signal a zero content length explicitly.
*/
- apr_table_setn(req->headers, "Content-Length", "0");
+ apr_table_setn(r->headers_in, "Content-Length", "0");
}
I cloned the Apache repository and read the 2.4.54, 2.4.55, 2.4.70 and 2.4.71 tags. This is what the source shows:
reqis the stream’s request object. The worker’s context points at the same object (h2_conn_ctx.c,conn_ctx->request = stream->request). Its header table is allocated from the stream pool. The stream pool is a child of the session pool and has no allocator of its own (h2_session.c,apr_pool_create(&stream_pool, session->pool)). This answers whose table is it?- A worker thread runs
slot_run(), which callsh2_c2_process(), thenc2_process(), thenh2_create_request_rec(), thenassign_headers(). So the write happens on a worker thread, into memory that belongs to the connection thread. This corresponds to which thread writes this information. - Red Hat describes a worker thread writing into connection-thread memory through a shared, lock-free allocator. That matches the source.
- Apache 2.4.54 has the same write, but in
h2_request_end_headers(), which runs while the connection thread parses headers. 2.4.55 moved it intoassign_headers(). That matches the affected range starting at 2.4.55. - The request is not CONNECT, it has no body, it carries a Content-Type header, and it has no Content-Length header.
- The call comes before virtual host selection, authentication and every handler. Any URL works, and access rules do not help.
- Adding a new key to an APR table can grow the table, which allocates from its pool. APR pools are not safe for two threads at once.
The line Apache removed has a companion on the other build path. h2_request_create_bucket() clones the table first and never writes to the shared one.
CVE-2026-119618 Reachability analysis
Seven conditions must hold, in order, before the race can corrupt memory. Five of them have an exit that stops the attack outright.
How do we know?
- Conditions 2 and 3 are verified lab results. I ran Apache 2.4.58 from Ubuntu 24.04 as ten instances. With no Protocols line, or with
Protocols http/1.1, the server stayed on HTTP/1.1 even with mod_http2 loaded. Two Protocols lines in one scope add up, so a second line that says only http/1.1 switches nothing off. - prefork is only a partial stop. With prefork the server logged AH10034 and refused
h2on TLS. It still answeredh2cwith prior knowledge as HTTP/2.0 on the cleartext port. The warning text says HTTP/2 will be inactive. Forh2cthat was not true in my run. The cleartext Upgrade was refused; only the prior-knowledge connection got through. - Conditions 4 to 6 come from the source and the advisory. Red Hat states that mod_http2 before 2.0.8 lacks the affected code.
- Condition 7 is where public knowledge ends. Red Hat says RHEL 9 and 10 give each stream its own allocator and rates those builds Important for that reason. Upstream builds share the session allocator.
There is vulnerability does not need authentication or depend if it’s a virtual host or a simple URL.
CVE-2026-119618 Attack path
A defender can break the attack path only at step 1 or step 2. After that, only side effects are visible.
There however are these caveats on the above attack path:
- Steps 1 to 3 follow from the source and my lab runs. Step 4 is from the Apache and Red Hat statements. Step 5 is what any code execution in a web server worker allows.
- An attacker would probably send multiple such streams at once, because the bug is a race between threads. No primary source states the count or timing.
How do I check whether a server is exposed?
In addition to checking the version, listing the modules, search for Protocols lines, check for a response of these commands:
# 1. What each listener really negotiates. Run from another host, once per hostname and port.
curl -sk -o /dev/null -w '%{http_version}\n' --http2 https://HOST/ # 2 means h2 is live
curl -s -o /dev/null -w '%{http_version}\n' --http2 http://HOST/ # 2 means the h2c Upgrade is live
curl -s -o /dev/null -w '%{http_version}\n' --http2-prior-knowledge http://HOST/ # 2 means direct h2c is live
openssl s_client -alpn h2,http/1.1 -connect HOST:443 </dev/null 2>/dev/null | grep ALPN
# 2. Every file Apache reads, so no Protocols line hides in an include.
apachectl -t -D DUMP_INCLUDES
# 3. Crash and warning history.
grep -hE 'AH00051|AH00052|AH10034' /var/log/httpd/error_log* /var/log/apache2/error.log* 2>/dev/null
These are quick checks that can help with rapid triages. But, results will not be reliable when working with Cloudflare and similar setups.
CVE-2026-119618 log hunts
| Hunt | What to look for |
|---|---|
| Probing after you turn HTTP/2 off | "PRI * HTTP/2.0" 400 in a standard access log. That is a cleartext prior-knowledge attempt against a listener that no longer speaks HTTP/2 |
| The request shape, by client | With the format above: HTTP/2.0, ct= set, cl=-, many lines from one client in a short window. Legitimate clients send this too, so baseline first |
| Failed attempts | AH00051 or AH00052 in the error log, clustered in time, on a server with HTTP/2 on |
grep -E '"PRI \* HTTP/2\.0" 400' /var/log/apache2/access.log* /var/log/httpd/access_log* 2>/dev/null
grep -hE 'AH00051|AH00052' /var/log/apache2/error.log* /var/log/httpd/error_log* 2>/dev/null
One blind spot inside these hunts is that a request that wins the race may never finish, so it may leave no access log line at all.
Generic post-exploitation rule (Sigma)
This rule does not detect the memory corruption. It detects what usually follows code execution in a web server worker: the server starting a shell or a download tool. It will fire on servers that run CGI. SigmaHQ already has a one related rule, Linux Webshell Indicators, which watches web server parents, apache2 and httpd included, for reconnaissance tools such as whoami, netstat and uname. Run that rule as well. Mine does not duplicate it. The SigmaHQ rule catches reconnaissance commands, and mine catches the shell, interpreter or download tool a foothold starts. Get it here: CVE-2026-119618.yml
What have government CERTs said about CVE-2026-119618?
One national CERT notice was findable on 12 November 2026: the Dutch NCSC. I searched for the others listed below and found nothing for this CVE.
| Agenry | Notice | Date | Rating | Information |
|---|---|---|---|---|
| NCSC-NL (Netherlands) | NCSC-2026-0484, version 1.0.0 | 12 November 2026, 08:59 Amsterdam time | Priority “Normaal”; CVSS v3 9.8 | Apache fixed a concurrency flaw in assign_headers; unauthenticated remote code execution where HTTP/2 is on; HTTP/1.1-only servers are not vulnerable |
Which public repositories are safe to run, and which do their job?
Four repositories existed for this CVE on 12 November 2026, all created that day. I scored the two defensive ones using the scoring algorithm I developed and posted here.
foxcornlab/apache-httpd-scanner · scanner · 80/100
- Graded 6 of 6 version cases correctly in my lab
- Flags distribution backports as UNKNOWN, not safe
- Covers all three 2.4.71 CVEs, cites fixed versions
- 55 unit tests, all passing; MIT licence
- Owner account is 8 years old
- Single author, 2 commits, none signed with the owner's key
- No CI workflows
Safe to run, does its job
outcome: Content 50 of 50, provenance 15 of 30, hygiene 15 of 20
outcome: Does not test the race; it is a version and ALPN check, by design
Version and exposure grader, read-only
suominen/CVE-2026-119618 · docs tracker · 74/100
- Tracks fixed versions across Debian, Ubuntu, Red Hat, NixOS, pkgsrc
- Extensive test suite; CC BY 4.0 licence; pinned Hugo build
- Owner account is 14 years old, member of 3 public organizations
- Facts live on the rendered site, not in the repository
- Single author, 4 commits, none signed; agent-authored (CLAUDE.md, auto-update)
Safe to read, useful
outcome: Content 41 of 50, provenance 17 of 30, hygiene 16 of 20
outcome: A tracker, not a scanner; do not compare its 74 with the scanner 80
Per-distribution patch-status site
The two exploit-side repositories, status only
- googlesky/CVE-2026-119618 ships a containerised lab, a standard-library HTTP/2 proof of concept, and sanitizer evidence.
- geovanidps/cve-2026-119618-Apache is a black-box validator whose
validatemode opens concurrent streams to drive the race.
Leave a Reply
You must be logged in to post a comment.