CVE-2026-16028 Overview
CVE-2026-16028 is a memory leak vulnerability in the Perl module Protocol::HTTP2 before version 1.14. The flaw allows a remote peer to exhaust server or client memory by opening and closing HTTP/2 streams on a single connection. Each closed stream retains roughly 920 bytes of residual state that is never removed from the connection stream table. The SETTINGS_MAX_CONCURRENT_STREAMS limit does not mitigate the issue because the growth comes from streams already released by the concurrency cap. The vulnerability is categorized under [CWE-401] Missing Release of Memory After Effective Lifetime.
Critical Impact
A remote attacker can send approximately 19 bytes per stream to force about 88 MiB of retained memory per 100,000 sequential streams on one connection, leading to denial of service.
Affected Products
- Protocol::HTTP2 for Perl, versions prior to 1.14
- Perl servers built on Protocol::HTTP2 accepting HTTP/2 connections
- Perl clients using Protocol::HTTP2 against untrusted HTTP/2 servers
Discovery Timeline
- 2026-09-07 - CVE-2026-16028 published to NVD
- 2026-09-07 - Vulnerability disclosed on the Openwall OSS-Security mailing list
- 2026-09-08 - Last updated in NVD database
Technical Details for CVE-2026-16028
Vulnerability Analysis
The vulnerability resides in the Protocol::HTTP2 distribution's stream lifecycle handling. When an HTTP/2 stream transitions to the CLOSED state, the stream_state routine returns the concurrency slot and clears most of the stream's keys. The stream entry itself remains in the connection's streams hash, and no code path removes it.
HTTP/2 stream identifiers increase monotonically, so a peer can indefinitely open and close streams on a single connection. Each close leaves a residual entry retained for the connection's lifetime. Measurements against a server built on the module show roughly 920 bytes retained per closed stream against about 19 bytes on the wire, an amplification factor of approximately 48x.
Root Cause
The root cause is missing cleanup of stream table entries after stream closure. The SETTINGS_MAX_CONCURRENT_STREAMS setting caps live streams but does not bound total closed-stream retention. Growth accumulates while concurrency never exceeds one. Both server and client code paths share the same table structure and are vulnerable in either role.
Attack Vector
An unauthenticated remote attacker opens a single HTTP/2 connection and issues a long sequence of ordinary requests that the application accepts and completes. Because each closed stream leaves a residual entry, resident memory grows linearly with the request count. A hostile server can apply the same technique against a Perl client using the module. The requests themselves are well-formed, making the traffic difficult to distinguish from legitimate high-volume clients.
The patch introduces a bounded closed_streams array and a PH2_MAX_CLOSED_STREAMS constant set to 65,535, capping the retained history.
type => $type,
streams => {},
+ closed_streams => [],
+ max_closed_streams => PH2_MAX_CLOSED_STREAMS,
last_stream => $type == CLIENT ? 1 : 2,
last_peer_stream => 0,
Source: GitHub Patch Commit 27a488a
SETTINGS_MAX_FRAME_SIZE => 5,
SETTINGS_MAX_HEADER_LIST_SIZE => 6,
+ # Protocol::HTTP2 Settings
+ PH2_MAX_CLOSED_STREAMS => 65_535
+
};
require Exporter;
Source: GitHub Patch Commit 27a488a
Detection Methods for CVE-2026-16028
Indicators of Compromise
- Single HTTP/2 connection with an unusually high monotonically increasing stream identifier count
- Perl process resident memory growth correlated with active HTTP/2 connections rather than request rate
- Long-lived HTTP/2 connections issuing thousands of small, sequential requests
Detection Strategies
- Instrument HTTP/2 endpoints to record the highest stream ID observed per connection and alert when it exceeds an operational baseline.
- Track resident set size (RSS) of Perl worker processes against HTTP/2 connection counts to identify per-connection accumulation.
- Compare bytes-in against memory growth to detect the ~48x amplification signature described in the advisory.
Monitoring Recommendations
- Enable process-level memory telemetry on hosts running Protocol::HTTP2 and forward metrics to a centralized platform.
- Review reverse-proxy or load-balancer logs for connections with abnormally high request counts before reaching the origin.
- Correlate application memory pressure events with peer IP addresses and connection duration.
How to Mitigate CVE-2026-16028
Immediate Actions Required
- Upgrade Protocol::HTTP2 to version 1.14 or later on all systems where the module is installed.
- Inventory Perl applications and dependencies using cpanm --showdeps or cpan-outdated to identify affected deployments.
- Restart services after upgrade to release accumulated memory from long-running connections.
Patch Information
The fix is available in Protocol::HTTP2 version 1.14, published on MetaCPAN. The patch commit 27a488a34d74fd16f123e5e6186d4f677faa246f introduces a bounded closed_streams array with a default cap of 65,535 entries through the new PH2_MAX_CLOSED_STREAMS constant. See the MetaCPAN Changes List and the original Openwall OSS-Security Post for full details.
Workarounds
- Place a hardened HTTP/2-aware reverse proxy in front of Perl applications to terminate and re-issue HTTP/2 connections at bounded intervals.
- Configure connection lifetime limits or maximum request-per-connection thresholds at the proxy layer to force periodic teardown.
- Restrict HTTP/2 access to trusted clients where feasible until the upgrade to 1.14 is deployed.
# Upgrade Protocol::HTTP2 to the patched release
cpanm Protocol::HTTP2@1.14
# Verify the installed version
perl -MProtocol::HTTP2 -e 'print "$Protocol::HTTP2::VERSION\n"'
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

