CVE-2026-54428 is a denial-of-service vulnerability in Apache HttpComponents Core, specifically in the HTTP/2 HPACK decoder shipped through the Maven artifact org.apache.httpcomponents.core5:httpcore5-h2. The public Apache advisory describes it as “Important” severity and says affected releases allow a remote attacker to cause memory exhaustion by sending oversized compressed header blocks before the HTTP/2 SETTINGS acknowledgement causes the configured header list size limit to be applied. (Openwall)
That wording is dense, but it gives defenders the whole shape of the bug. This is not a remote code execution flaw. It is not an authentication bypass. It is not a direct secret disclosure issue. It is a resource-consumption bug in a protocol decoder, and the main impact is availability loss. NVD records the same core description, maps the weakness to CWE-400 and CWE-770, and shows a CISA-ADP CVSS v3.1 score of 7.5 with the vector AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H. (NVD)
The practical risk depends on where the vulnerable decoder sits. A vulnerable httpcore5-h2 jar in a test-only module is not the same as the same jar running inside a public API gateway that accepts HTTP/2 traffic from the internet. A CDN that terminates HTTP/2 before forwarding HTTP/1.1 to the origin changes the exposure story. So does a service mesh that speaks HTTP/2 between workloads. The right response is not to panic over every scanner hit. It is to map the runtime component, map the HTTP/2 path, patch the affected artifact, and collect non-destructive evidence that the vulnerable decoder is no longer reachable.
Quick facts for security triage
| Field | Practical answer |
|---|---|
| CVE | CVE-2026-54428 |
| Primary component | Apache HttpComponents Core HTTP/2 support |
| Maven artifact to check | org.apache.httpcomponents.core5:httpcore5-h2 |
| Vulnerable version range | Apache describes 5.4.2 and earlier and 5.5-beta1 and earlier as affected |
| NVD affected package data | NVD lists the Maven package and affected ranges from 5.0-alpha through 5.4.2, plus the 5.5 alpha to 5.5 beta1 range |
| Vulnerability class | Resource consumption, memory exhaustion |
| CWE mapping | CWE-400, Uncontrolled Resource Consumption, and CWE-770, Allocation of Resources Without Limits or Throttling |
| Attack vector | Network |
| Privileges required | None in the CISA-ADP CVSS vector shown by NVD |
| User interaction | None |
| Main impact | Availability |
| RCE | No authoritative source describes this CVE as remote code execution |
| Key protocol detail | Oversized compressed HTTP/2 header blocks are processed before SETTINGS acknowledgement causes the configured header list size limit to be applied |
| Safe validation method | Version evidence, runtime artifact evidence, HTTP/2 exposure mapping, and lab-only behavioral testing |
| Primary remediation | Upgrade to a non-affected release or apply a vendor-supported backport |
The table hides one important nuance: the vulnerable path is below ordinary application logic. If an HTTP/2 decoder consumes heap while handling a field block, the service may fail before a controller, servlet, route handler, middleware chain, business authorization rule, or API schema validator gets a chance to reject the request. That is why a DoS issue in protocol parsing can be more operationally serious than a normal application-layer “bad request” bug.
Apache HttpComponents Core is not Apache HTTP Server
The first common mistake is confusing Apache HttpComponents Core with Apache HTTP Server. CVE-2026-54428 is not a vulnerability in the httpd web server or mod_http2. It is tied to Apache HttpComponents Core, a Java project. Apache’s HttpCore overview describes HttpCore as a set of low-level HTTP transport components that can be used to build custom client-side and server-side HTTP services, with both classic blocking I/O and non-blocking Java NIO models. The same Apache documentation says HttpCore aims to conform to HTTP Semantics, HTTP/1.1, HTTP/2, HPACK, and related RFCs. (hc.apache.org)
For inventory work, the artifact name matters more than the word “Apache.” Search for:
org.apache.httpcomponents.core5:httpcore5-h2
A service can use Apache HttpComponents Core directly, or it can receive the artifact through another library, SDK, internal platform wrapper, integration gateway, test harness, or vendor-shipped Java application. Modern Java deployments often package dependencies into fat jars, shaded jars, application images, or container layers. A dependency may not be obvious from a top-level pom.xml.
CVE-2026-54428 therefore has two separate questions:
| Question | Why it matters | Best evidence |
|---|---|---|
Is httpcore5-h2 present | The CVE is tied to the HTTP/2 artifact, not every Apache-branded package | Maven or Gradle tree, SBOM, jar inspection, image scan |
| Is the affected version running | Source dependencies do not always match deployed artifacts | Running classpath, container image digest, deployed jar list |
| Does untrusted HTTP/2 reach it | Memory exhaustion requires traffic to enter the vulnerable decoder path | ALPN evidence, gateway config, ingress config, service mesh routing |
| Is there an alternate path | Edge termination does not protect paths that bypass the edge | Internal listener map, partner routes, test endpoints, private load balancers |
If the vulnerable artifact exists only in a developer test module, the immediate operational risk is lower. If it runs behind a public or partner-facing HTTP/2 listener, the issue deserves fast action even though it is “only” availability impact.
Why HTTP/2 HPACK makes resource limits harder than they look
HTTP/2 replaced HTTP/1.1’s line-oriented text transport with binary frames. Headers are not sent as plain lines followed by a blank line. They are carried in HEADERS frames and, when the header block does not fit in one frame, CONTINUATION frames. RFC 9113 describes field section compression as the process of compressing field lines into a field block and decompression as decoding that field block back into field lines. It also notes that a receiving endpoint reassembles the field block fragments and decompresses the block to reconstruct the field section. (IETF Datatracker)
HPACK is the compression format used for HTTP/2 header fields. RFC 7541 defines HPACK as a format for efficiently representing HTTP header fields in HTTP/2. It explains that header fields can be represented literally or as references to entries in static and dynamic tables, and that the decoder reconstructs the header list from the encoded representation. (IETF Datatracker)
That compression design is useful. HTTP headers are repetitive. Many requests repeat the same field names and values: :method, :scheme, :path, :authority, accept, user-agent, cookies, authorization metadata, tracing headers, feature flags, and application-specific routing metadata. HPACK reduces bandwidth and latency by avoiding repeated literal transmission.
The security problem is not that HPACK exists. The problem is that compressed input and decoded memory cost are not the same thing. A small encoded representation may cause the receiver to allocate a much larger decoded structure. A decoder therefore needs to enforce resource limits while decoding, not only after it has already built an oversized header list in memory.
RFC 7541 explicitly says HPACK was designed with bounded memory requirements for constrained environments. (IETF Datatracker) But bounded memory in a protocol design still depends on correct implementation. CVE-2026-54428 is an implementation-level failure around resource allocation and timing. The public description says the affected decoder processes oversized compressed header blocks before the configured header list size limit is applied after HTTP/2 SETTINGS acknowledgement. (Openwall)
That is why ordinary “we set a header size limit” reasoning can fail. A configured limit is only protective if it is applied at the phase where memory is being committed.
The SETTINGS ACK timing issue

