Skip to content

CVE-2026-32316: Verified Repro With Script Download

CVE-2026-32316: jq: integer overflow in jv string concat triggers heap buffer overflow on large strings

CVE-2026-32316 is verified against jq · github. Affected versions: <= 1.8.1. Fixed in 1.8.2. Vulnerability class: Buffer Overflow. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00170.

REPRO-2026-00170 jq · github Buffer Overflow Variant found May 28, 2026 CVE entry ↗ .txt
Severity
HIGH
CVSS
8.2
Confidence
HIGH
Reproduced in
32m 33s
Tool calls
182
Spend
$1.56
01 · Overview

What Is CVE-2026-32316?

CVE-2026-32316 is a high-severity integer overflow in jq's jv_string_concat (used by the + string operator and by add over an array of strings) that leads to a heap buffer overflow when concatenated strings exceed 2^31 bytes. Pruva reproduced it (reproduction REPRO-2026-00170).

02 · Severity & CVSS

CVE-2026-32316 Severity & CVSS Score

CVE-2026-32316 is rated high severity, with a CVSS base score of 8.2 out of 10.

HIGH threat level
8.2 / 10 CVSS base
Weakness CWE-122

High — serious impact or readily exploitable. Prioritize remediation.

03 · Affected Versions

Affected jq Versions

jq · github versions <= 1.8.1 are affected.

How to Reproduce CVE-2026-32316

$ pruva-verify REPRO-2026-00170
or curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00170/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-32316

Reproduced by Pruva's autonomous agents — 182 tool calls over 33 min. Full root-cause analysis and the complete transcript are below.

Variants tested

Systematic variant analysis of CVE-2026-32316 (jq integer overflow in string concatenation). Four materially distinct alternate triggers were tested (add, join, reduce, interpolation). All reproduced on the vulnerable build (jq-1.8.1) and were caught by the fixed build (commit e47e56d). No bypass of the patch was foun…

How the agent worked 678 events · 182 tool calls · 33 min
33 minDuration
182Tool calls
163Reasoning steps
678Events
4Dead-ends
Agent activity over 33 min
Support
18
Repro
288
Variant
368
0:0032:33

Root Cause and Exploit Chain for CVE-2026-32316

Versions: <= 1.8.1

CVE-2026-32316 is an integer overflow vulnerability in jq's string concatenation path (jvp_string_append in src/jv.c). When two strings whose combined length exceeds INT_MAX (2,147,483,647 bytes) are concatenated, the allocation size (currlen + len) * 2 overflows uint32_t and wraps to a tiny value. A subsequent memcpy then writes gigabytes of data into the undersized heap buffer, causing a heap-based buffer overflow (CWE-190 → CWE-122).

  • Package/component affected: jq (command-line JSON processor), specifically jv_string_concat / jvp_string_append in src/jv.c
  • Affected versions: <= 1.8.1
  • Risk level: High (CVSS 3.1: 7.5)
  • Consequences: Any service or pipeline that runs jq filters on attacker-controlled input can be crashed or have heap memory corrupted when the attacker supplies JSON strings that, when concatenated, exceed INT_MAX bytes. This is reachable in common patterns such as add over an array of large strings or direct + operations.

Root Cause

In src/jv.c, jvp_string_append computes the new allocation size using 32-bit unsigned arithmetic:

uint32_t allocsz = (currlen + len) * 2;

When currlen + len >= INT_MAX (≈ 2.1 GB), the product can exceed UINT32_MAX and wrap around to a very small number (as small as 0, which is then clamped to 32 bytes). The function then allocates this tiny buffer via jvp_string_alloc(allocsz) and copies the full concatenated length with memcpy, writing far past the allocated region.

The same overflow pattern existed in jvp_string_copy_replace_bad, where length * 3 + 1 could wrap uint32_t for very large inputs.

Fix commit: e47e56d226519635768e6aab2f38f0ab037c09e5 — adds explicit 64-bit overflow checks:

