Cybersecurity News

Panic via Negative Slice Index in buger/jsonparser v1.1.1 Delete() — Unpatched DoS

Panic via Negative Slice Index in buger/jsonparser v1.1.1 Delete() — Unpatched DoS

Severity: High (CVSS ~7.5)  |  Affected: github.com/buger/jsonparser v1.1.1  |  Status: Unpatched  |  Discovered: February 2026

GitHub Issue #275 - buger/jsonparser DoS vulnerability

Introduction

A denial-of-service vulnerability has been identified in github.com/buger/jsonparser v1.1.1, the latest release of one of the most popular zero-allocation JSON parsing libraries in the Go ecosystem. The vulnerability causes an unrecovered panic with a negative slice index in the Delete() function when processing malformed JSON input, allowing any attacker to crash a Go service with a small crafted payload.

This finding is notable for two reasons. First, buger/jsonparser previously received a CVE (CVE-2020-10675) for a different vulnerability in the same Delete() function — an infinite loop that was fixed in v1.1.0. This new vulnerability is a distinct failure class (a panic via a negative computed index rather than an infinite loop) on a code path that was not covered by the CVE-2020-10675 fix. Second, the library already ships with its own internal fuzz targets (FuzzDelete, FuzzObjectEach, etc.) yet this crash survived them, suggesting the internal corpus lacked the specific input shape needed to trigger this path.

Background: buger/jsonparser

github.com/buger/jsonparser is a high-performance JSON parsing library for Go, authored by Leonid Bugaev. Unlike Go's standard encoding/json package, it is designed for zero-allocation operation — it avoids heap allocations by operating directly on the raw JSON byte slice using manual offset arithmetic and pointer manipulation rather than building an in-memory parse tree. This design makes it extremely fast for extracting specific values from large JSON documents, but it also means the library bypasses some of Go's standard bounds-checking safety mechanisms.

The library exposes a functional API: Get(data, keys...) for value extraction, Set(data, value, keys...) for value replacement, Delete(data, keys...) for key removal, ArrayEach for array iteration, and ObjectEach for object iteration. The Delete() function is the subject of this report.

The library has over 13,000 GitHub stars and is used in production systems where JSON processing performance is critical, including logging pipelines, API gateways, and data transformation services.

Prior Vulnerability: CVE-2020-10675

In March 2020, CVE-2020-10675 was assigned for an infinite loop in buger/jsonparser versions prior to v1.0.0. The vulnerability was triggered by calling Delete() on certain malformed JSON inputs, causing the function to loop indefinitely and exhaust CPU resources. The fix was released as part of v1.1.0. This established a pattern of the Delete() function being sensitive to malformed input — a pattern that reoccurs with the new vulnerability in v1.1.1.

A second CVE, CVE-2020-35381, was assigned for a denial-of-service vulnerability triggered via the Get() function on certain malformed JSON values. This was also fixed in v1.1.1, establishing a history of multiple CVEs across both the read and write paths of this library. The new vulnerability represents a third distinct crash class in the Delete() path that survived both prior fixes.

Vulnerability Discovery

