GHSA-cjcg-cxmh-9wcr: High severity rust/praxis-proxy vulnerability
Summary
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 ecparamgencurve: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: - certpath: /etc/praxis/server.crt keypath: /etc/praxis/server.key filterchains: [main]
filterchains: - name: main filters: - filter: router routes: - pathprefix: "/" host: "example.api.com" cluster: backend - filter: loadbalancer 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
./hpackbomb.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 arcswap::ArcSwap; use bytes::Bytes; +use pingoracore::protocols::http::v2::server::H2Options; use pingoracore::{Result, apps::HttpServerOptions, server::Server, services::listening::Service}; use pingoraproxy::{Session, httpproxy}; use praxiscore::{config::ABSOLUTEMAXBODYBYTES, connectivity::Upstream}; @@ -151,6 +152,11 @@ where let servicename = format!("http-proxy:{name}", name = listener.name); let mut proxy = httpproxy(&server.configuration, handler); proxy.serveroptions = Some(h2cserveroptions()); + let mut h2options = H2Options::new(); + h2options.maxheaderlistsize(65536); + h2options.maxconcurrentstreams(32); + proxy.h2options = Some(h2options); + let mut service = Service::new(servicename, proxy); if let Some(tx) = super::listener::addlistener(&mut service, listener)? { certwatchershutdowns.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 Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
rust/praxis-proxyto a version that resolves this vulnerability.Fixed in 0.5.2 - Upgrade
Upgrade
pingorato a version that resolves this vulnerability.Fixed in 0.8.1 - Configuration
Set the default HTTP/2 options to a maximum of 32 concurrent streams and a maximum header list size of 65536.
Pingora HTTP/2 server H2Options.max_concurrent_streams and H2Options.max_header_list_size = max_concurrent_streams(32); max_header_list_size(65536)
Event History
Frequently Asked Questions
What access does an attacker need to trigger this issue?
An attacker can target an exposed HTTP/2 server remotely with a crafted HTTP/2 request. The reported vector requires no privileges or user interaction, and a small request can cause large server-side memory allocations.
Are deployments using default HTTP/2 settings at risk?
The advisory states that the praxis-proxy Pingora fork at v0.8.2 is missing the change that sets the default HTTP/2 options. Deployments should not assume the default HTTP/2 configuration includes the needed protection.
How can I identify potentially affected deployments?
Identify instances using rust/praxis-proxy and determine whether they use the Pingora fork described as v0.8.2 without the referenced default-HTTP/2-options change. The upstream Pingora fix is stated to be in v0.8.1.