{
  "_class" : "io.jenkins.plugins.analysis.core.restapi.ReportApi",
  "issues" : [
    {
      "addedAt" : 0,
      "authorEmail" : "-",
      "authorName" : "-",
      "baseName" : "hazelcast-5.3.8.jar",
      "category" : "",
      "columnEnd" : 0,
      "columnStart" : 0,
      "commit" : "-",
      "description" : "",
      "fileName" : "/usr/local/tomcat/webapps/govway.war/WEB-INF/lib/hazelcast-5.3.8.jar",
      "fingerprint" : "FALLBACK-2c9ace5a",
      "lineEnd" : 1,
      "lineStart" : 1,
      "message" : "GHSA-72hv-8253-57qq: LanguageSpecificPackageVulnerability\u000a\u000ajackson-core: Number Length Constraint Bypass in Async Parser Leads to Potential DoS Condition\u000a\u000aFor additional help see: **Vulnerability GHSA-72hv-8253-57qq**\u000a| Severity | Package | Fixed Version | Link |\u000a| --- | --- | --- | --- |\u000a|HIGH|com.fasterxml.jackson.core:jackson-core|2.18.6, 2.21.1, 3.1.0|[GHSA-72hv-8253-57qq](https://github.com/advisories/GHSA-72hv-8253-57qq)|\u000a\u000a### Summary\u000aThe non-blocking (async) JSON parser in `jackson-core` bypasses the `maxNumberLength` constraint (default: 1000 characters) defined in `StreamReadConstraints`. This allows an attacker to send JSON with arbitrarily long numbers through the async parser API, leading to excessive memory allocation and potential CPU exhaustion, resulting in a Denial of Service (DoS).\u000a\u000aThe standard synchronous parser correctly enforces this limit, but the async parser fails to do so, creating an inconsistent enforcement policy.\u000a\u000a### Details\u000aThe root cause is that the async parsing path in `NonBlockingUtf8JsonParserBase` (and related classes) does not call the methods responsible for number length validation.\u000a\u000a- The number parsing methods (e.g., `_finishNumberIntegralPart`) accumulate digits into the `TextBuffer` without any length checks.\u000a- After parsing, they call `_valueComplete()`, which finalizes the token but does **not** call `resetInt()` or `resetFloat()`.\u000a- The `resetInt()`/`resetFloat()` methods in `ParserBase` are where the `validateIntegerLength()` and `validateFPLength()` checks are performed.\u000a- Because this validation step is skipped, the `maxNumberLength` constraint is never enforced in the async code path.\u000a\u000a### PoC\u000aThe following JUnit 5 test demonstrates the vulnerability. It shows that the async parser accepts a 5,000-digit number, whereas the limit should be 1,000.\u000a\u000a```java\u000apackage tools.jackson.core.unittest.dos;\u000a\u000aimport java.nio.charset.StandardCharsets;\u000a\u000aimport org.junit.jupiter.api.Test;\u000a\u000aimport tools.jackson.core.*;\u000aimport tools.jackson.core.exc.StreamConstraintsException;\u000aimport tools.jackson.core.json.JsonFactory;\u000aimport tools.jackson.core.json.async.NonBlockingByteArrayJsonParser;\u000a\u000aimport static org.junit.jupiter.api.Assertions.*;\u000a\u000a/**\u000a * POC: Number Length Constraint Bypass in Non-Blocking (Async) JSON Parsers\u000a *\u000a * Authors: sprabhav7, rohan-repos\u000a * \u000a * maxNumberLength default = 1000 characters (digits).\u000a * A number with more than 1000 digits should be rejected by any parser.\u000a *\u000a * BUG: The async parser never calls resetInt()/resetFloat() which is where\u000a * validateIntegerLength()/validateFPLength() lives. Instead it calls\u000a * _valueComplete() which skips all number length validation.\u000a *\u000a * CWE-770: Allocation of Resources Without Limits or Throttling\u000a */\u000aclass AsyncParserNumberLengthBypassTest {\u000a\u000a    private static final int MAX_NUMBER_LENGTH = 1000;\u000a    private static final int TEST_NUMBER_LENGTH = 5000;\u000a\u000a    private final JsonFactory factory = new JsonFactory();\u000a\u000a    // CONTROL: Sync parser correctly rejects a number exceeding maxNumberLength\u000a    @Test\u000a    void syncParserRejectsLongNumber() throws Exception {\u000a        byte[] payload = buildPayloadWithLongInteger(TEST_NUMBER_LENGTH);\u000a\u0009\u0009\u000a\u0009\u0009// Output to console\u000a        System.out.println(\"[SYNC] Parsing \" + TEST_NUMBER_LENGTH + \"-digit number (limit: \" + MAX_NUMBER_LENGTH + \")\");\u000a        try {\u000a            try (JsonParser p = factory.createParser(ObjectReadContext.empty(), payload)) {\u000a                while (p.nextToken() != null) {\u000a                    if (p.currentToken() == JsonToken.VALUE_NUMBER_INT) {\u000a                        System.out.println(\"[SYNC] Accepted number with \" + p.getText().length() + \" digits — UNEXPECTED\");\u000a                    }\u000a                }\u000a            }\u000a            fail(\"Sync parser must reject a \" + TEST_NUMBER_LENGTH + \"-digit number\");\u000a        } catch (StreamConstraintsException e) {\u000a            System.out.println(\"[SYNC] Rejected with StreamConstraintsException: \" + e.getMessage());\u000a        }\u000a    }\u000a\u000a    // VULNERABILITY: Async parser accepts the SAME number that sync rejects\u000a    @Test\u000a    void asyncParserAcceptsLongNumber() throws Exception {\u000a        byte[] payload = buildPayloadWithLongInteger(TEST_NUMBER_LENGTH);\u000a\u000a        NonBlockingByteArrayJsonParser p =\u000a            (NonBlockingByteArrayJsonParser) factory.createNonBlockingByteArrayParser(ObjectReadContext.empty());\u000a        p.feedInput(payload, 0, payload.length);\u000a        p.endOfInput();\u000a\u000a        boolean foundNumber = false;\u000a        try {\u000a            while (p.nextToken() != null) {\u000a                if (p.currentToken() == JsonToken.VALUE_NUMBER_INT) {\u000a                    foundNumber = true;\u000a                    String numberText = p.getText();\u000a                    assertEquals(TEST_NUMBER_LENGTH, numberText.length(),\u000a                        \"Async parser silently accepted all \" + TEST_NUMBER_LENGTH + \" digits\");\u000a                }\u000a            }\u000a            // Output to console\u000a            System.out.println(\"[ASYNC INT] Accepted number with \" + TEST_NUMBER_LENGTH + \" digits — BUG CONFIRMED\");\u000a            assertTrue(foundNumber, \"Parser should have produced a VALUE_NUMBER_INT token\");\u000a        } catch (StreamConstraintsException e) {\u000a            fail(\"Bug is fixed — async parser now correctly rejects long numbers: \" + e.getMessage());\u000a        }\u000a        p.close();\u000a    }\u000a\u000a    private byte[] buildPayloadWithLongInteger(int numDigits) {\u000a        StringBuilder sb = new StringBuilder(numDigits + 10);\u000a        sb.append(\"{\\\"v\\\":\");\u000a        for (int i = 0; i < numDigits; i++) {\u000a            sb.append((char) ('1' + (i % 9)));\u000a        }\u000a        sb.append('}');\u000a        return sb.toString().getBytes(StandardCharsets.UTF_8);\u000a    }\u000a}\u000a\u000a```\u000a\u000a\u000a### Impact\u000aA malicious actor can send a JSON document with an arbitrarily long number to an application using the async parser (e.g., in a Spring WebFlux or other reactive application). This can cause:\u000a1.  **Memory Exhaustion:** Unbounded allocation of memory in the `TextBuffer` to store the number's digits, leading to an `OutOfMemoryError`.\u000a2.  **CPU Exhaustion:** If the application subsequently calls `getBigIntegerValue()` or `getDecimalValue()`, the JVM can be tied up in O(n^2) `BigInteger` parsing operations, leading to a CPU-based DoS.\u000a\u000a### Suggested Remediation\u000a\u000aThe async parsing path should be updated to respect the `maxNumberLength` constraint. The simplest fix appears to ensure that `_valueComplete()` or a similar method in the async path calls the appropriate validation methods (`resetInt()` or `resetFloat()`) already present in `ParserBase`, mirroring the behavior of the synchronous parsers.\u000a\u000a**NOTE:** This research was performed in collaboration with [rohan-repos](https://github.com/rohan-repos)\u000a\u000aPackage: com.fasterxml.jackson.core:jackson-core\u000aInstalled Version: 2.15.2\u000aVulnerability GHSA-72hv-8253-57qq\u000aSeverity: HIGH\u000aFixed Version: 2.18.6, 2.21.1, 3.1.0\u000aLink: [GHSA-72hv-8253-57qq](https://github.com/advisories/GHSA-72hv-8253-57qq)",
      "moduleName" : "",
      "origin" : "trivy",
      "originName" : "Trivy Security Scanner",
      "packageName" : "-",
      "reference" : "1430",
      "severity" : "HIGH",
      "toString" : "hazelcast-5.3.8.jar(1,0): GHSA-72hv-8253-57qq: : GHSA-72hv-8253-57qq: LanguageSpecificPackageVulnerability\u000a\u000ajackson-core: Number Length Constraint Bypass in Async Parser Leads to Potential DoS Condition\u000a\u000aFor additional help see: **Vulnerability GHSA-72hv-8253-57qq**\u000a| Severity | Package | Fixed Version | Link |\u000a| --- | --- | --- | --- |\u000a|HIGH|com.fasterxml.jackson.core:jackson-core|2.18.6, 2.21.1, 3.1.0|[GHSA-72hv-8253-57qq](https://github.com/advisories/GHSA-72hv-8253-57qq)|\u000a\u000a### Summary\u000aThe non-blocking (async) JSON parser in `jackson-core` bypasses the `maxNumberLength` constraint (default: 1000 characters) defined in `StreamReadConstraints`. This allows an attacker to send JSON with arbitrarily long numbers through the async parser API, leading to excessive memory allocation and potential CPU exhaustion, resulting in a Denial of Service (DoS).\u000a\u000aThe standard synchronous parser correctly enforces this limit, but the async parser fails to do so, creating an inconsistent enforcement policy.\u000a\u000a### Details\u000aThe root cause is that the async parsing path in `NonBlockingUtf8JsonParserBase` (and related classes) does not call the methods responsible for number length validation.\u000a\u000a- The number parsing methods (e.g., `_finishNumberIntegralPart`) accumulate digits into the `TextBuffer` without any length checks.\u000a- After parsing, they call `_valueComplete()`, which finalizes the token but does **not** call `resetInt()` or `resetFloat()`.\u000a- The `resetInt()`/`resetFloat()` methods in `ParserBase` are where the `validateIntegerLength()` and `validateFPLength()` checks are performed.\u000a- Because this validation step is skipped, the `maxNumberLength` constraint is never enforced in the async code path.\u000a\u000a### PoC\u000aThe following JUnit 5 test demonstrates the vulnerability. It shows that the async parser accepts a 5,000-digit number, whereas the limit should be 1,000.\u000a\u000a```java\u000apackage tools.jackson.core.unittest.dos;\u000a\u000aimport java.nio.charset.StandardCharsets;\u000a\u000aimport org.junit.jupiter.api.Test;\u000a\u000aimport tools.jackson.core.*;\u000aimport tools.jackson.core.exc.StreamConstraintsException;\u000aimport tools.jackson.core.json.JsonFactory;\u000aimport tools.jackson.core.json.async.NonBlockingByteArrayJsonParser;\u000a\u000aimport static org.junit.jupiter.api.Assertions.*;\u000a\u000a/**\u000a * POC: Number Length Constraint Bypass in Non-Blocking (Async) JSON Parsers\u000a *\u000a * Authors: sprabhav7, rohan-repos\u000a * \u000a * maxNumberLength default = 1000 characters (digits).\u000a * A number with more than 1000 digits should be rejected by any parser.\u000a *\u000a * BUG: The async parser never calls resetInt()/resetFloat() which is where\u000a * validateIntegerLength()/validateFPLength() lives. Instead it calls\u000a * _valueComplete() which skips all number length validation.\u000a *\u000a * CWE-770: Allocation of Resources Without Limits or Throttling\u000a */\u000aclass AsyncParserNumberLengthBypassTest {\u000a\u000a    private static final int MAX_NUMBER_LENGTH = 1000;\u000a    private static final int TEST_NUMBER_LENGTH = 5000;\u000a\u000a    private final JsonFactory factory = new JsonFactory();\u000a\u000a    // CONTROL: Sync parser correctly rejects a number exceeding maxNumberLength\u000a    @Test\u000a    void syncParserRejectsLongNumber() throws Exception {\u000a        byte[] payload = buildPayloadWithLongInteger(TEST_NUMBER_LENGTH);\u000a\u0009\u0009\u000a\u0009\u0009// Output to console\u000a        System.out.println(\"[SYNC] Parsing \" + TEST_NUMBER_LENGTH + \"-digit number (limit: \" + MAX_NUMBER_LENGTH + \")\");\u000a        try {\u000a            try (JsonParser p = factory.createParser(ObjectReadContext.empty(), payload)) {\u000a                while (p.nextToken() != null) {\u000a                    if (p.currentToken() == JsonToken.VALUE_NUMBER_INT) {\u000a                        System.out.println(\"[SYNC] Accepted number with \" + p.getText().length() + \" digits — UNEXPECTED\");\u000a                    }\u000a                }\u000a            }\u000a            fail(\"Sync parser must reject a \" + TEST_NUMBER_LENGTH + \"-digit number\");\u000a        } catch (StreamConstraintsException e) {\u000a            System.out.println(\"[SYNC] Rejected with StreamConstraintsException: \" + e.getMessage());\u000a        }\u000a    }\u000a\u000a    // VULNERABILITY: Async parser accepts the SAME number that sync rejects\u000a    @Test\u000a    void asyncParserAcceptsLongNumber() throws Exception {\u000a        byte[] payload = buildPayloadWithLongInteger(TEST_NUMBER_LENGTH);\u000a\u000a        NonBlockingByteArrayJsonParser p =\u000a            (NonBlockingByteArrayJsonParser) factory.createNonBlockingByteArrayParser(ObjectReadContext.empty());\u000a        p.feedInput(payload, 0, payload.length);\u000a        p.endOfInput();\u000a\u000a        boolean foundNumber = false;\u000a        try {\u000a            while (p.nextToken() != null) {\u000a                if (p.currentToken() == JsonToken.VALUE_NUMBER_INT) {\u000a                    foundNumber = true;\u000a                    String numberText = p.getText();\u000a                    assertEquals(TEST_NUMBER_LENGTH, numberText.length(),\u000a                        \"Async parser silently accepted all \" + TEST_NUMBER_LENGTH + \" digits\");\u000a                }\u000a            }\u000a            // Output to console\u000a            System.out.println(\"[ASYNC INT] Accepted number with \" + TEST_NUMBER_LENGTH + \" digits — BUG CONFIRMED\");\u000a            assertTrue(foundNumber, \"Parser should have produced a VALUE_NUMBER_INT token\");\u000a        } catch (StreamConstraintsException e) {\u000a            fail(\"Bug is fixed — async parser now correctly rejects long numbers: \" + e.getMessage());\u000a        }\u000a        p.close();\u000a    }\u000a\u000a    private byte[] buildPayloadWithLongInteger(int numDigits) {\u000a        StringBuilder sb = new StringBuilder(numDigits + 10);\u000a        sb.append(\"{\\\"v\\\":\");\u000a        for (int i = 0; i < numDigits; i++) {\u000a            sb.append((char) ('1' + (i % 9)));\u000a        }\u000a        sb.append('}');\u000a        return sb.toString().getBytes(StandardCharsets.UTF_8);\u000a    }\u000a}\u000a\u000a```\u000a\u000a\u000a### Impact\u000aA malicious actor can send a JSON document with an arbitrarily long number to an application using the async parser (e.g., in a Spring WebFlux or other reactive application). This can cause:\u000a1.  **Memory Exhaustion:** Unbounded allocation of memory in the `TextBuffer` to store the number's digits, leading to an `OutOfMemoryError`.\u000a2.  **CPU Exhaustion:** If the application subsequently calls `getBigIntegerValue()` or `getDecimalValue()`, the JVM can be tied up in O(n^2) `BigInteger` parsing operations, leading to a CPU-based DoS.\u000a\u000a### Suggested Remediation\u000a\u000aThe async parsing path should be updated to respect the `maxNumberLength` constraint. The simplest fix appears to ensure that `_valueComplete()` or a similar method in the async path calls the appropriate validation methods (`resetInt()` or `resetFloat()`) already present in `ParserBase`, mirroring the behavior of the synchronous parsers.\u000a\u000a**NOTE:** This research was performed in collaboration with [rohan-repos](https://github.com/rohan-repos)\u000a\u000aPackage: com.fasterxml.jackson.core:jackson-core\u000aInstalled Version: 2.15.2\u000aVulnerability GHSA-72hv-8253-57qq\u000aSeverity: HIGH\u000aFixed Version: 2.18.6, 2.21.1, 3.1.0\u000aLink: [GHSA-72hv-8253-57qq](https://github.com/advisories/GHSA-72hv-8253-57qq)",
      "type" : "GHSA-72hv-8253-57qq"
    }
  ],
  "size" : 1,
  "toString" : "1 warning (high: 1)"
}