GHSA-cjcg-cxmh-9wcr

GHSA-cjcg-cxmh-9wcr HIGH
Published October 2, 2026

### Summary Multiple denial-of-service vulnerabilities have been discovered in HTTP/2 server implementations. All have been rated with a severity impact of [Important](https://access.redhat.com/security/updates/classification). The vulnerabilities target HPACK, the header compression scheme in...

Full CISO analysis pending enrichment.

What systems are affected?

Package Ecosystem Vulnerable Range Patched
H2O cargo < 0.5.2 0.5.2
7.5K OpenSSF 5.7 27 dependents Pushed 7d ago 8% patched ~0d to patch Full package profile →

Do you use H2O? You're affected.

How severe is it?

CVSS 3.1
7.5 / 10
EPSS
N/A
Exploitation Status
No known exploitation
Sophistication
N/A

What is the attack surface?

AV AC PR UI S C I A
AV Network
AC Low
PR None
UI None
S Unchanged
C None
I None
A High

What should I do?

Patch available

Update H2O to version 0.5.2

Which compliance frameworks are affected?

Compliance analysis pending. Sign in for full compliance mapping when available.

Frequently Asked Questions

What is GHSA-cjcg-cxmh-9wcr?

### Summary Multiple denial-of-service vulnerabilities have been discovered in HTTP/2 server implementations. All have been rated with a severity impact of [Important](https://access.redhat.com/security/updates/classification). The vulnerabilities target HPACK, the header compression scheme in HTTP/2, where a small request can trigger large memory allocations on the server. ### Details Credit to the original researcher, I'm mostly just run their tool against the code base. [Security Bulletins](https://access.redhat.com/security/vulnerabilities/RHSB-2026-007): https://access.redhat.com/security/vulnerabilities/RHSB-2026-007 Exploit details: https://blog.calif.io/p/codex-discovered-a-hidden-http2-bomb This bug was fixed in upstream pingora v0.8.1, but our fork (v0.8.2) is missing this important [PR](https://github.com/praxis-proxy/pingora/commit/d193c8d49b8b7c1c1ede93183759caa4f6906bbd) to set the default h2 options. (edited) ### PoC * Generate certificates ``` openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -keyout server.key -out server.crt -days 3650 -nodes -subj "/CN=localhost" ``` * Create praxis config as follow ``` listeners: - name: web address: "0.0.0.0:8443" tls: certificates: - cert_path: /etc/praxis/server.crt key_path: /etc/praxis/server.key filter_chains: [main] filter_chains: - name: main filters: - filter: router routes: - path_prefix: "/" host: "example.api.com" cluster: backend - filter: load_balancer clusters: - name: backend endpoints: - "httpbingo.org:443" tls: verify: false ``` * Start the container ``` docker run --name praxis --user $(id -u):$(id -g) -it --rm -p 8443:8443 -v ./config.yaml:/etc/praxis/config.yaml -v ./server.crt:/etc/praxis/server.crt -v ./server.key:/etc/praxis/server.key ghcr.io/praxis-proxy/praxis:0.5.1 ``` * Check container memory ``` $ docker stats CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 362cfa472792 praxis 0.00% 6.473MiB / 62.49GiB 0.01% 7.57kB / 126B 0B / 0B 22 ``` * In another terminal run the attack ``` ./hpack_bomb.py --host 127.0.0.1 --port 8443 -n 10 ``` * Observer the container memory ``` 98b040c5e5ad praxis 0.13% 687.1MiB / 62.49GiB 1.07% 41.6MB / 362kB 0B / 0B 23 ``` Memory usage spiked to around 700MB, and even after the attack ended, the memory was not freed up. * Patch the code to set h2options ``` diff --git a/protocol/src/http/pingora/handler/mod.rs b/protocol/src/http/pingora/handler/mod.rs index dc684ad..fc59234 100644 --- a/protocol/src/http/pingora/handler/mod.rs +++ b/protocol/src/http/pingora/handler/mod.rs @@ -18,6 +18,7 @@ use std::{collections::HashMap, sync::Arc, time::Duration}; use arc_swap::ArcSwap; use bytes::Bytes; +use pingora_core::protocols::http::v2::server::H2Options; use pingora_core::{Result, apps::HttpServerOptions, server::Server, services::listening::Service}; use pingora_proxy::{Session, http_proxy}; use praxis_core::{config::ABSOLUTE_MAX_BODY_BYTES, connectivity::Upstream}; @@ -151,6 +152,11 @@ where let service_name = format!("http-proxy:{name}", name = listener.name); let mut proxy = http_proxy(&server.configuration, handler); proxy.server_options = Some(h2c_server_options()); + let mut h2_options = H2Options::new(); + h2_options.max_header_list_size(65536); + h2_options.max_concurrent_streams(32); + proxy.h2_options = Some(h2_options); + let mut service = Service::new(service_name, proxy); if let Some(tx) = super::listener::add_listener(&mut service, listener)? { cert_watcher_shutdowns.push(tx); ``` * Rerun the attack, the memory usage looks a lot better now ``` CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS b1c82abca409 praxis 0.04% 10.09MiB / 62.49GiB 0.02% 1.16MB / 23.4kB 950kB / 0B 23 ```

