stamparm/maltrail · warning · QuicParseError
packet too short for header-protection sample
Error message
packet too short for header-protection sample
What it means
During QUIC Initial SNI extraction, the code needs a 16-byte header-protection sample starting at sample_offset (packet-number offset + 4). The packet's payload `p` is too short to supply those 16 bytes, so _extract_sni_impl raises QuicParseError.
Solutions
- Increase capture snapshot size (e.g. tcpdump -s0) so UDP payloads aren't truncated
- Catch QuicParseError in extract_sni_from_quic_initial callers and skip the packet
- Check length bounds after reading each varint before computing sample_offset
- Filter to only valid QUIC Initial long-header packets before parsing
Example fix
// before
sni = extract_sni_from_quic_initial(udp_payload)
// after
try:
sni = extract_sni_from_quic_initial(udp_payload)
except QuicParseError:
sni = None # malformed/short packet Defensive patterns
Strategy: try-catch
Validate before calling
def quic_initial_plausible(udp_payload):
return udp_payload and len(udp_payload) > 6 and (udp_payload[0] & 0x80) and len(udp_payload) >= 1200 # typical Initial size Try / catch
try:
sni = extract_sni_from_quic_initial(payload)
except QuicParseError:
sni = None # skip malformed packet Prevention
- Capture with full snapshot length (-s0) to avoid truncated payloads
- Filter to long-header Initial packets before parsing
- Bounds-check each varint read when extending the parser
- Fuzz-test the parser against short/corrupt packets
When it happens
Trigger: UDP payload shorter than the required varint-decoded offsets allow; coalesced/fragmented packets; crafted or corrupt QUIC Initial packets; non-Initial packets routed into the parser.
Common situations: Capturing truncated packets (snapshot length too small in tcpdump), feeding TCP-reassembled or padded junk into extract_sni_from_quic_initial, fuzz/malicious traffic.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- [x] invalid IP address
- not a Maltrail provenance sidecar (bad magic)
- provenance sidecar is truncated
- trail bin too small
- bad trail bin magic
AI-assisted analysis of stamparm/maltrail@77cfb06d76 (2026-09-13).
Data as JSON: /api/errors/981f1b1f132cb3e8.
Report an issue: GitHub.
Appendix: source
Thrown at core/quic_sni.py:288
off = 5
dcid_len = p[off]; off += 1
dcid = bytes(udp_payload[off:off + dcid_len]); off += dcid_len
scid_len = p[off]; off += 1
off += scid_len
# long header packet type must be Initial
if ver_kind == 1:
if (first & 0x30) != 0x00:
return None
else:
if (first & 0x30) != 0x10: # v2 remaps Initial to 0b01
return None
token_len, off = _read_varint(udp_payload, off)
off += token_len
length, off = _read_varint(udp_payload, off) # length of (pn + payload)
pn_offset = off
sample_offset = pn_offset + 4
if sample_offset + 16 > len(p):
raise QuicParseError("packet too short for header-protection sample")
key, iv, hp = derive_client_initial_keys(dcid, ver_kind)
sample = bytes(udp_payload[sample_offset:sample_offset + 16])
mask = _b(aes_ecb_block(hp, sample))
first_unmasked = first ^ (mask[0] & 0x0F)
pn_len = (first_unmasked & 0x03) + 1
pn_bytes = bytearray(udp_payload[pn_offset:pn_offset + pn_len])
for i in range(pn_len):
pn_bytes[i] ^= mask[1 + i]
packet_number = 0
for bb in pn_bytes:
packet_number = (packet_number << 8) | bb
payload_offset = pn_offset + pn_len
payload_len = length - pn_len
ciphertext = bytes(udp_payload[payload_offset:payload_offset + payload_len])View on GitHub (pinned to 77cfb06d76)