Project

General

Profile

Actions

Optimization #9173

open
JI OD

http: a multi-value Content-Encoding header silently disables HTTP body inspection

Optimization #9173: http: a multi-value Content-Encoding header silently disables HTTP body inspection

Added by Jason Ish 7 days ago. Updated 7 days ago.

Status:
Triaged
Priority:
Normal
Assignee:
Target version:
Effort:
Difficulty:
Label:

Description

Hi,

I have a detection-evasion defect to report in Suricata's HTTP/1 body decompression (rust/htp, libhtp-rs). Confirmed on 8.0.7 RELEASE, and I believe it affects main as well.

The short version: when Content-Encoding carries more than one value and one of those values is a token the list path does not know, that decompression layer gets dropped while the rest of the chain still runs. Suricata inflates the outer layer, hands the still-compressed inner stream to the body hooks, and inspects it as though it were plaintext. "br" is in the fast path but missing from the list path, so "Content-Encoding: br, gzip" over gzip(br(P)) is enough. On main, "zstd" has the same problem.

What that costs: for the affected transaction every rule on http.response_body, http.request_body and file_data stops matching at once, in both directions. This is not one signature being dodged. The only trace is an ABNORMAL_CE_HEADER applayer anomaly, and nothing about it says that body inspection was lost.

I verified it in two environments:

  • Offline replay of the attached pcap on 8.0.7 (jasonish/suricata:8.0.7). Four transactions with byte-identical plaintext once decoded, differing only in Content-Encoding. Three alerts instead of four. For the "br, gzip" transaction, 8,514 bytes reach inspection instead of 65,536.
  • A public instance of mine running 8.0.7 with the stock ET Open ruleset. No configuration changed and no rules added; I observed through signatures that were already loaded. Same result over the wire, both directions.

The messages themselves are fine. The test endpoint decodes every variant back to the full 65,536-byte plaintext, so the encoding combination is valid and both ends agree on what it means.

I also wrote the regression test as a suricata-verify test, since that seems to be what you prefer. It asserts four alerts and gets three, so it is red today and should go green with the fix. I ran it with your runner under the same container image rather than working the numbers out by hand; the output is in the report.

Two things in the report worth flagging, because they cost me time and might cost yours: http.length in EVE is the wire body length, so it cannot distinguish a healthy transaction from an evaded one (fileinfo.size can). And my first reproducer was a live capture that came out truncated, which looks exactly like "does not reproduce".

Severity: I would put this at HIGH under your policy. The feature is Tier 1 and enabled by default, and the evasion has a wide scope.

Attachments:

REPORT.md
Root cause with file and line references for both affected functions (response.rs and request.rs), observation tables for both directions, EVE samples, suggested fixes, the regression test, and the measurement traps I hit.

REPORT.html
The same report, browser-readable.

f2-repro.pcap
102 packets, 99,937 bytes, sha256
4b0422fe75f5dddcde717812dfe48fb253106436603fcd0179b974e42aab1b53
Four HTTP response transactions, byte-identical plaintext, differing only in Content-Encoding: absent / gzip / br / "br, gzip". The sessions are synthesised with full handshakes and complete bodies, so nothing is lost in transit. Replay with

docker run --rm --entrypoint /usr/bin/suricata -v $PWD:/d \
    jasonish/suricata:8.0.7 -r /d/input.pcap -S /d/test.rules -l /d/out -k none

Not confidential. Please feel free to put it in CI or QA.

http-content-encoding-multivalue.tar.gz
The suricata-verify test: test.yaml, test.rules, input.pcap, README.md. Red on 8.0.7, expected to go green once this is fixed.

f2-evidence.tar.gz
Raw EVE and logs behind the numbers above, including the suricata-verify runner output.

Credit as Zer0Gate, if that works for you.

Thanks,
Zer0Gate

Credit

Zer0Gate


Files

REPORT.md (24.1 KB) REPORT.md Jason Ish, 10/06/2026 04:43 PM
REPORT.html (32.4 KB) REPORT.html Jason Ish, 10/06/2026 04:43 PM
f2-repro.pcap (97.6 KB) f2-repro.pcap Jason Ish, 10/06/2026 04:43 PM
http-content-encoding-multivalue.tar.gz (40.5 KB) http-content-encoding-multivalue.tar.gz Jason Ish, 10/06/2026 04:43 PM
f2-evidence.tar.gz (55.4 KB) f2-evidence.tar.gz Jason Ish, 10/06/2026 04:43 PM

JI Updated by Jason Ish 7 days ago Actions #1

@Philippe Antoine You think public optmization ticket?

JI Updated by Jason Ish 7 days ago Actions #2

  • Subject changed from Suricata: a multi-value Content-Encoding header silently disables HTTP body inspection to http: a multi-value Content-Encoding header silently disables HTTP body inspection

PA Updated by Philippe Antoine 7 days ago Actions #3

  • Tracker changed from Security to Optimization
  • Status changed from New to Triaged
  • Target version changed from TBD to 9.0.0-beta1
  • Disclosure Date deleted (12/23/2026)

Yes, this behavior is intentional so as to avoid compression bombs
I am not sure we want to allow this even behind a congif option which is not by default...

But we can have a more precise anomaly than ABNORMAL_CE_HEADER

PA Updated by Philippe Antoine 7 days ago Actions #4

  • Private changed from Yes to No
Actions

Also available in: PDF Atom