GHSA-CJCG-CXMH-9WCR
Vulnerability from github – Published: 2026-10-02 23:09 – Updated: 2026-10-02 23:09Summary
Multiple denial-of-service vulnerabilities have been discovered in HTTP/2 server implementations. All have been rated with a severity impact of Important. 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 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 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
{
"affected": [
{
"package": {
"ecosystem": "crates.io",
"name": "praxis-proxy"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.5.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-409"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-02T23:09:37Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Summary\n\nMultiple 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. \n\n### Details\n\nCredit to the original researcher, I\u0027m mostly just run their tool against the code base.\n\n[Security Bulletins](https://access.redhat.com/security/vulnerabilities/RHSB-2026-007): https://access.redhat.com/security/vulnerabilities/RHSB-2026-007 \nExploit details: https://blog.calif.io/p/codex-discovered-a-hidden-http2-bomb\n\nThis 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.\u00a0(edited)\n\n### PoC\n\n* Generate certificates\n```\nopenssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -keyout server.key -out server.crt -days 3650 -nodes -subj \"/CN=localhost\"\n```\n\n* Create praxis config as follow\n\n```\nlisteners:\n - name: web\n address: \"0.0.0.0:8443\"\n tls:\n certificates:\n - cert_path: /etc/praxis/server.crt\n key_path: /etc/praxis/server.key\n filter_chains: [main]\n\nfilter_chains:\n - name: main\n filters:\n - filter: router\n routes:\n - path_prefix: \"/\"\n host: \"example.api.com\"\n cluster: backend\n - filter: load_balancer\n clusters:\n - name: backend\n endpoints:\n - \"httpbingo.org:443\"\n tls:\n verify: false\n```\n\n* Start the container\n\n```\ndocker 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\n```\n\n* Check container memory\n\n```\n$ docker stats\n\nCONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS\n362cfa472792 praxis 0.00% 6.473MiB / 62.49GiB 0.01% 7.57kB / 126B 0B / 0B 22\n```\n\n* In another terminal run the attack\n\n```\n./hpack_bomb.py --host 127.0.0.1 --port 8443 -n 10\n```\n\n* Observer the container memory\n\n```\n98b040c5e5ad praxis 0.13% 687.1MiB / 62.49GiB 1.07% 41.6MB / 362kB 0B / 0B 23\n```\n\nMemory usage spiked to around 700MB, and even after the attack ended, the memory was not freed up.\n* Patch the code to set h2options\n\n```\ndiff --git a/protocol/src/http/pingora/handler/mod.rs b/protocol/src/http/pingora/handler/mod.rs\nindex dc684ad..fc59234 100644\n--- a/protocol/src/http/pingora/handler/mod.rs\n+++ b/protocol/src/http/pingora/handler/mod.rs\n@@ -18,6 +18,7 @@ use std::{collections::HashMap, sync::Arc, time::Duration};\n\n use arc_swap::ArcSwap;\n use bytes::Bytes;\n+use pingora_core::protocols::http::v2::server::H2Options;\n use pingora_core::{Result, apps::HttpServerOptions, server::Server, services::listening::Service};\n use pingora_proxy::{Session, http_proxy};\n use praxis_core::{config::ABSOLUTE_MAX_BODY_BYTES, connectivity::Upstream};\n@@ -151,6 +152,11 @@ where\n let service_name = format!(\"http-proxy:{name}\", name = listener.name);\n let mut proxy = http_proxy(\u0026server.configuration, handler);\n proxy.server_options = Some(h2c_server_options());\n+ let mut h2_options = H2Options::new();\n+ h2_options.max_header_list_size(65536);\n+ h2_options.max_concurrent_streams(32);\n+ proxy.h2_options = Some(h2_options);\n+\n let mut service = Service::new(service_name, proxy);\n if let Some(tx) = super::listener::add_listener(\u0026mut service, listener)? {\n cert_watcher_shutdowns.push(tx);\n```\n\n* Rerun the attack, the memory usage looks a lot better now\n\n```\nCONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS\nb1c82abca409 praxis 0.04% 10.09MiB / 62.49GiB 0.02% 1.16MB / 23.4kB 950kB / 0B 23\n```",
"id": "GHSA-cjcg-cxmh-9wcr",
"modified": "2026-10-02T23:09:37Z",
"published": "2026-10-02T23:09:37Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/praxis-proxy/praxis/security/advisories/GHSA-cjcg-cxmh-9wcr"
},
{
"type": "WEB",
"url": "https://github.com/praxis-proxy/praxis/commit/2bb7b29d6992fc2d8045628475912d734e6bee97"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/vulnerabilities/RHSB-2026-007"
},
{
"type": "WEB",
"url": "https://blog.calif.io/p/codex-discovered-a-hidden-http2-bomb"
},
{
"type": "PACKAGE",
"url": "https://github.com/praxis-proxy/praxis"
},
{
"type": "WEB",
"url": "https://github.com/praxis-proxy/praxis/releases/tag/v0.5.2"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "Praxis affected by HTTP/2 Bomb "
}
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
Loading timeline…
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.