Detection rules › Splunk

HTTP Duplicated Header

Status
production
Severity
low
Group by
_raw, count, dest, header_names, src_ip
Author
Raven Tait, Splunk
Source
github.com/splunk/security_content

Detects when a request has more than one of the same header. This is commonly used in request smuggling and other web based attacks. HTTP Request Smuggling exploits inconsistencies in how front-end and back-end servers parse HTTP requests by using ambiguous or malformed headers to hide malicious requests within legitimate ones. Attackers leverage duplicate headers, particularly Content-Length and Transfer-Encoding, to cause different servers in the chain to disagree on where one request ends and another begins. RFC7230 states that a sender MUST NOT generate multiple header fields with the same field name in a message unless either the entire field value for that header field is defined as a comma-separated list or the header field is a well-known exception.

Known false positives

  • False positives are not expected, however, monitor, filter, and tune as needed based on organization log sources.

MITRE ATT&CK coverage

Rule body

name: HTTP Duplicated Header
id: 1606cc5b-fd5f-4865-9fe3-0ed1eaec2df6
version: 5
creation_date: '2025-10-21'
modification_date: '2026-05-13'
author: Raven Tait, Splunk
status: production
type: Anomaly
description: Detects when a request has more than one of the same header. This is commonly used in request smuggling and other web based attacks. HTTP Request Smuggling exploits inconsistencies in how front-end and back-end servers parse HTTP requests by using ambiguous or malformed headers to hide malicious requests within legitimate ones. Attackers leverage duplicate headers, particularly Content-Length and Transfer-Encoding, to cause different servers in the chain to disagree on where one request ends and another begins. RFC7230 states that a sender MUST NOT generate multiple header fields with the same field name in a message unless either the entire field value for that header field is defined as a comma-separated list or the header field is a well-known exception.
data_source:
    - Suricata
search: |-
    `suricata` http.request_headers{}.name="*"
      | rename dest_ip as dest
      | spath path=http.request_headers{}.name output=header_names
      | mvexpand header_names
      | where lower(header_names) != "set-cookie"
      | stats count
        BY _raw, header_names, src_ip,
           dest
      | where count > 1
      | stats values(header_names) as duplicate_headers
        BY _raw, count, src_ip,
           dest
      | `http_duplicated_header_filter`
how_to_implement: This detection requires the Web datamodel to be populated from a supported Technology Add-On like Suricata, Splunk for Apache, Splunk for Nginx, or Splunk for Palo Alto. Some of these will need to have all headers dumped to contain the necessary fields.
known_false_positives: False positives are not expected, however, monitor, filter, and tune as needed based on organization log sources.
references:
    - https://portswigger.net/web-security/request-smuggling#what-is-http-request-smuggling
    - https://portswigger.net/research/http1-must-die
    - https://www.vaadata.com/blog/what-is-http-request-smuggling-exploitations-and-security-best-practices/
    - https://www.securityweek.com/new-http-request-smuggling-attacks-impacted-cdns-major-orgs-millions-of-websites/
intermediate_findings:
    entities:
        - field: dest
          type: system
          score: 20
          message: Duplicated headers within a web request was detected. The source IP is $src_ip$ and the destination is $dest$.
threat_objects:
    - field: src_ip
      type: ip_address
analytic_story:
    - HTTP Request Smuggling
asset_type: Network
mitre_attack_id:
    - T1071.001
    - T1190
product:
    - Splunk Enterprise
    - Splunk Enterprise Security
    - Splunk Cloud
category: web
security_domain: network

Stages and Predicates

Stage 1: search

`suricata` http.request_headers{}.name="*"

Stage 2: rename

| rename dest_ip as dest

Stage 3: spath

| spath path=http.request_headers{}.name output=header_names

Stage 4: mvexpand

| mvexpand header_names

Stage 5: where

| where lower(header_names) != "set-cookie"

Stage 6: stats

| stats count
    BY _raw, header_names, src_ip,
       dest

Stage 7: where

| where count > 1

Stage 8: stats

| stats values(header_names) as duplicate_headers
    BY _raw, count, src_ip,
       dest

Stage 9: search

| `http_duplicated_header_filter`

Indicators

These rows show field, operator, and value matches.