if ((uint64_t)currlen + len >= INT_MAX) {
    jv_free(string);
    return jv_invalid_with_msg(jv_string("String too long"));
}

Reproduction Steps

  1. Execute repro/reproduction_steps.sh
  2. The script clones the jq repository, builds two binaries with AddressSanitizer:
    • Vulnerable: tag jq-1.8.1
    • Fixed: commit e47e56d226519635768e6aab2f38f0ab037c09e5
  3. The script runs the trigger program on both binaries:
    "A" * 1073741824 as $a | $a + $a
    
    This creates a 1 GB string and concatenates it with another 1 GB string, producing a total length of 2 GB (> INT_MAX).
  4. Expected evidence:
    • Vulnerable build: AddressSanitizer reports heap-buffer-overflow in jvp_string_append (called from jv_string_concatbinop_plus)
    • Fixed build: jq exits gracefully with the error message String too long

Evidence

  • Vulnerable ASAN output: logs/vulnerable_stderr.txt

    ==7265==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x506000001311
    WRITE of size 1073741824 at 0x506000001311 thread T0
        #0 memcpy
        #1 jvp_string_append src/jv.c:1191
        #2 jv_string_concat src/jv.c:1501
        #3 binop_plus src/builtin.c:96
    

    The buffer allocated was only 49 bytes, confirming the integer-overflow-induced undersized allocation.

  • Fixed output: logs/fixed_stderr.txt

    jq: error (at <unknown>): String too long
    
  • Runtime manifest: repro/runtime_manifest.json

Recommendations / Next Steps

  1. Upgrade jq to 1.8.2 or later (or any build containing commit e47e56d). The fix is minimal and precisely targeted at the overflow conditions.
  2. Input size limits: For deployments that cannot immediately upgrade, enforce maximum JSON input sizes well below 2 GB to reduce the likelihood of triggering the overflow.
  3. Regression testing: Add automated tests that attempt string concatenation near INT_MAX boundaries to prevent re-introduction of this bug class.
  4. Audit other integer size calculations: Review other uses of uint32_t for buffer-size math in src/jv.c (e.g., jvp_string_copy_replace_bad) to ensure similar overflows are not present elsewhere.

Additional Notes

  • Idempotency confirmed: repro/reproduction_steps.sh was run twice consecutively; both runs produced identical ASAN crash output on the vulnerable build and identical graceful error output on the fixed build.
  • Edge cases / limitations: The reproduction requires a host with enough RAM to hold two ~1 GB strings plus ASAN overhead (≈ 3–4 GB peak). On memory-constrained systems, the trigger can be adjusted by reducing the multiplier, but the combined concatenated length must still exceed INT_MAX (2,147,483,647 bytes) to hit the vulnerable code path.

Variant Analysis & Alternative Triggers for CVE-2026-32316

Versions: versions tested: jq-1.8.1 (vulnerable), e47e56d (fixed)

CVE-2026-32316 is an integer-overflow-to-heap-buffer-overflow in jq's string concatenation path (jvp_string_append in src/jv.c). The fix (commit e47e56d) adds an INT_MAX length check to jvp_string_append and to jvp_string_copy_replace_bad. Because every string-growth operation in jq ultimately routes through jvp_string_append, the fix comprehensively blocks all known alternate triggers—including add over arrays of strings, join, reduce-based incremental concatenation, and string interpolation. No bypass was found after testing four materially distinct variant entry points on the fixed build.

Fix Coverage / Assumptions

  • Invariant: The fix assumes that no legitimate jq operation should produce a string whose length reaches INT_MAX (2,147,483,647 bytes).
  • Covered paths: jvp_string_append is the single chokepoint for all string growth. Its callers include jv_string_concat, jv_string_append_buf, jv_string_append_str, jv_string_append_codepoint, jv_string_repeat, jv_dump_term (via put_buf), escape_string, and all formatting builtins (@csv, @tsv, @uri, @base64, @html).
  • Not covered: jvp_string_new and jvp_string_empty_new do not enforce an INT_MAX limit. However, every caller of those constructors either pre-validates the length (e.g., jv_string_repeat) or derives it from an already-bounded string, so they do not create a exploitable path for this specific CVE.