The library was selected as a fuzzing target based on its CVE history, its use of manual pointer arithmetic (which bypasses Go's slice bounds checking in some internal operations), and the fact that the most recent CVE affected v1.1.0 — meaning the latest version v1.1.1 was only one patch version beyond a known-vulnerable release.

Four fuzz targets were written targeting the key public APIs:

  • FuzzGet — calls jsonparser.Get(data, key)
  • FuzzArrayEach — calls jsonparser.ArrayEach(data, callback)
  • FuzzObjectEach — calls jsonparser.ObjectEach(data, callback)
  • FuzzDelete — calls jsonparser.Delete(data, key)

Because CVE-2020-10675 was an infinite loop, a two-second timeout wrapper was added around each fuzz call to detect hangs as well as panics:

func withTimeout(t *testing.T, d time.Duration, fn func()) {
    done := make(chan struct{})
    go func() {
        defer close(done)
        fn()
    }()
    select {
    case <-done:
    case <-time.After(d):
        t.Fatal("timeout: possible infinite loop")
    }
}

Technical Root Cause Analysis

The panic occurs at parser.go:729 inside the Delete() function. The full panic output is:

panic: runtime error: slice bounds out of range [-1:]

goroutine N [running]:
github.com/buger/jsonparser.Delete({0xc00000a4a0, 0x8, 0x8},
    {0xc000081f90, 0x1, 0x1})
        parser.go:729 +0x82d

The crashing input is:

  • JSON data: "0":"0": (7 bytes — a malformed JSON fragment)
  • Key: "0"

The input "0":"0": is not valid JSON — it looks like a key-value pair without enclosing braces, followed by a trailing colon. When Delete() processes this input looking for the key "0", it locates the key at offset 0 and then computes the boundaries of the value to determine what byte range to remove. The offset arithmetic used to calculate the start of the deletion range produces the value -1, which is then used directly as a slice bound in an expression such as data[-1:], causing the Go runtime to panic.

The root cause is a missing lower-bound validation on the computed deletion offset before it is used as a slice index. The Delete() function, like much of buger/jsonparser, uses raw integer offsets computed by scanning through the JSON byte slice. When the JSON is malformed in specific ways, these offset calculations can yield negative values that are never checked before use.

Line 729 of parser.go performs a slice operation using this computed offset without validating that the offset is non-negative. A one-line guard — if offset < 0 { return data } — would prevent the panic.

Proof of Concept

package main

import (
    "fmt"
    "github.com/buger/jsonparser"
)

func main() {
    data := []byte(`"0":"0":`)
    result := jsonparser.Delete(data, "0")
    fmt.Println(string(result))
}

Running this program produces:

goroutine 1 [running]:
github.com/buger/jsonparser.Delete(...)
        parser.go:729 +0x82d
main.main()
        main.go:9 +0x45
exit status 2

The crash is immediate and deterministic — the same input always triggers the same panic on v1.1.1.

Comparison with CVE-2020-10675

PropertyCVE-2020-10675This Vulnerability
FunctionDelete()Delete()
Failure classInfinite loop (CWE-835)Panic / slice[-1:] (CWE-125)
Fixed inv1.1.0Not yet fixed
Affected version<v1.0.0v1.1.1 (latest)
Detection methodManual testingCoverage-guided fuzzing

Both vulnerabilities share the same function and the same root cause category: insufficient validation of inputs in the offset-arithmetic-heavy Delete() implementation. The 2020 fix addressed the infinite loop but did not add comprehensive input validation across all code paths in Delete().

Impact Assessment

Any Go service that accepts JSON from untrusted sources and calls jsonparser.Delete() on that input is vulnerable. The Delete() function is commonly used in JSON transformation pipelines — for example, removing sensitive fields from a JSON document before logging or forwarding it.

In practice, exploitation requires that attacker-controlled data reaches a Delete() call without prior validation. Common scenarios include: API proxies that strip fields from request bodies, logging middleware that redacts sensitive keys, and data transformation pipelines that process external JSON events.

The panic is unrecovered by default in Go, meaning it will terminate the goroutine and — without a top-level recover() in the request handler — crash the entire process. This gives the vulnerability a direct, reliable denial-of-service impact.

CVSS 3.1 Base Score: 7.5 (High)
Vector: AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Suggested Fix

Add a bounds check before the slice operation at parser.go:729:

// Before:
return data[offset:]

// After:
if offset < 0 {
    return data
}
return data[offset:]

A more comprehensive fix would audit all offset computations in Delete() and related functions to ensure no negative values can reach slice operations.

Disclosure Timeline

  • February 19, 2026 — Vulnerability discovered via fuzzing
  • February 19, 2026 — Issue filed at github.com/buger/jsonparser/issues/275
  • February 19, 2026 — Reported to Go vulnerability database (x/vulndb)
  • March 5, 2026 — Public disclosure deadline (14 days)

References