From 532ccea6080ed6758f39fe9f6208a44b665023d2 Mon Sep 17 00:00:00 2001 From: itchyny Date: Tue, 5 May 2026 22:44:02 +0900 Subject: [PATCH] Limit recursive object merge depth to prevent stack overflow This fixes CVE-2026-43896. --- src/jv.c | 25 +++++++++++++++++++++++-- tests/jq.test | 9 +++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/jv.c b/src/jv.c index feb68d1a..84fafef6 100644 --- a/src/jv.c +++ b/src/jv.c @@ -1899,16 +1899,33 @@ jv jv_object_merge(jv a, jv b) { return a; } -jv jv_object_merge_recursive(jv a, jv b) { +#ifndef MAX_OBJECT_MERGE_DEPTH +#define MAX_OBJECT_MERGE_DEPTH (10000) +#endif + +static jv jvp_object_merge_recursive(jv a, jv b, int depth) { assert(JVP_HAS_KIND(a, JV_KIND_OBJECT)); assert(JVP_HAS_KIND(b, JV_KIND_OBJECT)); + if (depth > MAX_OBJECT_MERGE_DEPTH) { + jv_free(a); + jv_free(b); + return jv_invalid_with_msg(jv_string("Object merge too deep")); + } + jv_object_foreach(b, k, v) { jv elem = jv_object_get(jv_copy(a), jv_copy(k)); if (jv_is_valid(elem) && JVP_HAS_KIND(elem, JV_KIND_OBJECT) && JVP_HAS_KIND(v, JV_KIND_OBJECT)) { - a = jv_object_set(a, k, jv_object_merge_recursive(elem, v)); + jv merged = jvp_object_merge_recursive(elem, v, depth + 1); + if (!jv_is_valid(merged)) { + jv_free(k); + jv_free(a); + jv_free(b); + return merged; + } + a = jv_object_set(a, k, merged); } else { jv_free(elem); a = jv_object_set(a, k, v); @@ -1919,6 +1936,10 @@ jv jv_object_merge_recursive(jv a, jv b) { return a; } +jv jv_object_merge_recursive(jv a, jv b) { + return jvp_object_merge_recursive(a, b, 0); +} + /* * Object iteration (internal helpers) */ diff --git a/tests/jq.test b/tests/jq.test index 8094a5b6..9a80341f 100644 --- a/tests/jq.test +++ b/tests/jq.test @@ -2602,3 +2602,12 @@ true try (reduce range(10001) as $_ ([]; [.]) as $x | $x | contains($x)) catch . null "Containment check too deep" + +# regression test for CVE-2026-43896 +reduce range(10000) as $_ ({}; {a: .}) as $x | $x * $x | length +null +1 + +try (reduce range(10001) as $_ ({}; {a: .}) as $x | $x * $x) catch . +null +"Object merge too deep"