Project

General

Profile

Actions

Bug #8410

open

http2: response_frame_size is never set

Added by Philippe Antoine 6 days ago. Updated about 17 hours ago.

Status:
Resolved
Priority:
Normal
Target version:
Affected Versions:
Effort:
Difficulty:
Label:

Description

request_frame_size is set whatever the direction

Setting request_frame_size when we should set response_frame_size leads to FN

Submitted report:

[Summary]
`HTTP2State::parse_frames()` is called for both ToServer and ToClient directions, but unconditionally writes remaining frame bytes to `self.request_frame_size` (line 1153 of `rust/src/http2/http2.rs`). When a large (>=65536 bytes) server-to-client DATA frame is partially delivered, the remaining byte count is stored in `request_frame_size` instead of `response_frame_size`. On the next client-to-server data delivery, `parse_ts()` consumes `request_frame_size` bytes and discards them, causing all subsequent client HTTP/2 requests to be silently dropped from parsing and inspection.

[Root Cause]
`HTTP2State` maintains two fields for tracking remaining bytes of partially-delivered large frames:

```rust
// rust/src/http2/http2.rs:567-568
pub struct HTTP2State {
request_frame_size: u32, // used by parse_ts() at line 1343
response_frame_size: u32, // used by parse_tc() at line 1369
...
}
```

`parse_ts()` (ToServer) checks and consumes `self.request_frame_size` at lines 1343-1352. `parse_tc()` (ToClient) checks and consumes `self.response_frame_size` at lines 1369-1378. Both call the shared `parse_frames()` method.

Inside `parse_frames()`, when a frame with `length >= HTTP2_MAX_HANDLED_FRAME_SIZE` (65536) arrives partially (the available data contains at least `HTTP2_MIN_HANDLED_FRAME_SIZE` (256) bytes but not the full frame), line 1153 executes:

```rust
// rust/src/http2/http2.rs:1153
self.request_frame_size = head.length - (rem.len() as u32);
```

This always writes to `request_frame_size`, even when `parse_frames()` was called from `parse_tc()` with `dir Direction::ToClient`. The correct behavior would be:

```rust
if dir Direction::ToServer {
self.request_frame_size = head.length - (rem.len() as u32);
} else {
self.response_frame_size = head.length - (rem.len() as u32);
}
```

[PoC]
Please extract the attached compressed file and proceed.

1. docker build -t poc .
2. docker run --rm poc
스크린샷 2026-03-24 오후 9.51.45.png

[Impact]
- All client requests following a large server response are invisible to Suricata's detection engine. HTTP-based signature rules (`http.uri`, `http.method`, `http.request_header`, etc.) fail to match.
- This is trivially exploitable by any server an attacker controls. HTTP/2 responses >= 64KB are extremely common in normal web traffic.
- HTTP/2 is enabled by default in Suricata (`app-layer.protocols.http2.enabled: yes`).

[Affected Version]
  • Current `main` branch (commit bc4a055e7, Suricata 9.0.0-dev) is confirmed affected.

Files


Subtasks 1 (1 open0 closed)

Bug #8411: http2: response_frame_size is never set (8.0.x backport)In ReviewPhilippe AntoineActions
Actions

Also available in: Atom PDF