Where
-Infinity
0

7 vulnerabilities have been posted to https://github.com/jqlang/jq/security - 6 this week and one in March that I don't see in the list archives. Fixes appear to be available in their github repo, but not yet in a release.

https://github.com/jqlang/jq/security/advisories/GHSA-q3h9-m34w-h76f reports: Integer overflow in jvpstringappend and jvpstringcopyreplacebad allows heap buffer overflow

Affected versions: 1.8.1

Summary ------- An integer overflow in jvpstringappend() in src/jv.c causes a heap buffer overflow when concatenating strings whose combined length exceeds 2^31 bytes.

Details ------- The internal function jvpstringappend() computes the new buffer allocation size as:

// src/jv.c:1187 uint32t allocsz = (currlen + len) 2; if (allocsz < 32) allocsz = 32;

Both currlen and len are uint32t. When currlen + len >= 2^31, the multiplication by 2 overflows the 32-bit unsigned integer, wrapping allocsz to a small value (potentially 0, clamped to 32). The subsequent memcpy operations copy currlen + len bytes into the undersized buffer, causing a heap buffer overflow. The lengthhashed field ((currlen + len) << 1) suffers the same overflow, corrupting the stored string length.

Arrays and objects already have size limits, but strings have no equivalent bounds check. We have to limit the size of string so that the length does not overflow.

Similar vulnerability exists in jvpstringcopyreplacebad, too. [See GHSA for PoC] Impact ------ CWE-190 (Integer Overflow or Wraparound) leading to CWE-122 (Heap-based Buffer Overflow).

Any user or system that evaluates untrusted jq queries is affected. Attacker can easily crash the jq process by sending a crafted jq query. If the system uses a fixed jq query (that does not concatenate the input strings many times), attacker needs to send a huge JSON input to make it crash. Heap corruption may allow further exploitation depending on the allocator and environment. All versions of jq through 1.8.1 and current master version are affected.

Fix --- This issue was fixed by https://github.com/jqlang/jq/commit/e47e56d226519635768e6aab2f38f0ab037c09e5

Severity: High - 8.2 / 10 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H CVE ID: CVE-2026-32316 https://github.com/jqlang/jq/security/advisories/GHSA-2hhh-px8h-355p says: Out-of-Bounds Read in jvparsesized() Error Formatting for Non-NUL-Terminated Counted Buffers

Summary ------- libjq exposes jvparsesized(const char string, int length) as a counted-buffer JSON parsing API, but its parse-error path later treats the same buffer as a NUL-terminated C string. If a caller passes malformed JSON in a non-NUL-terminated buffer, the error construction logic can read past the caller-supplied length, causing an out-of-bounds read.

Details ------- The vulnerable path is:

jvparsesized() -> jvparsesizedcustomflags() -> jvparsersetbuf(&parser, string, length, 0) -> parse failure -> jvstringfmt("%s (while parsing '%s')", ..., string)

Relevant code:

src/jv.h (line 245) src/jvparse.c (line 865) src/jvparse.c (line 896) src/jv.c (line 1528)

The parser correctly accepts a (pointer, length) pair, but when building the error message it formats string with %s, which causes vsnprintf() to continue reading memory until a \0 is found. This makes the error path ignore the explicit buffer length and turns a counted-buffer API into an unbounded read sink.

Reachability:

Real external source: any libjq consumer calling jvparsesized() with a counted buffer.

In-project internal uses such as fromjson and lexer paths also reach jvparsesized(), but those pass jq-managed strings that are already NUL-terminated, so the practical attack surface is the public API rather than the normal jq CLI path. [See GHSA for PoC] Impact ------

Only libjq is affected. A caller that uses jvparsesized() on untrusted malformed JSON in a non-NUL-terminated buffer can trigger an out-of-bounds read during error construction. Depending on memory layout and how the returned error string is logged or exposed, this can lead to memory disclosure or process termination.

Severity: Moderate CVE ID: CVE-2026-39979 Weaknesses: CWE-125 Out-of-bounds Read Credits: @HO-9 Reporter https://github.com/jqlang/jq/commit/2f09060afab23fe9390cce7cb860b10416e1bf5f states that it fixes CVE-2026-39979.