HTTP/2 endpoints exchange SETTINGS frames to advertise parameters for a connection. One of those settings is SETTINGS_MAX_HEADER_LIST_SIZE. RFC 9113 defines it as an advisory setting that tells a peer the maximum field section size the sender is prepared to accept. The value is based on the uncompressed size of field lines, including the byte length of the name and value plus 32 octets of overhead for each field line. The initial value is unlimited. (IETF Datatracker)
The word “advisory” matters. RFC 9113 says endpoints can send field blocks that exceed the advertised limit and risk having the request or response treated as malformed. It also says a server that receives a larger field block than it is willing to handle can send HTTP 431, Request Header Fields Too Large, and that the field block must be processed to keep connection state consistent unless the connection is closed. (IETF Datatracker)
The SETTINGS synchronization rules also matter. RFC 9113 says recipients of non-ACK SETTINGS frames must apply updated settings as soon as possible, acknowledge SETTINGS frames in order, and immediately emit a SETTINGS frame with the ACK flag set after processing the values. When the sender receives the ACK, it can rely on values from the oldest unacknowledged SETTINGS frame having been applied. (IETF Datatracker)
CVE-2026-54428 sits in this early connection timing window. A simplified flow looks like this:
1. A client and server establish an HTTP/2 connection.
2. SETTINGS frames are exchanged.
3. A configured header list size limit is supposed to constrain decoded headers.
4. Before the relevant SETTINGS acknowledgement makes that limit effective in the expected way,
oversized compressed header blocks reach the HPACK decoder.
5. The decoder allocates resources without sufficient limits or throttling.
6. Heap pressure rises and the process can hit memory exhaustion.
This is not the same as a client merely sending a large HTTP/1.1 header line. HTTP/2 field blocks are compressed, fragmented, reassembled, decoded, and then surfaced to higher layers. The dangerous boundary is where the decoder turns compact wire data into internal objects before a limit stops the operation.
What is actually affected
Apache’s advisory names the affected versions as Apache HttpComponents Core org.apache.httpcomponents.core5:httpcore5-h2 5.5-beta1 and 5.4.2, and the description clarifies that 5.4.2 and earlier and 5.5-beta1 and earlier are affected. (seclists.org) NVD’s change history records affected Maven package data for org.apache.httpcomponents.core5:httpcore5-h2, including the range from 5.0-alpha through 5.4.2, and the 5.5 alpha through 5.5 beta1 line. (NVD)
Apache’s project news records HttpComponents Core 5.4.3 and 5.5-beta2 as released on June 25, 2026. The 5.5-beta2 entry lists HTTP/2 and HPACK conformance improvements among the notable 5.5-series items, and the 5.4.3 entry describes a maintenance release fixing defects and a regression reported since the previous release. (hc.apache.org)
For production systems, the safest default is to move to a non-affected stable release or a vendor-supported fixed build. If a vendor backports the fix without changing the upstream version string in a way your scanner understands, document the vendor advisory, package build, image digest, and deployment timestamp. Vulnerability management tools often reason from upstream version numbers, but enterprise distributions and commercial products sometimes ship patched builds with their own version metadata.
One more caveat: GitHub’s advisory entry for GHSA-v3jc-474w-2wm6 may show incomplete package metadata, such as unknown affected or patched versions. That should not override Apache’s advisory and NVD’s package data. Use GitHub advisory pages as one input, not the sole source of truth, especially for newly disclosed Java dependency issues.
Exposure scenarios that should get priority
Not every dependency finding has the same operational urgency. The following exposure model is more useful than treating every httpcore5-h2 scanner hit as identical.
| Scenario | Priority | Why |
|---|---|---|
Internet-facing Java service terminates HTTP/2 with affected httpcore5-h2 | High | Untrusted clients can reach the decoder directly |
| Public API behind a load balancer that forwards HTTP/2 to the Java origin | High | The edge does not remove the vulnerable protocol path |
| Partner integration endpoint accepts HTTP/2 and runs affected artifact | High to medium | Partner traffic may be semi-trusted, but parser work happens before business authorization |
| Internal service mesh uses HTTP/2 or gRPC-like traffic to a vulnerable Java service | Medium | Compromised workloads or overly broad internal access can create lateral DoS risk |
| CDN terminates HTTP/2 and forwards HTTP/1.1 to origin, with no bypass path | Lower for the origin | The vulnerable origin decoder may not receive HTTP/2 from public users |
| Affected artifact appears only in test scope or unused module | Lower | Still fix it, but prioritize reachable runtime paths first |
| Outbound client uses affected artifact to call only trusted services | Context-dependent | Lower than public inbound exposure, but malicious or compromised upstreams can still matter |
| Outbound client fetches from user-controlled URLs or third-party webhooks | Medium | The client may parse hostile HTTP/2 responses from untrusted peers |
The outbound-client case is easy to oversimplify. The public CVE wording says a remote attacker can cause memory exhaustion by sending oversized compressed header blocks. Many teams immediately picture a server receiving requests, and that is usually the most urgent case. But HTTP clients also receive and decode response headers. If an application makes HTTP/2 requests to attacker-controlled URLs, partner-controlled endpoints, customer-provided webhooks, or open internet resources, response parsing may still be part of the trust boundary. The correct question is not “server or client,” but “who controls the peer sending the HTTP/2 field block?”
Dependency discovery in Maven and Gradle
Start with direct and transitive dependencies. For Maven:
# Run inside the project root.
# This performs dependency inspection only. It does not send traffic.
mvn -q dependency:tree \
-Dincludes=org.apache.httpcomponents.core5:httpcore5-h2
For a multi-module project, run from the aggregator root and review each deployable module. A library module with a vulnerable dependency may not matter by itself, but a service module that packages it into a runtime image does.
You can also inspect resolved dependencies:
mvn -q dependency:list \
-DincludeGroupIds=org.apache.httpcomponents.core5 \
-DincludeArtifactIds=httpcore5-h2
For Gradle:
# Inspect runtime classpath for a service project.
./gradlew dependencies --configuration runtimeClasspath | grep -i "httpcore5-h2"
# In a multi-project build.
./gradlew :your-service:dependencies --configuration runtimeClasspath | grep -i "httpcore5-h2"
If the dependency appears through a transitive path, use dependency insight:
./gradlew :your-service:dependencyInsight \
--dependency httpcore5-h2 \
--configuration runtimeClasspath
The output should answer two questions: which version is selected, and why that version is selected. Dependency mediation can surprise teams. A top-level library may request a fixed version, while another dependency or platform BOM forces the build back to an older version.
For Maven, dependency management can pin the fixed version:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents.core5</groupId>
<artifactId>httpcore5-h2</artifactId>
<version>5.4.3</version>
</dependency>
</dependencies>
</dependencyManagement>
For Gradle, a constraint can prevent accidental downgrade:
dependencies {
constraints {
implementation("org.apache.httpcomponents.core5:httpcore5-h2") {
version {
require("5.4.3")
}
because("Avoid CVE-2026-54428 affected httpcore5-h2 versions")
}
}
}
Do not force dependency versions across a large platform without integration tests. HTTP libraries sit in sensitive paths: TLS negotiation, connection pooling, proxy handling, timeouts, redirects, multiplexing, stream lifecycle, and header normalization. A safe patch still needs a normal release process.
Runtime artifact checks
Source-level dependency evidence is not enough. Production risk lives in deployed artifacts.
For built jars:
# Search local build outputs for httpcore5-h2 jars.
find ./target ./build ./dist -type f -name "httpcore5-h2-*.jar" -print
For fat jars:
# Inspect a service jar for HttpCore HTTP/2 classes.
jar tf your-service.jar | grep "org/apache/hc/core5/http2" | head
For a container image you own or are authorized to inspect:
IMAGE="registry.example.com/your-team/your-service:current"
docker run --rm "$IMAGE" sh -c '
find / -type f \( -name "httpcore5-h2-*.jar" -o -name "*httpcore*5*.jar" \) 2>/dev/null
'
For Kubernetes, confirm the deployed image and restart state:
kubectl -n your-namespace get deploy your-service \
-o jsonpath='{.spec.template.spec.containers[*].image}{"\n"}'
kubectl -n your-namespace get pods -l app=your-service \
-o custom-columns=NAME:.metadata.name,START:.status.startTime,IMAGE:.spec.containers[*].image
If the service uses a vendor image, request or generate an SBOM. Look for Maven Package URLs like:
pkg:maven/org.apache.httpcomponents.core5/httpcore5-h2@5.4.2
pkg:maven/org.apache.httpcomponents.core5/httpcore5-h2@5.5-beta1
The strongest remediation evidence is a chain:
source dependency updated
-> lockfile or dependency tree confirms fixed selection
-> container image rebuilt
-> deployed image digest changed
-> running pod started after the image update
-> runtime artifact inspection confirms fixed version
Many CVE response failures happen between “merged PR” and “running process.” A repository can be fixed while production still runs last week’s image.
Confirming HTTP/2 exposure without harmful testing
After dependency discovery, determine whether untrusted or semi-trusted HTTP/2 traffic reaches the vulnerable decoder. Use only assets you own or are explicitly authorized to test. The following commands check protocol negotiation; they do not attempt to trigger the vulnerability.
Using curl:
# Replace with a host you own or are authorized to test.
curl --http2 -I --max-time 5 https://your-owned-host.example/
If HTTP/2 is used, curl may show:
HTTP/2 200
Using OpenSSL ALPN:
openssl s_client -alpn h2 -connect your-owned-host.example:443 </dev/null 2>/dev/null \
| grep -i "ALPN protocol"
A negotiated HTTP/2 result looks like:
ALPN protocol: h2
No ALPN negotiation might look like:
No ALPN negotiated
These checks answer only one question: can that listener negotiate HTTP/2? They do not prove that Apache HttpComponents Core handles the traffic. A CDN can negotiate HTTP/2 with users and forward HTTP/1.1 to the origin. A load balancer can accept HTTP/2 and talk HTTP/1.1 downstream. An ingress controller can terminate HTTP/2 and forward HTTP/2 to the service. A service mesh sidecar can convert protocols between hops.
Map the path:
browser or API client
-> CDN or DDoS provider
-> external load balancer
-> ingress controller
-> service mesh gateway
-> sidecar
-> Java service
-> downstream service
At each hop, record:
- Does the hop accept HTTP/2 from the previous peer?
- Does it terminate HTTP/2?
- Does it forward HTTP/1.1 or HTTP/2 downstream?
- Does it enforce decoded header limits?
- Can any route bypass this hop?
- Which process actually contains httpcore5-h2?
A common false positive is “the public hostname supports HTTP/2, and the Java service has httpcore5-h2, therefore it is exploitable.” That may be wrong if the CDN terminates HTTP/2 and the Java service only receives HTTP/1.1. A common false negative is “the CDN terminates HTTP/2, so we are safe.” That may be wrong if internal clients, partner networks, private load balancers, test environments, or service mesh routes can reach the Java process over HTTP/2.
Safe validation workflow

