# GHSA-cjcg-cxmh-9wcr: Praxis affected by HTTP/2 Bomb

> Remote attackers can cause denial of service in Praxis proxy by sending crafted HTTP/2 requests that trigger excessive memory allocation.

- **Severity:** Not scored
- **Exploited in the wild:** Not known
- **Login needed:** Not needed
- **Attackable:** Over the internet
- **Victim action needed:** Not needed
- **Fix available:** Yes
- **Published:** 2 Oct 2026

## What is GHSA-cjcg-cxmh-9wcr?

GHSA-cjcg-cxmh-9wcr is a denial of service vulnerability in praxis-proxy, published on 2 Oct 2026. An attacker can exploit it over the internet without logging in, with no action from the victim.

### Official description

### 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
```

## Which versions are affected by GHSA-cjcg-cxmh-9wcr?

2 open source packages ship an affected version, including praxis-proxy.


| Package | Ecosystem | Affected | Fixed in |
| --- | --- | --- | --- |
| `praxis-proxy` | crates.io | All versions | 0.5.2 |
| `praxis-proxy` | crates.io | All versions | 0.5.2 |

## How do I fix GHSA-cjcg-cxmh-9wcr?

Upgrade praxis-proxy to 0.5.2 or later.

## Is GHSA-cjcg-cxmh-9wcr being exploited?

There is no known exploitation of GHSA-cjcg-cxmh-9wcr in the wild and no public exploit code.

## Fix prompt for AI coding agents

```text
Check this codebase for GHSA-cjcg-cxmh-9wcr and fix it if it is affected.

What it is: GHSA-cjcg-cxmh-9wcr is a denial of service vulnerability in praxis-proxy, published on 2 Oct 2026. An attacker can exploit it over the internet without logging in, with no action from the victim.
Exploitation: There is no known exploitation of GHSA-cjcg-cxmh-9wcr in the wild and no public exploit code.

Affected packages and fixed versions:
- praxis-proxy (crates.io): affected all versions; fixed in 0.5.2
- praxis-proxy (crates.io): affected all versions; fixed in 0.5.2

Task:
1. Search the dependency manifests and lockfiles (for example package.json, package-lock.json, requirements.txt, poetry.lock, uv.lock, pom.xml, build.gradle, go.mod, Cargo.lock, Gemfile.lock) and any Dockerfiles for the affected packages, including transitive dependencies.
2. If an affected version is in use, upgrade it to the fixed version for its release line with the project's package manager, so the lockfile is regenerated. Prefer the smallest upgrade that fixes it.
3. If there is no fix, or the upgrade would break the build, do not guess: explain the risk and the safest workaround instead.
4. Run the tests and summarise what changed and why.
5. If nothing in the project is affected, say so and change nothing.

Reference: https://insights.sbomify.com/GHSA-cjcg-cxmh-9wcr/ (Markdown: https://insights.sbomify.com/GHSA-cjcg-cxmh-9wcr/index.md)
```

## Sources

- OSV: https://osv.dev/vulnerability/GHSA-cjcg-cxmh-9wcr

---
From sbomify Insights: https://insights.sbomify.com/GHSA-cjcg-cxmh-9wcr/
Summaries are generated and may contain mistakes; the official description above is the record.