https://github.com/jqlang/jq/security/advisories/GHSA-32cx-cvvh-2wj9 advises: Embedded-NUL Truncation in jq CLI JSON Input Path Causes Prefix-Only Validation of Malformed Input

Summary ------- The normal jq CLI JSON input path uses fgets() and then derives the valid byte length with strlen() when parsing JSON input without a newline. If the input contains an embedded NUL byte, jq truncates the already-read buffer at the NUL and passes only the benign prefix to the JSON parser. As a result, jq may accept malformed input by validating only the prefix before the NUL.

Details ------- The reachable CLI path is:

CLI file/stdin input -> jqutilinputaddinput() / stdin default -> jqutilinputsetparser(..., jvparsernew(...)) -> jqutilinputnextinput() -> jqutilinputreadmore() -> strlen(state->buf) -> jvparsersetbuf(state->parser, state->buf, state->bufvalidlen, !islast)

Relevant code:

src/main.c (line 361) src/main.c (line 653) src/main.c (line 664) src/main.c (line 671) src/util.c (line 315) src/util.c (line 320) src/util.c (line 432)

The flaw is that the code does not use the actual number of bytes read by fgets(). Instead it uses strlen(state->buf), which stops at the first embedded NUL. Trailing bytes after the NUL may already have been consumed from the input stream, but they are silently excluded from parsing.

This is realistically reachable because it affects the stock jq CLI file and stdin parsing path used by end users. [See GHSA for PoC] Observed error:

jq: Bad JSON in --slurpfile ...: Invalid numeric literal at line 1, column 17

Impact

This issue can cause validation bypass in workflows that rely on jq to validate untrusted JSON before forwarding, storing, or otherwise acting on the original bytes. An attacker can place a benign JSON prefix before an embedded NUL and append malicious trailing data after it. jq may accept the prefix as valid JSON while silently ignoring the suffix, creating a parser differential between jq and downstream components that process the full input.

Severity: Low CVE ID: CVE-2026-33948 Weaknesses: No CWEs Credits: @HO-9 https://github.com/jqlang/jq/commit/6374ae0bcdfe33a18eb0ae6db28493b1f34a0a5b says it fixes CVE-2026-33948.

https://github.com/jqlang/jq/security/advisories/GHSA-xwrw-4f8h-rjvg states: Unbounded Recursion in jvsetpath() / jvgetpath() / delpathssorted()

Affected versions: <= 1.8.1

Summary ------- The jvsetpath(), jvgetpath(), and delpathssorted() functions in src/jvaux.c use unbounded recursion where the recursion depth equals the length of a caller-supplied path array. There is no depth limit check. When a path array with ~60,000 or more elements is supplied — either constructed by a jq filter expression or provided directly in attacker-controlled JSON input — the C call stack is exhausted, causing a segmentation fault (SIGSEGV) and immediate process crash.

This vulnerability bypasses the MAXPARSINGDEPTH (10,000) limit that protects the JSON parser, because path arrays can be constructed programmatically to arbitrary lengths without being constrained by parsing depth. Critically, the path array can be sourced entirely from attacker-controlled JSON input, making this exploitable in scenarios where a trusted jq filter processes untrusted data. [See GHSA for code analysis and PoC] Impact ------ - Denial of Service (Crash): Any jq process that calls setpath, getpath, or delpaths with a sufficiently long path array will crash with SIGSEGV. This is an unrecoverable crash — no error handling is possible. - Bypass of existing depth limits: The JSON parser's MAXPARSINGDEPTH (10,000) does not protect against this because path arrays are constructed at the jq runtime level, not during JSON parsing. An attacker can embed a flat array of 65,000 integers in a JSON document (only ~200 KB) that causes a crash when used as a path. - Affected real-world scenarios: - Web services using jq to transform or extract data from user-submitted JSON - CI/CD pipelines processing untrusted configuration or API responses with jq - Shell scripts that use setpath/getpath/delpaths on paths derived from input data - Any application embedding libjq where path arguments can be influenced by external input - Note: Unlike memory corruption vulnerabilities, stack overflow from recursion is generally not exploitable for code execution on modern systems with guard pages. The impact is limited to denial of service.