Do not validate CVE-2026-54428 in production by sending oversized compressed header blocks. The expected impact is denial of service through memory exhaustion. A “successful” exploit test may crash the service, cause container OOMKills, trigger autoscaling churn, break SLOs, and violate bug bounty or customer testing rules.
A safe production validation package should include evidence like this:
| Evidence | Safe collection method | What it proves | What it does not prove |
|---|---|---|---|
| Dependency version | Maven, Gradle, SBOM, jar inspection | A vulnerable or fixed artifact exists | Whether traffic reaches it |
| Runtime artifact | Container inspection, classpath, image digest | The running service uses the artifact | Whether every route is covered |
| HTTP/2 listener | ALPN check, ingress config, LB config | A listener supports HTTP/2 | Which process decodes it |
| Protocol path | CDN, LB, ingress, mesh, sidecar config | Where HTTP/2 terminates | Whether a decoder can be memory-exhausted |
| Patch deployment | Build logs, image digest, pod start time | The fix was deployed | Whether old images exist elsewhere |
| Monitoring | JVM, proxy, container, HTTP/2 metrics | Whether symptoms are visible | Whether exploitation occurred |
A strong internal ticket should say something like:
The deployed image registry.example.com/api-gateway@sha256:... contains
org.apache.httpcomponents.core5:httpcore5-h2:5.4.2.
Apache and NVD identify Apache HttpComponents Core httpcore5-h2 5.4.2 and earlier
as affected by CVE-2026-54428, an HTTP/2 HPACK decoder memory exhaustion DoS.
The service accepts HTTP/2 on the partner integration listener through ALPN h2.
The CDN path terminates HTTP/2 before origin, but the partner listener reaches
the Java service directly through an internal load balancer.
Recommended remediation:
- Upgrade httpcore5-h2 to a non-affected release or vendor-supported fixed build.
- Rebuild and redeploy the service image.
- Confirm the running jar version inside the deployed container.
- Apply temporary header and connection limits at the integration edge.
- Do not perform destructive DoS reproduction in production.
That ticket is useful because it gives the owner enough context to act. It does not merely paste a scanner result.
Authorized testing workflows can help collect and preserve this evidence, but they should stay within a safe boundary. Penligent describes an AI-assisted security workflow for vulnerability discovery, verification, tool orchestration, and evidence-based reports, and its site states the product is for authorized security testing only. For a DoS-class issue like CVE-2026-54428, the useful automation path is asset mapping, version confirmation, controlled lab validation, remediation evidence, and retesting, not firing destructive payloads at production. (Penligent)
Safe educational PoC, local toy model only
The following PoC is a local educational model. It is not an exploit for CVE-2026-54428. It does not implement HTTP/2. It does not implement HPACK. It does not create real HEADERS or CONTINUATION frames. It does not connect to any service. It does not provide a payload that can be pointed at production.
The goal is to show the dangerous programming pattern: a compact input expands into a large decoded header-like structure, and the size limit is checked after allocation instead of during allocation.
#!/usr/bin/env python3
"""
Safe local demonstration of a resource-accounting bug pattern.
This is NOT an exploit for CVE-2026-54428.
It does NOT implement HTTP/2.
It does NOT implement HPACK.
It does NOT send traffic.
It only models the difference between late accounting and incremental accounting.
"""
from dataclasses import dataclass
@dataclass
class HeaderField:
name: str
value: str
# A tiny symbolic "compressed" representation.
# In a real compression format, compact tokens can represent repeated structure.
# Here, ("repeat", n, name, value) means "expand into n header-like fields".
toy_encoded_header_block = [
("literal", "method", "GET"),
("literal", "path", "/demo"),
("repeat", 50_000, "x-demo", "A" * 64),
]
def unsafe_decode_then_check(encoded, max_decoded_bytes):
"""
Dangerous pattern:
1. Decode everything into memory.
2. Count decoded size afterward.
3. Reject only after allocation already happened.
"""
decoded = []
for item in encoded:
if item[0] == "literal":
_, name, value = item
decoded.append(HeaderField(name, value))
elif item[0] == "repeat":
_, count, name, value = item
for _ in range(count):
decoded.append(HeaderField(name, value))
decoded_size = sum(len(h.name) + len(h.value) + 32 for h in decoded)
if decoded_size > max_decoded_bytes:
raise ValueError(f"decoded header list too large: {decoded_size} bytes")
return decoded
def safer_decode_with_incremental_limit(encoded, max_decoded_bytes):
"""
Safer pattern:
1. Keep a running decoded-size counter.
2. Check before adding each decoded object.
3. Fail before unbounded allocation.
"""
decoded = []
decoded_size = 0
def add_header(name, value):
nonlocal decoded_size
# RFC 9113's header list size model includes name length,
# value length, and 32 octets of overhead per field line.
field_cost = len(name) + len(value) + 32
if decoded_size + field_cost > max_decoded_bytes:
raise ValueError(
f"decoded header list would exceed limit: "
f"{decoded_size + field_cost} > {max_decoded_bytes}"
)
decoded.append(HeaderField(name, value))
decoded_size += field_cost
for item in encoded:
if item[0] == "literal":
_, name, value = item
add_header(name, value)
elif item[0] == "repeat":
_, count, name, value = item
for _ in range(count):
add_header(name, value)
return decoded
if __name__ == "__main__":
limit = 16 * 1024
print("Running safer decoder first")
try:
safer_decode_with_incremental_limit(toy_encoded_header_block, limit)
except ValueError as exc:
print(f"Safer decoder stopped early: {exc}")
print("\nRunning unsafe decoder")
try:
unsafe_decode_then_check(toy_encoded_header_block, limit)
except ValueError as exc:
print(f"Unsafe decoder rejected too late: {exc}")
Both functions reject the oversized decoded header list. The difference is when they reject it. The unsafe version builds a large object graph first and then checks the limit. The safer version accounts for decoded size before adding each object. Real HPACK decoding is more complex than this toy model, but the defensive principle is the same: limits that run after allocation do not reliably prevent memory exhaustion.
For defenders, the PoC helps explain three points:
- A small input can be expensive after decoding.
- The right unit is decoded field section size, not only wire size.
- The limit has to be active inside the decode path, including early connection state.
Detection signals and false positives
CVE-2026-54428 affects memory availability. Detection therefore needs application telemetry, JVM telemetry, container telemetry, and edge protocol signals. Application request logs alone may miss the issue because the expensive work can happen before normal routing.
| Signal | Why it matters | False positive risk |
|---|---|---|
| Sudden JVM heap growth during HTTP/2 traffic | Directly matches memory pressure from decoded headers | Legitimate load spikes, cache warmups, unrelated leaks |
| Frequent full GC or long GC pauses | Heap pressure often appears before failure | Normal traffic surge or background job |
java.lang.OutOfMemoryError near HTTP/2 handling | Strong crash-level indicator | Other memory bugs can produce the same error |
Kubernetes OOMKilled events | Confirms process exceeded memory limit | Does not identify the triggering request |
| Spike in HTTP/2 connection errors | Decoder or edge may be rejecting bad field blocks | Client bugs, deploys, network instability |
| HTTP 431 responses at edge | Header limits may be firing before origin | Legitimate clients with large cookies or metadata |
| Many resets with low completed request count | Work may happen below application routing | DDoS, mobile network churn, bot traffic |
| HEADERS or CONTINUATION anomalies | Relevant to HTTP/2 field block processing | Requires protocol-aware telemetry |
| Heap dump shows many header-like objects | Useful in controlled incident analysis | Heap dumps may contain sensitive data |
Useful metrics may include:
jvm_memory_used_bytes
jvm_memory_committed_bytes
jvm_gc_pause_seconds_count
process_resident_memory_bytes
container_memory_working_set_bytes
container_oom_events
http2_active_connections
http2_active_streams
http2_connection_errors
http2_compression_errors
ingress_431_responses
load_balancer_reset_count
Metric names differ by framework, ingress controller, service mesh, and exporter. The important distinction is between application-level request metrics and protocol-level connection metrics. If the decoder burns memory before the request becomes an application event, a dashboard built only around route latency and HTTP status codes will be late or blind.
For incident response, collect evidence before it disappears:
# Kubernetes pod-level OOM evidence.
kubectl -n your-namespace describe pod your-pod-name | egrep -i "oom|killed|reason|exit|memory"
# Previous container logs after a restart.
kubectl -n your-namespace logs your-pod-name --previous | egrep -i \
"OutOfMemoryError|http2|hpack|header|compression|connection|431"
Handle heap dumps carefully. They can contain request headers, cookies, bearer tokens, customer data, or internal service metadata. Store them under incident-handling controls, not in ordinary chat channels or public issue trackers.
Mitigation when patching needs time
The primary fix is to upgrade to a non-affected Apache HttpComponents Core release or apply a vendor-supported backport. Temporary controls can reduce exposure while the patch is tested, but they do not remove the vulnerable code path.
| Temporary control | What it reduces | Limitation |
|---|---|---|
| Terminate HTTP/2 at a patched edge proxy | Prevents vulnerable origin from decoding untrusted HTTP/2 | Only works if no bypass route reaches the origin |
| Disable HTTP/2 on affected listener | Removes the vulnerable protocol path | May break gRPC, mobile clients, partner integrations, or service mesh behavior |
| Limit decoded header size at edge | Blocks oversized field sections before origin | Must be enforced at the hop that decodes HTTP/2 |
| Limit header count and individual header value size | Reduces application-visible header expansion | May not cover every HPACK or continuation-frame path |
| Cap concurrent streams | Reduces per-connection amplification | Does not by itself fix oversized header decoding |
| Rate-limit connections per client or identity | Reduces repeated attempts | Attackers may distribute sources |
| Set JVM and container memory limits | Limits blast radius | Can turn memory pressure into repeated restarts |
| Isolate edge parser workloads | Prevents one parser issue from killing unrelated workloads | Requires architecture and deployment changes |
| Add header read and request timeouts | Reduces slow or stalled resource retention | Does not stop rapid allocation bursts |
If you disable HTTP/2, treat it as a change with owners, rollback, and dependency checks. gRPC commonly relies on HTTP/2. Mobile clients may rely on HTTP/2 connection reuse. Service meshes may have assumptions around HTTP/2 routing and observability. Some browser-facing endpoints will tolerate HTTP/1.1 with only latency changes, while internal API paths may not.
A temporary NGINX-style mitigation might look like this, subject to your installed version and configuration model:
server {
listen 443 ssl;
server_name app.example.internal;
# Temporary mitigation only if this build supports the directive.
# Validate client and upstream impact before rollout.
http2 off;
# Existing TLS, proxy, and application settings here.
}
For Apache HTTP Server as an edge proxy, a temporary protocol fallback might look like:
<VirtualHost *:443>
ServerName app.example.internal
# Temporary mitigation only.
# Use a patched stack instead of leaving this permanently disabled.
Protocols http/1.1
SSLEngine on
# Existing TLS and proxy config here.
</VirtualHost>
Do not copy proxy snippets blindly. The vulnerable component in CVE-2026-54428 is Apache HttpComponents Core, not the edge proxy shown in these examples. The examples only illustrate how some teams may temporarily prevent HTTP/2 from reaching an affected backend while they patch.
Why edge termination can help but cannot be assumed
Edge termination is one of the strongest compensating controls when it is real and complete. If a patched CDN or load balancer terminates HTTP/2 and forwards only HTTP/1.1 to the Java service, the origin’s vulnerable HTTP/2 decoder may not be exposed to public clients. But that statement needs proof.
A safe protocol map might look like:
Public client -> CDN: HTTP/2
CDN -> cloud load balancer: HTTP/1.1
Cloud load balancer -> ingress: HTTP/1.1
Ingress -> Java service: HTTP/1.1
A risky alternate route might look like:
Partner client -> private load balancer: HTTP/2
Private load balancer -> Java integration service: HTTP/2
Another risky internal route:
Compromised workload -> service mesh sidecar: HTTP/2
Sidecar -> Java service: HTTP/2
The public hostname may be safe while the partner listener is not. The production environment may be safe while staging is internet-accessible. The main API may be safe while a webhook receiver bypasses the CDN. This is why CVE-2026-54428 belongs in asset and path mapping, not only dependency scanning.
Related CVEs that sharpen the risk model
CVE-2026-54428 is not the first availability issue involving HTTP parsing, HTTP/2 state, or Apache HttpComponents Core. Related CVEs help defenders avoid narrow thinking.
| CVE | Area | Relationship | Main risk | Defender lesson |
|---|---|---|---|---|
| CVE-2026-54428 | Apache HttpComponents Core HTTP/2 HPACK decoder | Main issue | Memory exhaustion before configured header list limit is applied after SETTINGS ACK | Patch httpcore5-h2 and map HTTP/2 exposure |
| CVE-2026-54399 | Apache HttpComponents Core HTTP/1.1 parser | Same project family and similar resource-consumption theme | Memory exhaustion from excessive number of headers or excessive header length | Review both HTTP/1.1 and HTTP/2 parser paths |
| CVE-2023-44487 | HTTP/2 Rapid Reset | Different mechanism, same protocol-layer DoS lesson | Server resource consumption through rapid stream cancellation | HTTP/2 control behavior can be weaponized without RCE |
| CVE-2026-49975 | HTTP/2 header accounting and memory pressure theme | Related HPACK and header-limit risk model | Small header traffic can create expensive server-side state | Count decoded size, retained state, and stream lifetime, not just raw bytes |
CVE-2026-54399 is worth reviewing alongside this issue. Public descriptions characterize it as an uncontrolled resource consumption issue in the HTTP/1.1 message parser in Apache HttpComponents Core, affecting 5.4.2 and earlier and 5.5-beta1 and earlier, where excessive numbers of headers or excessive header length can cause memory exhaustion. That is a different parser path, but the remediation workflow overlaps: update HttpComponents Core, confirm runtime artifacts, and verify edge header limits. (Tenable®)
CVE-2023-44487, known as HTTP/2 Rapid Reset, is also different. It abused HTTP/2 request cancellation and stream reset behavior rather than HPACK header list sizing. NVD describes it as a server resource consumption issue caused by request cancellation resetting many streams quickly, and notes exploitation in the wild from August through October 2023. (NVD) The relevance is strategic: HTTP/2 DoS bugs often hide in connection state, stream state, compression state, or parser behavior rather than in obvious application endpoints.
CVE-2026-49975 is a useful adjacent case for teams studying HTTP/2 header accounting and HPACK-driven memory pressure. Penligent’s write-up describes the broader pattern as cheap client-side header traffic becoming expensive server-side memory state and emphasizes assessing the whole HTTP/2 path across CDN, WAF, load balancer, ingress, service mesh, sidecar, API gateway, and origin server. (Penligent) That path-based thinking applies directly to CVE-2026-54428.
CI guardrails after remediation
Once the patch lands, prevent regression. Dependency issues often reappear through transitive upgrades, internal BOM changes, old service templates, copied Dockerfiles, or vendor package drift.
For Maven, use an Enforcer rule. Adapt the ranges to your internal policy and vendor-backport model:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<id>ban-vulnerable-httpcore5-h2</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<bannedDependencies>
<excludes>
<exclude>org.apache.httpcomponents.core5:httpcore5-h2:(,5.4.3)</exclude>
<exclude>org.apache.httpcomponents.core5:httpcore5-h2:5.5-alpha1</exclude>
<exclude>org.apache.httpcomponents.core5:httpcore5-h2:5.5-beta1</exclude>
</excludes>
</bannedDependencies>
</rules>
<fail>true</fail>
</configuration>
</execution>
</executions>
</plugin>
For Gradle:
configurations.all {
resolutionStrategy.eachDependency { details ->
if (details.requested.group == "org.apache.httpcomponents.core5" &&
details.requested.name == "httpcore5-h2") {
def badVersions = ["5.5-alpha1", "5.5-beta1"]
if (badVersions.contains(details.requested.version)) {
throw new GradleException(
"Blocked vulnerable httpcore5-h2 version ${details.requested.version}"
)
}
}
}
}
For SBOM policy, express the rule in the language your tool supports. The logic should capture both stable and prerelease lines:
block if:
package.type == "maven"
package.group == "org.apache.httpcomponents.core5"
package.name == "httpcore5-h2"
and (
version <= "5.4.2"
or version == "5.5-alpha1"
or version == "5.5-beta1"
)
Be careful with prerelease comparison. Many tools handle semantic versions poorly when alpha and beta strings are involved. Explicit rules are safer than assuming a generic comparator understands Maven prerelease ordering.
Incident response playbook
If CVE-2026-54428 appears during an outage investigation, start with containment and evidence preservation. Do not generate new DoS traffic.
A reasonable response sequence:
1. Identify services containing affected httpcore5-h2 versions.
2. Identify which of those services receive HTTP/2 from untrusted or semi-trusted peers.
3. If an exposed vulnerable path exists, reduce exposure:
- route through a patched edge,
- disable HTTP/2 temporarily where safe,
- tighten header and connection limits,
- isolate the affected workload.
4. Preserve logs, image digests, dependency evidence, OOM events, and GC data.
5. Upgrade or apply vendor-supported backport.
6. Rebuild and redeploy.
7. Confirm runtime artifact and restart time.
8. Review traffic patterns to determine whether the event was likely attempted exploitation,
load anomaly, client bug, or unrelated memory failure.
9. Add CI and observability guardrails.
For evidence collection:
# Show recent pod events.
kubectl -n your-namespace get events --sort-by=.lastTimestamp | tail -50
# Look for restart reasons.
kubectl -n your-namespace describe pod your-pod-name | egrep -i \
"Restart|OOM|Killed|Exit Code|Reason|Memory"
# Capture deployed image and image ID.
kubectl -n your-namespace get pod your-pod-name \
-o jsonpath='{.status.containerStatuses[*].imageID}{"\n"}'
For Java services, if GC logs are enabled, look for sudden heap growth, repeated full GC, allocation failures, and failures to reclaim memory. If GC logs are not enabled, consider adding them as part of normal hardening, not only during the incident.
Operational hardening that remains useful after patching
A fixed decoder removes this specific bug, but parser-layer resource limits should stay. HTTP/2 has legitimate features that can still create pressure when abused. RFC 9113’s denial-of-service considerations note that HTTP/2 connections can require greater resource commitments than HTTP/1.1, and that field section compression and flow control depend on state. The RFC also warns that limits in SETTINGS cannot be reduced instantaneously and that immediately after connection establishment, server limits may not be known to clients. (IETF Datatracker)
A hardened HTTP/2 edge should define and monitor:
- Maximum decoded field section size
- Maximum number of header fields
- Maximum individual header value size where supported
- Maximum number of CONTINUATION frames
- Maximum concurrent streams
- Connection idle timeout
- Header read timeout
- Request body timeout
- Per-client connection limits
- Per-client or per-identity rate limits
- Memory limits for parser-facing workloads
- Alerting on OOMKilled and abnormal GC pressure
Avoid unlimited defaults in parser-facing components. “Unlimited” often means “the peer decides.” In public, partner, or multi-tenant environments, that is not a safe resource policy.
Common mistakes
The most common mistake is assigning the issue to the wrong team because of the word Apache. CVE-2026-54428 is about Apache HttpComponents Core, a Java HTTP library, not Apache HTTP Server.
The second mistake is assuming a scanner hit equals exploitable production exposure. A vulnerable dependency is important evidence, but runtime and protocol path determine urgency.
The third mistake is assuming a CDN removes all risk. It may remove public HTTP/2 exposure to the origin, but internal routes, partner paths, private load balancers, service mesh traffic, and test environments may still reach the Java process over HTTP/2.
The fourth mistake is validating with a destructive production test. A denial-of-service vulnerability should not be proven by causing denial of service. Use version, runtime, and exposure evidence for production triage. Use an isolated lab for behavioral reproduction.
The fifth mistake is patching the source repository but not the running image. Confirm the deployed artifact and restart time.
The sixth mistake is treating availability as a minor security property. For APIs, login flows, checkout systems, telemetry collectors, SaaS control planes, and security tooling, availability is part of the security boundary.
FAQ
What is CVE-2026-54428 in plain English?
- CVE-2026-54428 is a denial-of-service vulnerability in Apache HttpComponents Core’s HTTP/2 HPACK decoder.
- It affects the Maven artifact
org.apache.httpcomponents.core5:httpcore5-h2in vulnerable version ranges. - The bug allows memory exhaustion when oversized compressed HTTP/2 header blocks are processed before the configured header list size limit is applied after SETTINGS acknowledgement.
- The main impact is service availability loss.
Is CVE-2026-54428 remote code execution?
- No authoritative source describes CVE-2026-54428 as remote code execution.
- NVD’s CVSS vector shows no confidentiality impact and no integrity impact, but high availability impact.
- Reports should describe it as remote unauthenticated denial of service when the vulnerable HTTP/2 decoder is reachable.
- Overstating it as RCE can slow remediation because engineers will distrust the finding.
Which package should I check?
- Check
org.apache.httpcomponents.core5:httpcore5-h2. - Review Maven, Gradle, SBOM, jar, container image, and runtime classpath evidence.
- Do not stop at direct dependencies; transitive dependencies can introduce the artifact.
- Confirm deployed artifacts, because source repositories and running containers often differ.
How do I know whether my service is exposed?
- Confirm the service runs an affected
httpcore5-h2version. - Confirm HTTP/2 traffic can reach the process that loads that artifact.
- Map CDN, WAF, load balancer, ingress, service mesh, sidecar, and origin behavior.
- Check alternate routes such as partner endpoints, internal listeners, staging systems, and direct origin access.
- Treat outbound clients as relevant if they receive HTTP/2 responses from untrusted or user-controlled peers.
Can I test CVE-2026-54428 safely in production?
- Do not send oversized compressed header blocks to production.
- The expected impact is memory exhaustion, so a successful exploit test can cause an outage.
- Use non-destructive evidence: vulnerable version, runtime artifact, HTTP/2 exposure, and official advisory mapping.
- Behavioral testing belongs in an isolated lab with explicit authorization and resource limits.
What should I do if I cannot upgrade immediately?
- Route traffic through a patched edge that terminates HTTP/2 before the vulnerable service.
- Disable HTTP/2 temporarily on affected listeners if application dependencies allow it.
- Enforce header size, header count, stream, connection, and timeout limits at the edge.
- Set JVM and container memory limits to reduce blast radius.
- Monitor heap pressure, GC pauses, OOM events, HTTP/2 errors, and 431 responses.
- Treat all of these as temporary controls, not a substitute for patching.
How is CVE-2026-54428 different from HTTP/2 Rapid Reset?
- CVE-2026-54428 involves Apache HttpComponents Core’s HPACK decoder and header list size limit timing.
- CVE-2023-44487, Rapid Reset, involves HTTP/2 stream cancellation and rapid reset behavior.
- Both are denial-of-service issues, but the abused protocol mechanisms differ.
- The shared lesson is that HTTP/2 security requires connection-level and protocol-level resource controls, not only application-layer validation.
Closing judgment
CVE-2026-54428 is not the loudest kind of vulnerability, but it sits in a place defenders cannot ignore: the HTTP/2 decoding path before normal application logic. The fix path is straightforward if the team stays precise. Find httpcore5-h2. Confirm the running version. Map whether HTTP/2 reaches that process. Upgrade or apply a supported backport. Avoid destructive production tests. Keep protocol-layer memory, header, stream, and connection limits in place after the immediate patch, because the next HTTP parser bug will not wait for the application layer either.
