high · 7.5Jun 26, 2026

Hysteria Server Crash via Tiny QUIC max_datagram_frame_size

Pranav Khune
Penetration Testing Team Lead, SecureLayer7

An authenticated Hysteria client can crash the server instantly by advertising a tiny QUIC datagram size and then sending a UDP packet, triggering a slice-bounds panic in the fragmentation code.

Packagegithub.com/apernet/hysteria
Ecosystemgo
Affected< 2.9.2
Fixed in2.9.2

The problem

Hysteria versions before 2.9.2 crash when a client advertises a very small QUIC `max_datagram_frame_size` (for example, 20 bytes) and then triggers a UDP response from the server.

When `sendMessageAutoFrag` catches a `DatagramTooLargeError` from quic-go, it calls `FragUDPMessage` with the attacker-supplied max payload size. The function blindly computes `maxPayloadSize := maxSize - m.HeaderSize()`. If `maxSize` is smaller than the header, the result is zero or negative.

The subsequent slice operation `frag.Data = fullPayload[off : off+payloadSize]` panics, terminating the entire server process.

Any authenticated client can trigger this. No special privileges are needed beyond a valid credential.

Proof of concept

bash
# 1. Run a local UDP echo target
go run -tags poc ./poc_udp_frag_panic.go \
  --server 127.0.0.1:8443 \
  --auth udp-frag-panic-poc \
  --insecure \
  --target 127.0.0.1:19090 \
  --max-datagram 20

# The client connects via HTTP/3, authenticates normally, then sends
# a single Hysteria UDP datagram addressed to the echo target.
# The QUIC connection advertises MaxDatagramFrameSize=20, which is
# smaller than the Hysteria UDP message header (~30 bytes for a short addr).
# The server tries to fragment the reply, computes a negative payload size,
# and panics with: runtime error: slice bounds out of range.

The root cause (CWE-1325, effectively CWE-400) is a missing bounds check in `core/internal/frag/frag.go`. Before the fix, `FragUDPMessage` assumed `maxSize > m.HeaderSize()` without verifying it. The attacker fully controls `MaxDatagramFrameSize` via the QUIC transport parameter negotiation, and quic-go faithfully surfaces that value in `DatagramTooLargeError.MaxDatagramPayloadSize`.

The patch adds an early return in `FragUDPMessage` when `maxSize <= m.HeaderSize()`, preventing the negative slice index from ever being computed. This also causes `sendMessageAutoFrag` to drop the packet rather than crash.

The fix

Upgrade to Hysteria 2.9.2 or later. The release is tagged `app/v2.9.2` and is described by the maintainers as containing important security fixes. No configuration-level workaround exists for earlier versions; the only safe remediation is to upgrade.

Reporter not attributed.

References: [1][2]