Improper Validation of Array Index in Packetbeat Leading to Denial of Service
Description
Improper Validation of Array Index (CWE-129) in multiple protocol parser components in Packetbeat can lead Denial of Service via Input Data Manipulation (CAPEC-153). An attacker with the ability to send specially crafted, malformed network packets to a monitored network interface can trigger out-of-bounds read operations, resulting in application crashes or resource exhaustion. This requires the attacker to be positioned on the same network segment as the Packetbeat deployment or to control traffic routed to monitored interfaces.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CVE-2026-26933: Improper array index validation in Packetbeat protocol parsers allows denial of service via crafted network packets.
Vulnerability
Overview
CVE-2026-26933 is an improper validation of array index vulnerability (CWE-129) in multiple protocol parser components of Packetbeat, a network packet analyzer within the Elastic Beats family [1][3]. The root cause lies in insufficient bounds checking when parsing malformed network packets, which can lead to out-of-bounds read operations. A commit addressing the issue in the PostgreSQL parser shows added checks for malformed streams that could cause infinite loops or invalid start points for extended requests, as well as bounds checks on field counts in DataRow messages [2].
Exploitation
Conditions
An attacker must be positioned on the same network segment as the Packetbeat deployment or be able to control traffic routed to monitored interfaces [1][4]. The vulnerability is triggered by sending specially crafted, malformed network packets to a network interface that Packetbeat is monitoring. Protocol parsing is enabled protocol parsers are active only when their respective protocols are explicitly configured in packetbeat.yml [4]. No authentication is required beyond network access, and the attack complexity is low [4].
Impact
Successful exploitation results in denial of service (DoS) through application crashes or resource exhaustion [1][4]. The CVSS v3.1 base score is 5.7 (Medium) with a vector of AV:A/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H, indicating high availability impact but no confidentiality or integrity loss [4]. Indicators of compromise include frequent panic/crash events, error messages related to index out of range or slice bounds violations, and repeated restarts of the Packetbeat process [4].
Mitigation
The vulnerability is fixed in Packetbeat versions 8.19.11 and 9.2.5 [4]. Users unable to upgrade should implement network segmentation to ensure Packetbeat instances only monitor trusted network segments and apply network-level controls to prevent untrusted traffic from reaching monitored interfaces [4]. The fix includes additional bounds checks and loop termination conditions in protocol parsers [2].
AI Insight generated on May 18, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/elastic/beats/v7Go | < 7.0.0-alpha2.0.20260126223743-dec1b31111ec | 7.0.0-alpha2.0.20260126223743-dec1b31111ec |
Affected products
2- Elastic/Packetbeatv5Range: 9.0.0
Patches
2dec1b31111ecAdd array bounds and loop checks in postgres input (#48528)
2 files changed · +72 −11
changelog/fragments/1769202503-clean-up-postgres-array-access.yaml+45 −0 added@@ -0,0 +1,45 @@ +# REQUIRED +# Kind can be one of: +# - breaking-change: a change to previously-documented behavior +# - deprecation: functionality that is being removed in a later release +# - bug-fix: fixes a problem in a previous version +# - enhancement: extends functionality but does not break or fix existing behavior +# - feature: new functionality +# - known-issue: problems that we are aware of in a given version +# - security: impacts on the security of a product or a user’s deployment. +# - upgrade: important information for someone upgrading from a prior version +# - other: does not fit into any of the other categories +kind: bug-fix + +# REQUIRED for all kinds +# Change summary; a 80ish characters long description of the change. +summary: fix potential array access panics & infinite loops in postgres parser + +# REQUIRED for breaking-change, deprecation, known-issue +# Long description; in case the summary is not enough to describe the change +# this field accommodate a description without length limits. +# description: + +# REQUIRED for breaking-change, deprecation, known-issue +# impact: + +# REQUIRED for breaking-change, deprecation, known-issue +# action: + +# REQUIRED for all kinds +# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc. +component: packetbeat + +# AUTOMATED +# OPTIONAL to manually add other PR URLs +# PR URL: A link the PR that added the changeset. +# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added. +# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number. +# Please provide it if you are adding a fragment for a different PR. +# pr: https://github.com/owner/repo/1234 + +# AUTOMATED +# OPTIONAL to manually add other issue URLs +# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of). +# If not present is automatically filled by the tooling with the issue linked to the PR number. +# issue: https://github.com/owner/repo/1234
packetbeat/protos/pgsql/parse.go+27 −11 modified@@ -18,6 +18,7 @@ package pgsql import ( + "encoding/binary" "errors" "fmt" "strings" @@ -59,9 +60,16 @@ func (pgsql *pgsqlPlugin) parseMessageStart(s *pgsqlStream) (bool, bool) { pgsql.detailf("parseMessageStart") m := s.message + //malformed streams can put us in an infinite loop, + // just stop if we get multiple iterations where + // isSpecialCommand can't find the length of the command + lengthFailed := 0 - for len(s.data[s.parseOffset:]) >= 5 { + for len(s.data[s.parseOffset:]) >= 5 && (lengthFailed < 100) { isSpecial, length, command := pgsql.isSpecialCommand(s.data[s.parseOffset:]) + if length == 0 { + lengthFailed++ + } if !isSpecial { return pgsql.parseCommand(s) } @@ -340,8 +348,15 @@ func (pgsql *pgsqlPlugin) parseExtReq(s *pgsqlStream, length int) (bool, bool) { } m.size = uint64(msgSize) m.toExport = true + queryRequestPoint := m.start + 6 + + if len(s.data) < (queryRequestPoint) { + pgsql.detailf("invalid start point for extended request: len %v, start %v", + len(s.data), queryRequestPoint) + return false, false + } - query, err := common.ReadString(s.data[m.start+6:]) + query, err := common.ReadString(s.data[queryRequestPoint:]) if err != nil { pgsql.detailf("Invalid extended query request") return false, false @@ -573,7 +588,7 @@ func (pgsql *pgsqlPlugin) parseMessageData(s *pgsqlStream) (bool, bool) { } func (pgsql *pgsqlPlugin) parseDataRow(s *pgsqlStream, buf []byte) error { - m := s.message + msg := s.message // read field count (int16) off := 2 @@ -583,8 +598,8 @@ func (pgsql *pgsqlPlugin) parseDataRow(s *pgsqlStream, buf []byte) error { rows := []string{} rowLength := 0 - if fieldCount > len(m.fieldsFormat) { - return fmt.Errorf("%w: DataRow field mismatch, got %d, expected %d", errFieldBufferBig, fieldCount, len(m.fieldsFormat)) + if fieldCount > len(msg.fieldsFormat) { + return fmt.Errorf("%w: DataRow field mismatch, got %d, expected %d", errFieldBufferBig, fieldCount, len(msg.fieldsFormat)) } for field := range fieldCount { if len(buf) <= off { @@ -603,7 +618,7 @@ func (pgsql *pgsqlPlugin) parseDataRow(s *pgsqlStream, buf []byte) error { // read column value (byten) var columnValue []byte - if m.fieldsFormat[field] == 0 { + if msg.fieldsFormat[field] == 0 { // field value in text format if columnLength > 0 { columnValue = buf[off : off+columnLength] @@ -626,9 +641,9 @@ func (pgsql *pgsqlPlugin) parseDataRow(s *pgsqlStream, buf []byte) error { return errFieldBufferBig } - m.numberOfRows++ - if len(m.rows) < pgsql.maxStoreRows { - m.rows = append(m.rows, rows) + msg.numberOfRows++ + if len(msg.rows) < pgsql.maxStoreRows { + msg.rows = append(msg.rows, rows) } return nil @@ -743,11 +758,12 @@ func (pgsql *pgsqlPlugin) isSpecialCommand(data []byte) (bool, int, int) { // length field in pgsql counts total length of length field + payload, not // including the message identifier. => Always check buffer size >= length + 1 func readLength(b []byte) int { - return int(common.BytesNtohl(b)) + // big endian = network byte order + return int(binary.BigEndian.Uint32(b)) } func readCount(b []byte) int { - return int(common.BytesNtohs(b)) + return int(binary.BigEndian.Uint16(b)) } func pgsqlString(b []byte, sz int) (string, error) {
941098459db6Add array checks to packetbeat procfs parser (#48428)
3 files changed · +65 −12
changelog/fragments/1768584444-fix-procfs-network-parsers.yaml+45 −0 added@@ -0,0 +1,45 @@ +# REQUIRED +# Kind can be one of: +# - breaking-change: a change to previously-documented behavior +# - deprecation: functionality that is being removed in a later release +# - bug-fix: fixes a problem in a previous version +# - enhancement: extends functionality but does not break or fix existing behavior +# - feature: new functionality +# - known-issue: problems that we are aware of in a given version +# - security: impacts on the security of a product or a user’s deployment. +# - upgrade: important information for someone upgrading from a prior version +# - other: does not fit into any of the other categories +kind: bug-fix + +# REQUIRED for all kinds +# Change summary; a 80ish characters long description of the change. +summary: fix procfs network parsers + +# REQUIRED for breaking-change, deprecation, known-issue +# Long description; in case the summary is not enough to describe the change +# this field accommodate a description without length limits. +# description: + +# REQUIRED for breaking-change, deprecation, known-issue +# impact: + +# REQUIRED for breaking-change, deprecation, known-issue +# action: + +# REQUIRED for all kinds +# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc. +component: packetbeat + +# AUTOMATED +# OPTIONAL to manually add other PR URLs +# PR URL: A link the PR that added the changeset. +# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added. +# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number. +# Please provide it if you are adding a fragment for a different PR. +# pr: https://github.com/owner/repo/1234 + +# AUTOMATED +# OPTIONAL to manually add other issue URLs +# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of). +# If not present is automatically filled by the tooling with the issue linked to the PR number. +# issue: https://github.com/owner/repo/1234
packetbeat/procs/procs_linux.go+12 −7 modified@@ -141,13 +141,13 @@ func findSocketsOfPid(prefix string, pid int) (inodes []uint64, err error) { } if strings.HasPrefix(link, "socket:[") { - inode, err := strconv.ParseInt(link[8:len(link)-1], 10, 64) + inode, err := strconv.ParseUint(link[8:len(link)-1], 10, 64) if err != nil { logp.Debug("procs", "%s", err.Error()) continue } - inodes = append(inodes, uint64(inode)) + inodes = append(inodes, inode) } } @@ -204,10 +204,10 @@ func parseProcNetProto(input io.Reader, ipv6 bool) ([]*socketInfo, error) { continue } - uid, _ := strconv.Atoi(string(words[7])) + uid, _ := strconv.ParseUint(string(words[7]), 10, 32) sock.uid = uint32(uid) - inode, _ := strconv.Atoi(string(words[9])) - sock.inode = uint64(inode) + inode, _ := strconv.ParseUint(string(words[9]), 10, 64) + sock.inode = inode sockets = append(sockets, &sock) } @@ -230,7 +230,7 @@ func hexToIPPort(str []byte, ipv6 bool) (net.IP, uint16, error) { return nil, 0, err } - port, err := strconv.ParseInt(string(words[1]), 16, 32) + port, err := strconv.ParseUint(string(words[1]), 16, 16) if err != nil { return nil, 0, err } @@ -255,8 +255,13 @@ func hexToIpv4(word string) (net.IP, error) { func hexToIpv6(word string) (net.IP, error) { p := make(net.IP, net.IPv6len) + if len(word) < 32 { + return nil, fmt.Errorf("got ip6 address of invalid length: %d", len(word)) + } for i := 0; i < 4; i++ { - part, err := strconv.ParseUint(word[i*8:(i+1)*8], 16, 32) + start := i * 8 + end := (i + 1) * 8 + part, err := strconv.ParseUint(word[start:end], 16, 32) if err != nil { return nil, err }
packetbeat/procs/procs_linux_test.go+8 −5 modified@@ -20,16 +20,14 @@ package procs import ( - "io/ioutil" "os" "path/filepath" "testing" - "github.com/elastic/elastic-agent-libs/logp" + "github.com/stretchr/testify/require" ) func TestFindSocketsOfPid(t *testing.T) { - logp.TestingSetup() proc := []testProcFile{ {path: "/proc/766/fd/0", isLink: true, contents: "/dev/null"}, @@ -44,7 +42,7 @@ func TestFindSocketsOfPid(t *testing.T) { } // Create fake proc file system - pathPrefix, err := ioutil.TempDir("", "find-sockets") + pathPrefix, err := os.MkdirTemp("", "find-sockets") if err != nil { t.Error("TempDir failed:", err) return @@ -65,6 +63,11 @@ func TestFindSocketsOfPid(t *testing.T) { assertUint64ArraysAreEqual(t, []uint64{7619, 7620}, inodes) } +func TestParseInvalidIp6Addr(t *testing.T) { + _, err := hexToIpv6("B80D012000000000FFFF2301EFCD") + require.Error(t, err) +} + func TestParse_Proc_Net_Tcp(t *testing.T) { socketInfo, err := socketsFromProc("../tests/files/proc_net_tcp.txt", false) if err != nil { @@ -116,7 +119,7 @@ func createFakeDirectoryStructure(prefix string, files []testProcFile) error { } if !file.isLink { - err = ioutil.WriteFile(filepath.Join(prefix, file.path), + err = os.WriteFile(filepath.Join(prefix, file.path), []byte(file.contents), 0o644) if err != nil { return err
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-27qj-9gvp-8rh9ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-26933ghsaADVISORY
- discuss.elastic.co/t/packetbeat-8-19-11-9-2-5-security-update-esa-2026-11/385533ghsaWEB
- github.com/elastic/beats/commit/941098459db6556b837194f40c076b08d51137cbghsaWEB
- github.com/elastic/beats/commit/dec1b31111ec3500b82db21ba67dde5c914ee94dghsaWEB
News mentions
0No linked articles in our index yet.