Severity: Moderate - 6.2 / 10 CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H CVE ID: CVE-2026-33947 Weaknesses: CWE-674 Uncontrolled Recursion Credits: @bg0d-glitch https://github.com/jqlang/jq/commit/fb59f1491058d58bdc3e8dd28f1773d1ac690a1f declares that it fixes CVE-2026-33947.

https://github.com/jqlang/jq/security/advisories/GHSA-6gc3-3g9p-xx28 announces: jq strindices missing runtime type checks lead to crash and limited memory disclosure

Affected versions: 1.8.1-dev commit 69785bf

Summary ------- strindices is the C builtin used by indices / index / rindex for string inputs. Its wrapper passes both arguments straight to jvstringindexes() without checking that they are strings, and jvstringindexes() itself only uses assert(). In release builds those checks disappear under -DNDEBUG. strindices(0) is enough to crash jq, and the same bug also gives an attacker controlled pointer dereference and a limited read/probe primitive.

Details ------- commit 69785bf77f86e2ea1b4a20ca86775916889e91c9, strindices is implemented in src/builtin.c like this

static jv fstringindexes(jqstate jq, jv a, jv b) { return jvstringindexes(a, b); }

jvstringindexes() in src/jv.c then blindly assumes both given args are strings:

jv jvstringindexes(jv j, jv k) { assert(JVPHASKIND(j, JVKINDSTRING)); assert(JVPHASKIND(k, JVKINDSTRING)); const char jstr = jvstringvalue(j); const char idxstr = jvstringvalue(k); }

In a debug build the assertions fire. In a normal release build they are compiled out, and jq dereferences j.u.ptr as if it were a valid jvpstring .

When the assertions are gone, jvstringvalue() treats j.u.ptr as a string header and jvstringlengthbytes() reads a length from that same fake object. This results in either 1. an easy crash with invalid input 2. a limited read primitive when a crafted number is used so its bit pattern is treated as a pointer. The number being crafted matters because default jq builds use decnum. A plain numeric literal doesn't give control of u.ptr, but arithmetic such as this does: (<bit-cast double> + 0) reaches jvnumber(double) and stores the IEEE-754 bits of that double in the same union field which is later read as u.ptr

PoC --- Crash: jq -n 'strindices(0)'

Controlled pointer dereference:

import struct, subprocess

def asdouble(u64): return struct.unpack("<d", struct.pack("<Q", u64))[0]

# because we want jstr = addr, the fake jvpstring sits 16 bytes earlier addr = 0x4141414141414151 expr = f"({asdouble(addr - 16)!r} + 0) | strindices(\"\\u0000\")" result = subprocess.run(["jq", "-n", expr]) print(result.returncode) # sigsegv in python

Impact ------

Anything that runs untrusted jq filters against a release build can be crashed very easily. If the system uses a fixed jq query (such that does not use the internal strindices filter), it is not affected. The same bug also gives limited read behavior because values which are not strings can be treated as fake string objects and walked by strindices. In a real deployment that means an attacker can use the exit status as a mapped/unmapped probe, and in favorable cases can get some bytes back through the strindices position output.

Severity: Moderate - 6.1 / 10 CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:H CVE ID: CVE-2026-39956 Weaknesses: CWE-125 Out-of-bounds Read CWE-476 NULL Pointer Dereference CWE-843 Access of Resource Using Incompatible Type ('Type Confusion') Credits: @tlsbollei Reporter https://github.com/jqlang/jq/commit/fdf8ef0f0810e3d365cdd5160de43db46f57ed03 claims to fix CVE-2026-39956.

https://github.com/jqlang/jq/security/advisories/GHSA-wwj8-gxm6-jc29 expresses: Algorithmic complexity DoS via hardcoded MurmurHash3 seed

Summary ------- jq uses MurmurHash3 with a compile-time constant seed 0x432A9843 (src/jv.c:1200) for all JSON object hash table operations. Since the seed is hardcoded and publicly visible in source, an attacker can precompute hash collisions offline and construct a JSON object where all keys hash to the same bucket. This degrades operations from O(1) to O(n), making any jq expression O(n^2). Only ~100KB of crafted JSON needed — far more practical than the heap overflow issues.

