Back to Articles

h2cSmuggler: Exploiting HTTP/2 Cleartext Upgrades to Bypass Reverse Proxies

[ View on GitHub ]

h2cSmuggler: Exploiting HTTP/2 Cleartext Upgrades to Bypass Reverse Proxies

Hook

A single HTTP header can transform your browser into a weapon that punches straight through enterprise reverse proxies, bypassing authentication, WAFs, and access controls as if they didn't exist.

Context

HTTP request smuggling has plagued web infrastructure since the early 2000s, but the introduction of HTTP/2 added a new attack surface that most security teams never anticipated. When HTTP/2 was standardized, it included an upgrade mechanism called h2c (HTTP/2 Cleartext) that allows clients to negotiate an HTTP/2 connection over an existing HTTP/1.1 connection using upgrade headers. This was meant as a convenience feature for testing and development.

The problem emerged when reverse proxies like HAProxy and nginx began supporting h2c backends while simultaneously forwarding user-supplied upgrade headers without sanitization. This created a perfect storm: attackers could send specially crafted HTTP/1.1 requests with h2c upgrade headers through the proxy, which would dutifully forward them to backend servers. If those backends supported h2c, they'd establish an HTTP/2 connection directly with the attacker—completely bypassing the proxy's security controls. Bishop Fox's h2cSmuggler was created to systematically identify and exploit this vulnerability class, turning what was a theoretical attack into a practical penetration testing tool.

Technical Insight

h2cSmuggler's architecture revolves around manipulating the HTTP upgrade mechanism defined in RFC 7540. The tool sends an HTTP/1.1 request with three critical headers: Connection: Upgrade, HTTP2-Settings, Upgrade: h2c, and HTTP2-Settings containing base64url-encoded HTTP/2 SETTINGS frames. When a misconfigured proxy forwards these headers to an h2c-capable backend, the backend responds with 101 Switching Protocols and the connection transitions to HTTP/2.

The exploitation flow begins with the tool establishing a TCP connection and sending the upgrade request:

# Simplified version of h2cSmuggler's upgrade request construction
import base64
import h2.settings

def create_h2c_upgrade_request(target_path, host):
    # Generate HTTP/2 settings frame
    settings = h2.settings.Settings(client=True)
    settings_frame = settings.serialize()
    encoded_settings = base64.urlsafe_b64encode(settings_frame).decode('utf-8').rstrip('=')
    
    request = (
        f"GET {target_path} HTTP/1.1\r\n"
        f"Host: {host}\r\n"
        f"Connection: Upgrade, HTTP2-Settings\r\n"
        f"Upgrade: h2c\r\n"
        f"HTTP2-Settings: {encoded_settings}\r\n"
        "\r\n"
    )
    return request.encode()

Once the upgrade succeeds, h2cSmuggler uses the hyper-h2 library to handle HTTP/2 framing. This is where the tool becomes particularly dangerous: it can now send HTTP/2 requests directly to the backend, completely invisible to the proxy. The proxy sees only the initial HTTP/1.1 upgrade request; everything afterward is opaque binary data it blindly forwards.

The tool's most powerful feature is its ability to leverage HTTP/2 multiplexing for high-speed enumeration. Unlike HTTP/1.1's sequential request model, HTTP/2 allows multiple concurrent requests over a single connection using stream IDs. h2cSmuggler exploits this to brute-force internal endpoints at speeds that would trigger rate limiting or connection exhaustion with traditional tools:

# Conceptual example of multiplexed requests
from h2.connection import H2Connection

def smuggle_multiple_requests(connection, endpoints):
    h2_conn = H2Connection(config=h2.config.H2Configuration(client_side=True))
    h2_conn.initiate_connection()
    
    stream_map = {}
    for endpoint in endpoints:
        stream_id = h2_conn.get_next_available_stream_id()
        headers = [
            (':method', 'GET'),
            (':path', endpoint),
            (':scheme', 'http'),
            (':authority', 'internal.backend.local'),
        ]
        h2_conn.send_headers(stream_id, headers, end_stream=True)
        stream_map[stream_id] = endpoint
    
    # Send all frames at once
    connection.sendall(h2_conn.data_to_send())

The tool also includes practical exploitation payloads for common targets. One particularly elegant example targets AWS metadata services, which are typically blocked by proxies but become accessible through h2c tunneling. By smuggling a request to http://169.254.169.254/latest/meta-data/iam/security-credentials/, attackers can retrieve IAM credentials from backend EC2 instances.

What makes h2cSmuggler especially reliable for HTTPS targets is that h2c should never appear in encrypted contexts—HTTP/2 over TLS uses ALPN negotiation, not upgrade headers. If an HTTPS endpoint accepts h2c upgrades, it's definitively vulnerable, eliminating false positives. The tool checks for this by looking for the 101 Switching Protocols response and validating that subsequent data follows HTTP/2 frame structure. This binary validation is more reliable than timing-based or content-based detection methods used in other smuggling tools.

The repository includes a complete Docker-based lab environment demonstrating real-world vulnerable configurations. The setup chains HAProxy (frontend) → nginx (middle proxy) → nginx (h2c backend), showing how multi-tier architectures amplify the vulnerability. This is particularly educational because it reveals that even security-conscious organizations using multiple proxy layers for defense-in-depth can be compromised if any single layer mishandles upgrade headers.

Gotcha

The biggest limitation is false positives on HTTP (non-TLS) services. Some proxies themselves support h2c and will respond with 101 Switching Protocols without forwarding the upgrade to backends. When this happens, you're establishing an HTTP/2 connection with the proxy, not smuggling through it. The tool attempts to mitigate this by checking response characteristics, but distinguishing between 'proxy responded' and 'backend responded through proxy' isn't always possible without additional context about the infrastructure.

Another issue is that server implementations vary wildly in their h2c support signaling. Some servers send 101 Switching Protocols but then fail to actually speak HTTP/2, continuing to expect HTTP/1.1. Others close the connection immediately after the 101 response. This creates scenarios where h2cSmuggler reports a potential vulnerability that isn't actually exploitable. The tool requires manual verification for production exploitation scenarios—automated scanning can identify candidates, but confirming actual smuggling requires follow-up testing with specific payloads. Additionally, the tool's effectiveness is completely dependent on misconfiguration. Modern proxy versions with proper default configurations that strip upgrade headers won't be vulnerable, meaning this technique has a limited shelf life as infrastructure modernizes and security awareness increases.

Verdict

Use if: You're conducting penetration tests or bug bounty research on enterprise web applications behind reverse proxies, especially HAProxy, nginx, or Traefik deployments. This tool shines when targeting HTTPS endpoints where h2c detection is unambiguous, or when you need to bypass WAFs and authentication layers to access internal APIs. It's particularly valuable in cloud environments where metadata services might be exposed through backend systems. Skip if: You're testing simple single-server applications without proxy layers, targeting modern infrastructure that's been hardened against request smuggling (look for recent proxy versions with upgrade header sanitization), or you need a general-purpose smuggling tool that covers CL.TE and TE.CL variants—h2cSmuggler is laser-focused on h2c and won't detect other smuggling classes. Also skip if you can't afford false positives; the tool requires manual validation for HTTP targets and isn't suitable for fully automated security pipelines without additional verification logic.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/cybersecurity/bishopfox-h2csmuggler.svg)](https://starlog.is/api/badge-click/cybersecurity/bishopfox-h2csmuggler)