Variant / Alternate Trigger

Four distinct variant attempts were encoded and executed:

  1. add over an array of large strings (alternate jq builtin)

    • Trigger: ["A" * 1073741824, "A" * 1073741824] | add
    • Path: f_plusbinop_plusjv_string_concatjvp_string_append
  2. join("") over an array of large strings (alternate jq-level entry point)

    • Trigger: ["A" * 1073741824, "A" * 1073741824] | join("")
    • Path: builtin.jq:def joinreduce with +binop_plusjv_string_concatjvp_string_append
  3. Incremental reduce string building (step-wise growth)

    • Trigger: reduce range(3) as $i (""; . + "A" * 1000000000)
    • Path: jq_nextbinop_plusjv_string_concatjvp_string_append (caught when cumulative length crosses INT_MAX)
  4. String interpolation with large strings (syntactic sugar for concatenation)

    • Trigger: "A" * 1073741824 as $a | "\($a + $a)"
    • Path: compilation emits +binop_plusjv_string_concatjvp_string_append

All four variants reproduced the crash on the vulnerable build (jq-1.8.1) and were rejected with String too long on the fixed build (e47e56d).

  • Package/component: jq (src/jv.c)
  • Affected versions tested: jq-1.8.1 (vulnerable), e47e56d (fixed)
  • Risk level: High (CVSS 3.1: 7.5)
  • Consequences: If a bypass existed, any service running jq filters on attacker-controlled input (CI pipelines, log shippers, k8s admission webhooks, etc.) could still be crashed or have heap memory corrupted via an unpatched string-concatenation path.

Root Cause

The root cause is 32-bit unsigned integer overflow in the buffer-size computation (currlen + len) * 2 inside jvp_string_append. When currlen + len exceeds INT_MAX, the product wraps around in uint32_t, causing a tiny allocation followed by a massive memcpy. The fix adds a 64-bit pre-check so that any append operation whose combined length would reach INT_MAX is aborted with a jq-level error.

Because this same jvp_string_append function is the exclusive sink for all string growth in jq, patching it closes every downstream concatenation path simultaneously.

Reproduction Steps

  1. Run vuln_variant/reproduction_steps.sh.
  2. The script tests four variant triggers on both the vulnerable (jq-1.8.1) and fixed (e47e56d) binaries.
  3. For each variant:
    • Vulnerable: AddressSanitizer reports a heap-buffer-overflow in jvp_string_append.
    • Fixed: jq exits gracefully with jq: error (at <unknown>): String too long.

Evidence

  • Log directory: logs/
  • Variant 1 (add):
    • Vulnerable: logs/variant1_vuln.txt — ASAN heap-buffer-overflow in jvp_string_append
    • Fixed: logs/variant1_fixed.txtString too long
  • Variant 2 (join):
    • Fixed: logs/variant2_fixed.txtString too long
  • Variant 3 (reduce):
    • Vulnerable: logs/variant3_vuln.txt — ASAN memcpy-param-overlap / heap corruption
    • Fixed: logs/variant3_fixed.txtString too long
  • Variant 4 (interpolation):
    • Vulnerable: logs/variant4_vuln.txt — ASAN heap-buffer-overflow in jvp_string_append
    • Fixed: logs/variant4_fixed.txtString too long

Environment: x86_64 Linux, jq built with -fsanitize=address, 15 GB RAM available.

Recommendations / Next Steps

  1. The fix is complete for this CVE. No additional code paths need to be patched to prevent the specific uint32_t → heap-buffer-overflow chain.
  2. Defense-in-depth: Add an INT_MAX guard to jvp_string_new and jvp_string_empty_new so that all string constructors (not just the two growth functions) enforce the same maximum length boundary.
  3. Regression tests: Add automated test cases for:
    • add over an array whose combined string length exceeds INT_MAX
    • join with a large separator on large array elements
    • reduce accumulating a string past INT_MAX
  4. Audit other integer arithmetic: Review remaining int-sized buffer growth in the JSON parser (jv_parse.c token buffer: tokenlen = tokenlen*2 + 256) and array reallocation to prevent separate overflow bugs.

