CVE-2026-39956 Overview
CVE-2026-39956 is a type confusion vulnerability in jq, a widely-used command-line JSON processor. The vulnerability exists in the _strindices builtin function within src/builtin.c, where arguments are passed directly to jv_string_indexes() without proper type verification. The underlying jv_string_indexes() function in src/jv.c relies solely on assert() checks for type validation, which are stripped in release builds compiled with the -DNDEBUG flag.
This flaw enables an attacker to crash jq trivially with crafted input such as _strindices(0). More critically, by carefully crafting a numeric value whose IEEE-754 bit pattern maps to a chosen pointer, an attacker can achieve a controlled pointer dereference and limited memory read/probe primitive.
Critical Impact
Any deployment that evaluates untrusted jq filters against a release build is vulnerable to denial of service and potential information disclosure through controlled memory reads.
Affected Products
- jq releases compiled with -DNDEBUG after commit 69785bf77f86e2ea1b4a20ca86775916889e91c9
- Release builds of jq that strip assert() checks
- Systems processing untrusted jq filters
Discovery Timeline
- 2026-04-13 - CVE-2026-39956 published to NVD
- 2026-04-14 - Last updated in NVD database
Technical Details for CVE-2026-39956
Vulnerability Analysis
The vulnerability is classified as CWE-125 (Out-of-Bounds Read) and stems from insufficient input validation in jq's string indexing functionality. The f_string_indexes() function in src/builtin.c directly passes its arguments to jv_string_indexes() without verifying that both arguments are actually string types.
In debug builds, assert() statements in jv_string_indexes() would catch type mismatches. However, release builds compiled with the -DNDEBUG preprocessor definition strip these assertions entirely, leaving no runtime protection against type confusion attacks. When a numeric value is passed instead of a string, the function interprets the value's internal representation as string data, leading to out-of-bounds memory access.
Root Cause
The root cause is the absence of runtime type checks in the f_string_indexes() function. The code incorrectly assumes that callers will always provide string arguments, and defensive assertions are removed in production builds. This creates a disconnect between the expected behavior during development (with assertions enabled) and the actual behavior in deployed release builds.
Attack Vector
The attack requires local access with user interaction, as an attacker must convince a user or automated system to evaluate a malicious jq filter. The attack can be executed by:
- Supplying a jq filter containing _strindices(0) or similar non-string arguments
- The function processes the numeric value without type validation
- The IEEE-754 bit pattern of the crafted number is interpreted as a pointer
- This results in controlled pointer dereference allowing memory probing
}
static jv f_string_indexes(jq_state *jq, jv a, jv b) {
+ if (jv_get_kind(a) != JV_KIND_STRING) {
+ jv_free(b);
+ return type_error(a, "cannot be searched, as it is not a string");
+ }
+ if (jv_get_kind(b) != JV_KIND_STRING) {
+ jv_free(a);
+ return type_error(b, "is not a string");
+ }
return jv_string_indexes(a, b);
}
Source: GitHub Commit fdf8ef0f0810e3d365cdd5160de43db46f57ed03
Detection Methods for CVE-2026-39956
Indicators of Compromise
- Unexpected jq process crashes or segmentation faults when processing filters
- Abnormal memory access patterns in jq processes
- Error logs showing type-related failures in string indexing operations
- Unusual jq filter inputs containing _strindices with non-string arguments
Detection Strategies
- Monitor jq process execution for crashes or unexpected termination signals (SIGSEGV)
- Implement input validation on jq filters before execution to detect suspicious patterns like _strindices( followed by numeric values
- Deploy application-level logging to capture jq filter contents for forensic analysis
- Use memory sanitizers in testing environments to detect out-of-bounds read attempts
Monitoring Recommendations
- Enable core dump collection for jq processes to analyze crash patterns
- Implement rate limiting on systems that accept untrusted jq filters
- Monitor system logs for repeated jq failures that may indicate exploitation attempts
- Consider sandboxing jq execution in environments processing untrusted input
How to Mitigate CVE-2026-39956
Immediate Actions Required
- Update jq to a version containing commit fdf8ef0f0810e3d365cdd5160de43db46f57ed03 or later
- Audit systems that evaluate untrusted jq filters and implement input validation
- Consider restricting jq filter capabilities in production environments
- Review deployment configurations to ensure jq is not processing arbitrary user-supplied filters
Patch Information
The vulnerability has been patched in commit fdf8ef0f0810e3d365cdd5160de43db46f57ed03. The fix adds explicit runtime type checks in the f_string_indexes() function to verify that both arguments are strings before passing them to jv_string_indexes(). If non-string arguments are detected, the function now returns appropriate type error messages instead of proceeding with potentially dangerous operations.
For detailed patch information, see the GitHub Security Advisory and the patch commit.
Workarounds
- Avoid processing untrusted jq filters in release builds until patched
- Implement a filter allowlist that restricts use of _strindices and related builtins
- Deploy jq in sandboxed environments with limited memory access capabilities
- Compile jq without the -DNDEBUG flag to retain assertion checks (note: this may impact performance)
# Configuration example
# Rebuild jq from source with assertions enabled (temporary workaround)
git clone https://github.com/jqlang/jq.git
cd jq
git checkout fdf8ef0f0810e3d365cdd5160de43db46f57ed03
autoreconf -i
./configure
make
sudo make install
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.


