From c36bb38b491cb75b38c2c239cb582f3035807c7e Mon Sep 17 00:00:00 2001 From: SAY-5 Date: Tue, 21 Apr 2026 12:04:26 -0700 Subject: [PATCH] fix: guard Delete against out-of-range endOffset+tokEnd on fuzz input Delete's nested-key branch assumed that endOffset+tokEnd (the byte after the found value's closing token) always stayed inside the input buffer. Fuzz-generated or truncated input can leave the computed index one-past the buffer, and the subsequent data[endOffset+tokEnd] read panicked with 'index out of range', killing the whole process before any caller could recover - this is how Delete surfaced as a deadly signal under libFuzzer (#274). Bail out early and return the original buffer unchanged when the next-byte index is out of range. That is equivalent to 'there is nothing after the match to remove', which is the correct no-op semantic here: the caller gets their input back, no panic, no partial delete. Closes #274 Signed-off-by: SAY-5 --- parser.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/parser.go b/parser.go index 1a4e337..0f49995 100644 --- a/parser.go +++ b/parser.go @@ -707,12 +707,10 @@ func WriteToBuffer(buffer []byte, str string) int { } /* - Del - Receives existing data structure, path to delete. Returns: `data` - return modified data - */ func Delete(data []byte, keys ...string) []byte { lk := len(keys) @@ -752,6 +750,16 @@ func Delete(data []byte, keys ...string) []byte { tokEnd := tokenEnd(data[endOffset:]) tokStart := findTokenStart(data[:keyOffset], ","[0]) + // Fuzz-generated or truncated input can leave endOffset+tokEnd + // past the end of data, which used to panic the whole process + // with 'index out of range' before any caller could recover + // (#274). Bail out and return the original buffer unchanged + // when the index is out of range - equivalent to 'nothing to + // delete here'. + if endOffset+tokEnd >= len(data) { + return data + } + if data[endOffset+tokEnd] == ","[0] { endOffset += tokEnd + 1 } else if data[endOffset+tokEnd] == " "[0] && len(data) > endOffset+tokEnd+1 && data[endOffset+tokEnd+1] == ","[0] { @@ -797,13 +805,11 @@ func Delete(data []byte, keys ...string) []byte { } /* - Set - Receives existing data structure, path to set, and data to set at that key. Returns: `value` - modified byte array `err` - On any parsing error - */ func Set(data []byte, setValue []byte, keys ...string) (value []byte, err error) { // ensure keys are set