GitHub Advisoryadvisory · Go

GHSA-6r28-9ppf-4hj5 GoPacket's Diameter AVP decoder: uint32 underflow on vendor header size leads to unbounded ~4 GiB allocation (unauthenticated remote DoS)

MEDIUM Published 2026-07-28 Modified 2026-07-28 Official page ↗
Aliases
CVE-2026-54345
Ecosystem
Go
Packages
github.com/gopacket/gopacket
Severity
Moderate
CVSS vector
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N
Weaknesses
CWE-191, CWE-770
Reviewed
2026-07-28

Affected packages

• Go github.com/gopacket/gopacket: < 1.6.1 → fixed in 1.6.1

Description

Summary The Diameter AVP decoder in `github.com/gopacket/gopacket` computes `dataLength := avp.Length - uint32(headerSize)` without first ensuring `avp.Length >= headerSize`. When the Vendor flag is set, `headerSize` is 12, but the only length guard upstream rejects `avp.Length CWE-770 unbounded allocation). Root cause (file:line @ v1.6.0) `layers/diameter_avp_decoders.go`, `decodeDiameterAVP`: ```go avp.Length = uint32(data[5])= 8 was checked dataOffset = 12 } paddedLength := avp.Length // equals avp.Length; for avp.Length panic ``` For `avp.Length` in `{8, 9, 10, 11}` with the Vendor flag set: the `avp.Length sink) `LayerTypeDiameter` is a registered decoder (`layertypes.go:159`, `RegisterLayerType(154, ... decodeDiameter)`): `decodeDiameter` -> `(*Diameter).DecodeFromBytes` (diameter.go:118) -> parses the 20-byte header -> `avpData := data[20:d.MessageLength]` -> AVP loop `decodeDiameterAVP(avpData)` (diameter.go:158) -> sink at `diameter_avp_decoders.go:57`. Diameter (RFC 6733) is a TCP/SCTP base protocol used for AAA and telecom/5G signaling. Any service that parses Diameter with gopacket (packet collectors, signaling monitors, IDS/analysis tooling) processes attacker-sent or attacker-forwarded Diameter messages with no authentication involved, so any host able to deliver such a message to the parser reaches the sink. The same path is reached via `gopacket.NewPacket(data, LayerTypeDiameter, ...)`. The Diameter layer is specific to this gopacket fork (the original google/gopacket has no Diameter layer), so there is no upstream sibling fix. Impact Unauthenticated remote denial of service via memory exhaustion. Each malicious 32-byte Diameter message requests a ~4 GiB allocation (amplification ~1.34e8x over the input). There is no memory corruption and no code execution -- the impact is resource exhaustion / process termination. Severity assessed as Medium (unauthenticated remote DoS, no memory-safety violation). Note on consumer behavior (measured end-to-end against a deployed collector, see PoC): • A collector using the recovering `gopacket.NewPacket(..., gopacket.Default)` API survives a *single* malicious message: the ~4 GiB `make([]byte, dataLength)` runs (in-process `runtime.MemStats` shows a 4096 MB `TotalAlloc` delta per message), but the immediately-following out-of-bounds `copy` panics before the allocator faults in the 4 GiB of physical pages, the panic is recovered into an `ErrorLayer`, and the reservation is reclaimed by the GC. RSS therefore does not commit on a single message. • Two malicious messages in succession reliably OOM-kill the collector under a 256 MB cap: the second `make` commits physical pages before the first reservation is fully returned to the cgroup, and the kernel cgroup OOM-killer terminates the process (`OOMKilled=true`, exit 137). This was reproduced with two messages sent strictly serially to the single-threaded accept loop (no concurrency required). • Consumers that call `DecodeFromBytes` directly (common in performance-sensitive collectors) or set `SkipDecodeRecovery: true` additionally get an uncaught panic / crash on the first message. In all cases the underlying defect is the same unbounded ~4 GiB allocation driven by an attacker-controlled field; the only variable is how many messages it takes to exhaust a given memory limit. Proof of Concept This PoC is an end-to-end test against a real deployed Diameter collector. A minimal but realistic TCP collector (built on the public gopacket API) runs inside a hard-capped 256 MB container; an independent client process sends real malicious Diameter messages over a real TCP socket; the collector process is then observed to die. A benign message is used as a negative control. The harness pins `github.com/gopacket/[email protected]` (the sink is confirmed at the v1.6.0 tag, `layers/diameter_avp_decoders.go:56-58`). Collector (real TCP Diameter collector) ```go // collector.go — accepts a TCP connection, reads one Diameter message (framed by // the 24-bit Message Length in the base header), builds a gopacket.Packet rooted // at LayerTypeDiameter and accesses the layer, which drives the registered // Diameter decoder over the attacker-controlled bytes. package main import ( "fmt" "io" "net" "os" "github.com/gopacket/gopacket" "github.com/gopacket/gopacket/layers" ) func readDiameterMessage(conn net.Conn) ([]byte, error) { hdr := make([]byte, 20) if _, err := io.ReadFull(conn, hdr); err != nil { return nil, err } msgLen := uint32(hdr[1])= 12` so the AVP carries `avpLen-12` real bytes and parses cleanly. ```go // client.go — usage: client <…

Related

Alias · CVE (1)

  • CVE-2026-54345 gopacket provides packet processing capabilities for Go. vulnerability

Weakness · CWE (2)

  • CWE-191 Integer Underflow (Wrap or Wraparound) weakness
  • CWE-770 Allocation of Resources Without Limits or Throttling weakness

References