Additional Notes

  • The reproduction script is idempotent: running it a second time reuses existing log files and produces identical output.
  • gsub with expansion on a 1 GB string was attempted but is infeasibly slow (regex engine scans the entire input character-by-character). It is not needed as a distinct variant because gsub compiles to reduce + +, which routes through the already-tested binop_plusjvp_string_append path.

CVE-2026-32316 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:000:48
0:00
session startedaccounts/fireworks/models/kimi-k2p6 · cve-2026-32316 · cve-2026
0:22
0:22
0:22
error

Unknown error

0:23
0:23
web search
0:23
error

Unknown error

0:35
0:35
extract_facts
no facts extracted
0:35
0:35
0:35
supportrepro
0:37
0:38
0:38
0:38
0:39
0:39
0:39
0:39
0:46
0:47
$git clone --depth=100 https://github.com/jqlang/jq.git external/jq && cd external/jq && git log --oneline --all | head -20
1.1s
{"cwd":"/root/.pruva/runs/cve-2026-32316_20260528-102301","duration_ms":1138,"exit_code":0,"stderr":"Cloning into 'external/jq'...\n","stdout":"df924ea Fix undefined pointer arithmetic in UTF-8 helpers\na829f67 Fix one-byte over-read in BASE64_DECODE_TABLE (#3547)\n7122866 Guard deep structural equality and comparison recursion (#3539)\nf58787c Detect circular module imports to prevent stack overflow\n9d223f1 Reject embedded NUL bytes in module import paths\n9761ceb Reject numeric literals longer than DEC_MAX_DIGITS (999999999)\n532ccea Limit recursive object merge depth to prevent stack overflow\n33d7bce Avoid stack overflow when freeing deeply nested values\n7316e5c Fix CI to add `artifact-metadata` permission for actions/attest (#3530)\n63751f8 Fix signed-int overflow in `tokenadd` to prevent buffer overflow\n5f2a14d docs: fix \"happened\" spelling in tutorial changelog entries (#3525)\n5a015de Fix NUL truncation in program files loaded with -f\n01b3cde Fix signed-int overflow in `stack_reallocate`\nd1a1256 Limit the containment check depth\n8702073 build(deps): bump lxml from 6.0.2 to 6.1.0 in /docs (#3526)\n1eaa31a build(deps): bump actions/upload-pages-artifact from 4 to 5 in… [truncated]
0:48
08 · How to Fix

How to Fix CVE-2026-32316

Upgrade jq · github to 1.8.2 or later.

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-32316 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-32316

How does the jq string-concatenation heap overflow work?

A jq filter (e.g. add over an array of strings, or repeated + concatenation) is run over attacker-controlled JSON strings whose combined length exceeds roughly 2.1 GB. The 32-bit size computation in jvp_string_append wraps around to a tiny allocation, and the following memcpy writes gigabytes of data past the undersized heap buffer, corrupting adjacent heap memory (CWE-190 to CWE-122).

Which versions of jq are affected by CVE-2026-32316, and where is it fixed?

Versions <= 1.8.1 are affected. It is fixed in 1.8.2.

How severe is CVE-2026-32316?

High severity (CVSS 3.1: 7.5) -- any service or pipeline that runs jq filters over attacker-controlled input (CI pipelines, log shippers, observability stacks, k8s admission webhooks) can be crashed or have heap memory corrupted, given the attacker can supply roughly 2 GB of string content.

How can I reproduce CVE-2026-32316?

Download the verified script from this page and run it in an isolated environment against jq <= 1.8.1 with sufficient available memory. It concatenates JSON strings whose combined length exceeds INT_MAX bytes via add/+ and shows the resulting heap buffer overflow.
11 · References

References for CVE-2026-32316

Authoritative sources for CVE-2026-32316 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.