Summary
Jayway JsonPath accepts oversized numeric literals in filter expressions and parses them into BigDecimal during path compilation without a numeric-token length guard. An application that exposes JSONPath filtering to clients can be forced to spend unbounded CPU and allocation work before producing a result, making request-worker exhaustion practical with repeated oversized filters. This includes security relevant effects but I was not able to find any private channels to report this which is why I decided to file it via github issue.
Affected
Root cause
The public string entry point JsonPath.read(String, String, Predicate...) passes the caller-supplied JSONPath text into DocumentContext.read at json-path/src/main/java/com/jayway/jsonpath/JsonPath.java:549. JsonContext.read only rejects an empty path before looking it up in the path cache at json-path/src/main/java/com/jayway/jsonpath/internal/JsonContext.java:75; on a cache miss, pathFromCache compiles the supplied path at json-path/src/main/java/com/jayway/jsonpath/internal/JsonContext.java:221. The compiler accepts inline filter tokens and forwards the complete filter criteria to FilterCompiler.compile at json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java:478, which creates a compiler over that attacker-controlled filter string at json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java:52. Numeric operands fall through readLiteral into readNumberLiteral at json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java:108; readNumberLiteral then advances across every numeric character with no maximum length check, slices the full token, and passes it to ValueNode.createNumberNode at json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java:328 and json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java:333. The sink is NumberNode(CharSequence), which calls new BigDecimal(num.toString()) on the full attacker-sized token at json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNodes.java:286 and json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNodes.java:287. This is the same structural oversized numeric-token resource exhaustion pattern as GHSA-72hv-8253-57qq, with the JSONPath filter compiler as the parser front end and BigDecimal construction as the expensive sink.
PoC
with an arbitrary json doc.json and a text file with a large number large-number.txt, run the java below
import com.jayway.jsonpath.JsonPath;
import java.nio.file.Files;
import java.nio.file.Path;
public class JaywayBigDecimalProbe {
public static void main(String[] args) throws Exception {
Path inputs = Path.of(args[0]);
String doc = Files.readString(inputs.resolve("doc.json"));
String numericLiteral = Files.readString(inputs.resolve("large-number.txt")).trim();
long started = System.nanoTime();
Object result = JsonPath.read(doc, "$[?(@.x == " + numericLiteral + ")]");
long elapsedMs = (System.nanoTime() - started) / 1_000_000L;
if (numericLiteral.length() != 1024 * 1024) {
throw new AssertionError("unexpected generated token length=" + numericLiteral.length());
}
if (result == null) {
throw new AssertionError("JsonPath.read returned null");
}
System.out.println("JAYWAY_JSONPATH_FILTER_BIGDECIMAL_UNBOUNDED token_digits="
+ numericLiteral.length() + " elapsed_ms=" + elapsedMs
+ " result_class=" + result.getClass().getName());
}
}
Suggested fix
--- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java
+++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java
@@ -47,6 +47,8 @@
private static final char PATTERN = '/';
private static final char IGNORE_CASE = 'i';
+ private static final int MAX_NUMBER_LITERAL_LENGTH = 1000;
+
private CharacterIndex filter;
public static Filter compile(String filterString) {
@@ -327,6 +329,9 @@
while (filter.inBounds() && filter.isNumberCharacter(filter.position())) {
filter.incrementPosition(1);
+ if (filter.position() - begin > MAX_NUMBER_LITERAL_LENGTH) {
+ throw new InvalidPathException("Number literal length exceeds the maximum allowed length of " + MAX_NUMBER_LITERAL_LENGTH);
+ }
}
CharSequence numberLiteral = filter.subSequence(begin, filter.position());
logger.trace("NumberLiteral from {} to {} -> [{}]", begin, filter.position(), numberLiteral);
Reported by Team Atlanta.
Summary
Jayway JsonPath accepts oversized numeric literals in filter expressions and parses them into
BigDecimalduring path compilation without a numeric-token length guard. An application that exposes JSONPath filtering to clients can be forced to spend unbounded CPU and allocation work before producing a result, making request-worker exhaustion practical with repeated oversized filters. This includes security relevant effects but I was not able to find any private channels to report this which is why I decided to file it via github issue.Affected
Root cause
The public string entry point
JsonPath.read(String, String, Predicate...)passes the caller-supplied JSONPath text intoDocumentContext.readatjson-path/src/main/java/com/jayway/jsonpath/JsonPath.java:549.JsonContext.readonly rejects an empty path before looking it up in the path cache atjson-path/src/main/java/com/jayway/jsonpath/internal/JsonContext.java:75; on a cache miss,pathFromCachecompiles the supplied path atjson-path/src/main/java/com/jayway/jsonpath/internal/JsonContext.java:221. The compiler accepts inline filter tokens and forwards the complete filter criteria toFilterCompiler.compileatjson-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java:478, which creates a compiler over that attacker-controlled filter string atjson-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java:52. Numeric operands fall throughreadLiteralintoreadNumberLiteralatjson-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java:108;readNumberLiteralthen advances across every numeric character with no maximum length check, slices the full token, and passes it toValueNode.createNumberNodeatjson-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java:328andjson-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java:333. The sink isNumberNode(CharSequence), which callsnew BigDecimal(num.toString())on the full attacker-sized token atjson-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNodes.java:286andjson-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNodes.java:287. This is the same structural oversized numeric-token resource exhaustion pattern as GHSA-72hv-8253-57qq, with the JSONPath filter compiler as the parser front end andBigDecimalconstruction as the expensive sink.PoC
with an arbitrary json
doc.jsonand a text file with a large numberlarge-number.txt, run the java belowSuggested fix
Reported by Team Atlanta.