From ae7ca199aa8004c7a4f1088dc20d141610c81f2f Mon Sep 17 00:00:00 2001 From: Nikolaus Schuetz Date: Sat, 18 Jul 2026 19:45:34 -0700 Subject: [PATCH] fix(jsonpath): prevent panic on negative array index (#1703) A jsonpath condition with a negative array index (e.g. [BODY].data[-1] or [BODY][-1]) reached array[arrayIndex] with a negative index because the len(array) > arrayIndex bounds checks are satisfied by any negative value, causing a 'runtime error: index out of range [-1]' panic. Since condition evaluation runs in the watchdog with no recover(), this would crash the process. Guard against negative indices alongside the existing strconv.Atoi error check so an out-of-range negative index returns nil (treated as an invalid path) instead of panicking. Adds tests for negative indices on keyed arrays, root arrays, and negative-index-followed-by-key. Made by an AI agent (Claude Code, model Claude Opus 4.8). Co-authored-by: TwiN --- jsonpath/jsonpath.go | 2 +- jsonpath/jsonpath_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/jsonpath/jsonpath.go b/jsonpath/jsonpath.go index b41e393f..07e12305 100644 --- a/jsonpath/jsonpath.go +++ b/jsonpath/jsonpath.go @@ -87,7 +87,7 @@ func extractValue(currentKey string, value interface{}) interface{} { } } arrayIndex, err := strconv.Atoi(index) - if err != nil { + if err != nil || arrayIndex < 0 { return nil } currentKeyWithoutIndex := currentKey[:startOfBracket] diff --git a/jsonpath/jsonpath_test.go b/jsonpath/jsonpath_test.go index 83244c5c..8081dc68 100644 --- a/jsonpath/jsonpath_test.go +++ b/jsonpath/jsonpath_test.go @@ -174,6 +174,38 @@ func TestEval(t *testing.T) { ExpectedOutputLength: 18, ExpectedError: false, }, + { + Name: "negative-index-on-keyed-array", + Path: "data[-1]", + Data: `{"data": [1, 2, 3]}`, + ExpectedOutput: "", + ExpectedOutputLength: 0, + ExpectedError: true, + }, + { + Name: "negative-index-on-root-array", + Path: "[-1]", + Data: `[1, 2, 3]`, + ExpectedOutput: "", + ExpectedOutputLength: 0, + ExpectedError: true, + }, + { + Name: "negative-index-followed-by-key", + Path: "data[-1].name", + Data: `{"data": [{"name": "value"}]}`, + ExpectedOutput: "", + ExpectedOutputLength: 0, + ExpectedError: true, + }, + { + Name: "negative-index-nested-array", + Path: "data[0][-1]", + Data: `{"data": [[1, 2, 3]]}`, + ExpectedOutput: "", + ExpectedOutputLength: 0, + ExpectedError: true, + }, } for _, scenario := range scenarios { t.Run(scenario.Name, func(t *testing.T) {