[packetbeat-parser-safety] Cassandra prepared-result pkeyCount can trigger makeslice panic in parseResultMetadata
- Dominant language
- Go
- Stars
- 12.7k
- Forks
- 5k
- Avg merge
- 2d 15m
- Merged PRs (30d)
- 385
Description
## Findings
### 1. Cassandra prepared-result metadata trusts unbounded `pkeyCount` and panics
**Location**
- `packetbeat/protos/cassandra/internal/gocql/frame.go:385-391`
- `packetbeat/protos/cassandra/internal/gocql/frame.go:171-185`
- `packetbeat/protos/cassandra/internal/gocql/frame.go:456-467`
**Evidence**
At `packetbeat/protos/cassandra/internal/gocql/frame.go:389` the parser allocates directly from a packet-derived count with no bounds validation:
```go
pkeyCount := decoder.ReadInt()
pkeys := make([]int, pkeyCount)
for i := 0; i < pkeyCount; i++ {
pkeys[i] = int(decoder.ReadShort())
}
```
`pkeyCount` is read from untrusted frame bytes (`decoder.ReadInt()`), and this code is reached on `RESULT kind=prepared` via `parseResultPrepared()` (`frame.go:456-467`). A malformed response can set `pkeyCount` negative or huge, causing a runtime `makeslice` panic. `Framer.ReadFrame()` re-panics `runtime.Error` (`frame.go:179-180`), so this is a process-crashing path, not a handled parse error.
**Why this is wrong**
A network peer controls Cassandra response bytes. Using packet-derived counts as allocation sizes without validating range violates parser bounds safety and allows malformed/truncated traffic to crash Packetbeat.
**Impact**
High severity denial-of-service: a malicious or buggy Cassandra server (or any man-in-the-middle/fuzzed traffic source in capture path) can crash packet processing by sending a malformed prepared-result metadata section.
**Suggested fix**
Add explicit bounds checks before allocation and before iterating:
```go
if pkeyCount < 0 || pkeyCount > maxReasonablePKeyCount {
panic(fmt.Errorf("invalid pkeyCount: %d", pkeyCount))
}
```
Use a limit derived from remaining frame bytes (e.g., `remaining/2`) and reject impossible values before `make`.
## Reproducer test (currently panics)
The following test demonstrates the panic today by supplying `pkeyCount = -1`:
```go
func TestParseResultMetadata_NegativePkeyCountDoesNotPanic(t *testing.T) {
raw := []byte{
0x00, 0x00, 0x00, 0x00, // flags
0x00, 0x00, 0x00, 0x00, // colCount
0xff, 0xff, 0xff, 0xff, // pkeyCount = -1
}
decoder := &ByteArrayDecoder{Data: &raw}
f := &Framer{decoder: decoder, proto: protoVersion4}
// Desired behavior: handled parser error, not panic.
require.NotPanics(t, func() {
_ = f.parseResultMetadata(true)
})
}
```
Run with:
```bash
go test ./packetbeat/protos/cassandra/internal/gocql -run TestParseResultMetadata_NegativePkeyCountDoesNotPanic -count=1
```
## Unsafe-location checklist from this sweep
- [ ] `packetbeat/protos/cassandra/internal/gocql/frame.go:389` — validate `pkeyCount` before `make([]int, pkeyCount)` and loop.
## Coverage checked and found clean for this run
Inspected parser families for this bug class (high-severity panic/infinite-loop/overflow paths): `amqp`, `dhcpv4`, `dns`, `http`, `icmp`, `memcache`, `mongodb`, `mysql`, `nfs`, `pgsql`, `redis`, `sip`, `thrift`, `tls`; no additional distinct high-severity findings survived verification in this pass.
---
[What is this?](https://ela.st/github-ai-tools) | [From workflow: Sweeper: Packetbeat Parser Bounds Safety](https://github.com/elastic/beats/actions/runs/30805255066)
Give us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.
> - [x] expires on Aug 10, 2026, 10:35 AM UTC
Contributor guide
Research direction
Start in packetbeat/protos/cassandra/internal/gocql/frame.go, reading parseResultMetadata and the prepared-result path in parseResultPrepared, then run the provided focused Go test command. Use the existing negative-pkeyCount reproducer as the baseline; done means malformed metadata is handled without a panic and the focused test passes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- backend, networking, security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100