Details ------- File: src/jv.c, line 1200

static const uint32t HASHSEED = 0x432A9843;

Used at line 1219:

static uint32t jvpvalhash(jv val) { uint32t h1 = HASHSEED; // ... MurmurHash3 body ... }

Many languages randomize hash seeds at startup to prevent this (Python 3.3+, Ruby 1.9+, Perl 5.18+). jq does not. [See GHSA for PoC] Severity: High - 7.5 / 10 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H CVE ID: CVE-2026-40164 Weaknesses: CWE-328 Use of Weak Hash CWE-407 Inefficient Algorithmic Complexity Credits: @AsafMeizner Reporter https://github.com/jqlang/jq/commit/0c7d133c3c7e37c00b6d46b658a02244fdd3c784 appears to mitigate this, but does not list the CVE id.

https://github.com/jqlang/jq/security/advisories/GHSA-gf4g-95wj-4q4r discloses: jq args2obj() Heap-Use-After-Free Vulnerability Report

Affected versions: 1.8.1 (commit ref:b33a763)

Summary ------- A potential heap-use-after-free vulnerability exists in jq's args2obj() function at src/execute.c:1218. The bug is in the public jqcompileargs() API's array argument processing path: when called with an array of 2+ named argument entries, freed heap memory is read (CWE-416); with 1+ entries, a double-free occurs (CWE-415). The standard jq CLI binary is not affected, as it always passes an object (not an array) to args2obj(). It appears the bug was introduced in commit b279713e (2017-02-26) and affects jq HEAD (jq-1.8.1-32-gb33a763).

Details ------- Root cause: The strings kk ("name") and vk ("value") are allocated once before the loop but passed directly to jvobjectget(), which consumes (frees) both its arguments. On the first iteration, kk and vk are freed. On subsequent iterations, they are dangling pointers — jvpstringhash() reads from freed heap memory. After the loop, jvfree(kk) / jvfree(vk) trigger a double-free.

// src/execute.c:1208-1223 jv kk = jvstring("name"); jv vk = jvstring("value"); jvarrayforeach(args, i, v) r = jvobjectset(r, jvobjectget(jvcopy(v), kk), jvobjectget(v, vk)); jvfree(kk); // double-free: already freed by jvobjectget() jvfree(vk);

Git history: Commit b279713e refactored inline array processing in jqcompileargs() into the args2obj() helper. The original code created fresh jvstring("name") / jvstring("value") on each iteration; the refactored version hoisted them into locals but failed to account for jvobjectget() consuming its key argument.

[See GHSA for PoC]

Impact

CWE-416 (Use After Free) / CWE-415 (Double Free). The vulnerability is reachable through the public jqcompileargs() API when called with array arguments — not through the CLI binary. Heap corruption from the UAF and double-free may lead to arbitrary code execution via corrupted heap metadata, though no exploit has been demonstrated. All downstream consumers of jqcompileargs() that pass array arguments have been affected since commit b279713e (2017-02-26).

My name is Scott Seal, and I work at Trail of Bits. Per the instructions of my employer, I am required to provide the following disclosure:

This bug was found as part of follow-on research from DARPA's AI Cyber Challenge (AIXCC), where Trail of Bits built Buttercup, a Cyber Reasoning System that combines static analysis, fuzzing, and large language models to find and fix vulnerabilities.

https://www.darpa.mil/research/programs/ai-cyber https://www.trailofbits.com/buttercup/

Severity: Low CVE ID: No known CVE Weaknesses CWE-415 Double Free CWE-416 Use After Free Credits: @sseal Reporter https://github.com/jqlang/jq/commit/3985b80ce50bd75c6eb5a97cb3348c3f835ca8e0 includes "Fixes GHSA-gf4g-95wj-4q4r."

-- -Alan Coopersmith- alan.coopersmith () oracle com Oracle Solaris Engineering - https://blogs.oracle.com/solaris

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203