Is GHSA-cjcg-cxmh-9wcr actively exploited?

No confirmed active exploitation of GHSA-cjcg-cxmh-9wcr has been reported, but organizations should still patch proactively.

How to fix GHSA-cjcg-cxmh-9wcr?

Update to patched version: H2O 0.5.2.

What is the CVSS score for GHSA-cjcg-cxmh-9wcr?

GHSA-cjcg-cxmh-9wcr has a CVSS v3.1 base score of 7.5 (HIGH).

What are the technical details?

Original Advisory

### Summary Multiple denial-of-service vulnerabilities have been discovered in HTTP/2 server implementations. All have been rated with a severity impact of [Important](https://access.redhat.com/security/updates/classification). The vulnerabilities target HPACK, the header compression scheme in HTTP/2, where a small request can trigger large memory allocations on the server. ### Details Credit to the original researcher, I'm mostly just run their tool against the code base. [Security Bulletins](https://access.redhat.com/security/vulnerabilities/RHSB-2026-007): https://access.redhat.com/security/vulnerabilities/RHSB-2026-007 Exploit details: https://blog.calif.io/p/codex-discovered-a-hidden-http2-bomb This bug was fixed in upstream pingora v0.8.1, but our fork (v0.8.2) is missing this important [PR](https://github.com/praxis-proxy/pingora/commit/d193c8d49b8b7c1c1ede93183759caa4f6906bbd) to set the default h2 options. (edited) ### PoC * Generate certificates ``` openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -keyout server.key -out server.crt -days 3650 -nodes -subj "/CN=localhost" ``` * Create praxis config as follow ``` listeners: - name: web address: "0.0.0.0:8443" tls: certificates: - cert_path: /etc/praxis/server.crt key_path: /etc/praxis/server.key filter_chains: [main] filter_chains: - name: main filters: - filter: router routes: - path_prefix: "/" host: "example.api.com" cluster: backend - filter: load_balancer clusters: - name: backend endpoints: - "httpbingo.org:443" tls: verify: false ``` * Start the container ``` docker run --name praxis --user $(id -u):$(id -g) -it --rm -p 8443:8443 -v ./config.yaml:/etc/praxis/config.yaml -v ./server.crt:/etc/praxis/server.crt -v ./server.key:/etc/praxis/server.key ghcr.io/praxis-proxy/praxis:0.5.1 ``` * Check container memory ``` $ docker stats CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 362cfa472792 praxis 0.00% 6.473MiB / 62.49GiB 0.01% 7.57kB / 126B 0B / 0B 22 ``` * In another terminal run the attack ``` ./hpack_bomb.py --host 127.0.0.1 --port 8443 -n 10 ``` * Observer the container memory ``` 98b040c5e5ad praxis 0.13% 687.1MiB / 62.49GiB 1.07% 41.6MB / 362kB 0B / 0B 23 ``` Memory usage spiked to around 700MB, and even after the attack ended, the memory was not freed up. * Patch the code to set h2options ``` diff --git a/protocol/src/http/pingora/handler/mod.rs b/protocol/src/http/pingora/handler/mod.rs index dc684ad..fc59234 100644 --- a/protocol/src/http/pingora/handler/mod.rs +++ b/protocol/src/http/pingora/handler/mod.rs @@ -18,6 +18,7 @@ use std::{collections::HashMap, sync::Arc, time::Duration}; use arc_swap::ArcSwap; use bytes::Bytes; +use pingora_core::protocols::http::v2::server::H2Options; use pingora_core::{Result, apps::HttpServerOptions, server::Server, services::listening::Service}; use pingora_proxy::{Session, http_proxy}; use praxis_core::{config::ABSOLUTE_MAX_BODY_BYTES, connectivity::Upstream}; @@ -151,6 +152,11 @@ where let service_name = format!("http-proxy:{name}", name = listener.name); let mut proxy = http_proxy(&server.configuration, handler); proxy.server_options = Some(h2c_server_options()); + let mut h2_options = H2Options::new(); + h2_options.max_header_list_size(65536); + h2_options.max_concurrent_streams(32); + proxy.h2_options = Some(h2_options); + let mut service = Service::new(service_name, proxy); if let Some(tx) = super::listener::add_listener(&mut service, listener)? { cert_watcher_shutdowns.push(tx); ``` * Rerun the attack, the memory usage looks a lot better now ``` CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS b1c82abca409 praxis 0.04% 10.09MiB / 62.49GiB 0.02% 1.16MB / 23.4kB 950kB / 0B 23 ```

Weaknesses (CWE)

CWE-409 — Improper Handling of Highly Compressed Data (Data Amplification): The product does not handle or incorrectly handles a compressed input with a very high compression ratio that produces a large output.

Source: MITRE CWE corpus.

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Timeline

Published
October 2, 2026
Last Modified
October 2, 2026
First Seen
October 3, 2026

Related Vulnerabilities