GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

GCVE-1988-2026-0078

Vulnerability from gna-1988 – Published: 2026-09-07 13:20 – Updated: 2026-09-11 08:13
VLAI
Title
UltraJSON v5.13.0-6-g733f9e1 Length-Boundary Violation Causes Out-of-Bounds Read During Incomplete JSON Parsing
Summary
UltraJSON contains an out-of-bounds read in its native C JSON decoder when processing certain incomplete JSON values supplied through an explicitly length-bounded input buffer. The affected native entry point, JSON_DecodeObject(), accepts both a buffer pointer and an explicit buffer length: JSON_DecodeObject( JSONObjectDecoder *dec, const char *buffer, size_t cbBuffer ) The decoder establishes cbBuffer as the logical boundary of the supplied input. However, several parsing paths can advance the internal input cursor to this boundary and subsequently dereference it without first verifying that additional input remains. A minimal one-byte input containing only: [ is sufficient to reproduce the issue. When an exact one-byte, non-NUL-terminated heap allocation containing 0x5b ( [) is passed to JSON_DecodeObject() with cbBuffer == 1, decode_array() consumes the opening bracket and advances the decoder cursor to the end of the supplied input. decode_array() then calls SkipWhitespace(). Because SkipWhitespace() immediately dereferences the cursor without verifying that it remains below ds->end, it performs a one-byte read immediately beyond the supplied buffer. AddressSanitizer confirms the resulting out-of-bounds read: ERROR: AddressSanitizer: heap-buffer-overflow READ of size 1 0x502000000011 is located 0 bytes after 1-byte region [0x502000000010,0x502000000011) SUMMARY: AddressSanitizer: heap-buffer-overflow /src/./src/ujson/lib/ultrajsondec.c:317:13 in SkipWhitespace Malformed or truncated JSON should result in a normal decoding error. It should not cause the native decoder to access memory outside the explicitly supplied input boundary. Affected Attack Surface The vulnerable native decoder entry point is: src/ujson/lib/ultrajsondec.c through: JSON_DecodeObject( JSONObjectDecoder *dec, const char *buffer, size_t cbBuffer ) JSON_DecodeObject() explicitly accepts a buffer length rather than requiring the supplied buffer to be NUL-terminated. The decoder initializes its input boundaries using: ds.start = (char *) buffer; ds.end = ds.start + cbBuffer; ds.end therefore represents the exclusive upper boundary of the supplied input. Any parser operation that dereferences ds.start or another cursor derived from it must first establish that the cursor is strictly less than ds.end. The vulnerable parser path fails to enforce this invariant. Vulnerable Code The confirmed invalid access occurs in SkipWhitespace(): static FASTCALL_ATTR void FASTCALL_MSVC SkipWhitespace(struct DecoderState *ds) { char *offset = ds->start; for (;;) { switch (*offset) { case ' ': case '\t': case '\r': case '\n': offset++; break; default: ds->start = offset; return; } } } The function immediately evaluates: *offset without checking: offset < ds->end Consequently, if a caller reaches SkipWhitespace() after consuming the final byte of the supplied input: offset == ds->start == ds->end the first switch (*offset) operation accesses memory outside the length-bounded input. Proof of Concept The PoC deliberately avoids relying on an implicit trailing NUL byte. It allocates exactly one byte: buffer = malloc(1); copies the payload into that allocation: memcpy(buffer, "[", 1); and invokes the decoder with the exact allocation length: JSON_DecodeObject(&decoder, buffer, 1); The supplied allocation therefore contains only: Address N: 0x5b There is intentionally no second byte belonging to the allocation. This is consistent with the native API contract because JSON_DecodeObject() receives the input length explicitly through cbBuffer. Reproduction From the repository root: scripts/repro_decoder_oob_asan.sh array /tmp/ujson-asan-poc.log The harness reports: seed=array payload=[ payload_hex=5b FUZZ seed=array len=1 payload="[" hex=5b The process subsequently terminates under AddressSanitizer after detecting the invalid memory access. AddressSanitizer Evidence AddressSanitizer identifies the vulnerability as a heap-buffer overflow involving a one-byte read: ERROR: AddressSanitizer: heap-buffer-overflow READ of size 1 at 0x502000000011 thread T0 #0 ... in SkipWhitespace /src/./src/ujson/lib/ultrajsondec.c:317:13 #1 ... in decode_array /src/./src/ujson/lib/ultrajsondec.c:617:5 #2 ... in decode_any /src/./src/ujson/lib/ultrajsondec.c:780:24 #3 ... in JSON_DecodeObject /src/./src/ujson/lib/ultrajsondec.c:822:9 #4 ... in run_seed /src/./scripts/decoder_oob_asan_harness.c:150:18 #5 ... in main /src/./scripts/decoder_oob_asan_harness.c:171:16 0x502000000011 is located 0 bytes after 1-byte region [0x502000000010,0x502000000011) Ron Edgerson Vulnerability Researcher & Exploit Developer CVE Research | Binary Exploitation | Application & Systems Security Responsible Disclosure β€’ Proof-of-Concept Development 🌐 https://github.com/ob1sec πŸ”— https://www.linkedin.com/in/ronedgerson1 <https://linkedin.com/in/yourhandle> _______________________________________________ Sent through the Full Disclosure mailing list https://nmap.org/mailman/listinfo/fulldisclosure Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
Impacted products
Vendor Product Version CPE status
Ultrajson UltraJSON Affected: unknown
guessed Create a notification for this product.
Credits

{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "UltraJSON",
          "vendor": "Ultrajson",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "Ron E"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "UltraJSON contains an out-of-bounds read in its native C JSON decoder when\nprocessing certain incomplete JSON values supplied through an explicitly\nlength-bounded input buffer.\n\nThe affected native entry point, JSON_DecodeObject(), accepts both a buffer\npointer and an explicit buffer length:\n\nJSON_DecodeObject(\n    JSONObjectDecoder *dec,\n    const char *buffer,\n    size_t cbBuffer\n)\n\nThe decoder establishes cbBuffer as the logical boundary of the supplied\ninput. However, several parsing paths can advance the internal input cursor\nto this boundary and subsequently dereference it without first verifying\nthat additional input remains.\n\nA minimal one-byte input containing only:\n\n[\n\nis sufficient to reproduce the issue.\n\nWhen an exact one-byte, non-NUL-terminated heap allocation containing 0x5b (\n[) is passed to JSON_DecodeObject() with cbBuffer == 1, decode_array()\nconsumes the opening bracket and advances the decoder cursor to the end of\nthe supplied input.\n\ndecode_array() then calls SkipWhitespace(). Because SkipWhitespace()\nimmediately dereferences the cursor without verifying that it remains below\nds-\u003eend, it performs a one-byte read immediately beyond the supplied buffer.\n\nAddressSanitizer confirms the resulting out-of-bounds read:\n\nERROR: AddressSanitizer: heap-buffer-overflow\nREAD of size 1\n\n0x502000000011 is located 0 bytes after 1-byte region\n[0x502000000010,0x502000000011)\n\nSUMMARY: AddressSanitizer: heap-buffer-overflow\n/src/./src/ujson/lib/ultrajsondec.c:317:13\nin SkipWhitespace\n\nMalformed or truncated JSON should result in a normal decoding error. It\nshould not cause the native decoder to access memory outside the explicitly\nsupplied input boundary.\nAffected Attack Surface\n\nThe vulnerable native decoder entry point is:\n\nsrc/ujson/lib/ultrajsondec.c\n\nthrough:\n\nJSON_DecodeObject(\n    JSONObjectDecoder *dec,\n    const char *buffer,\n    size_t cbBuffer\n)\n\nJSON_DecodeObject() explicitly accepts a buffer length rather than\nrequiring the supplied buffer to be NUL-terminated.\n\nThe decoder initializes its input boundaries using:\n\nds.start = (char *) buffer;\nds.end = ds.start + cbBuffer;\n\nds.end therefore represents the exclusive upper boundary of the supplied\ninput.\n\nAny parser operation that dereferences ds.start or another cursor derived\nfrom it must first establish that the cursor is strictly less than ds.end.\n\nThe vulnerable parser path fails to enforce this invariant.\nVulnerable Code\n\nThe confirmed invalid access occurs in SkipWhitespace():\n\nstatic FASTCALL_ATTR void FASTCALL_MSVC\nSkipWhitespace(struct DecoderState *ds)\n{\n    char *offset = ds-\u003estart;\n\n    for (;;)\n    {\n        switch (*offset)\n        {\n            case \u0027 \u0027:\n            case \u0027\\t\u0027:\n            case \u0027\\r\u0027:\n            case \u0027\\n\u0027:\n                offset++;\n                break;\n\n            default:\n                ds-\u003estart = offset;\n                return;\n        }\n    }\n}\n\nThe function immediately evaluates:\n\n*offset\n\nwithout checking:\n\noffset \u003c ds-\u003eend\n\nConsequently, if a caller reaches SkipWhitespace() after consuming the\nfinal byte of the supplied input:\n\noffset == ds-\u003estart == ds-\u003eend\n\nthe first switch (*offset) operation accesses memory outside the\nlength-bounded input.\nProof of Concept\n\nThe PoC deliberately avoids relying on an implicit trailing NUL byte.\n\nIt allocates exactly one byte:\n\nbuffer = malloc(1);\n\ncopies the payload into that allocation:\n\nmemcpy(buffer, \"[\", 1);\n\nand invokes the decoder with the exact allocation length:\n\nJSON_DecodeObject(\u0026decoder, buffer, 1);\n\nThe supplied allocation therefore contains only:\n\nAddress N:\n    0x5b\n\nThere is intentionally no second byte belonging to the allocation.\n\nThis is consistent with the native API contract because JSON_DecodeObject()\nreceives the input length explicitly through cbBuffer.\nReproduction\n\nFrom the repository root:\n\nscripts/repro_decoder_oob_asan.sh array /tmp/ujson-asan-poc.log\n\nThe harness reports:\n\nseed=array\npayload=[\npayload_hex=5b\n\nFUZZ seed=array len=1 payload=\"[\" hex=5b\n\nThe process subsequently terminates under AddressSanitizer after detecting\nthe invalid memory access.\nAddressSanitizer Evidence\n\nAddressSanitizer identifies the vulnerability as a heap-buffer overflow\ninvolving a one-byte read:\n  ERROR: AddressSanitizer: heap-buffer-overflow\n  READ of size 1 at 0x502000000011 thread T0\n      #0 ... in SkipWhitespace /src/./src/ujson/lib/ultrajsondec.c:317:13\n      #1 ... in decode_array /src/./src/ujson/lib/ultrajsondec.c:617:5\n      #2 ... in decode_any /src/./src/ujson/lib/ultrajsondec.c:780:24\n      #3 ... in JSON_DecodeObject /src/./src/ujson/lib/ultrajsondec.c:822:9\n      #4 ... in run_seed /src/./scripts/decoder_oob_asan_harness.c:150:18\n      #5 ... in main /src/./scripts/decoder_oob_asan_harness.c:171:16\n\n  0x502000000011 is located 0 bytes after 1-byte region\n  [0x502000000010,0x502000000011)\n\nRon Edgerson\nVulnerability Researcher \u0026 Exploit Developer\n\nCVE Research | Binary Exploitation | Application \u0026 Systems Security\nResponsible Disclosure \u2022 Proof-of-Concept Development\n\n\ud83c\udf10 https://github.com/ob1sec\n\ud83d\udd17 https://www.linkedin.com/in/ronedgerson1\n\u003chttps://linkedin.com/in/yourhandle\u003e\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-09-11T08:13:07Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description",
            "exploit"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Aug/106"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Aug/106"
        },
        {
          "url": "https://github.com/ob1sec"
        },
        {
          "url": "https://linkedin.com/in/yourhandle"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        },
        {
          "url": "https://www.linkedin.com/in/ronedgerson1"
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Aug/106"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "UltraJSON v5.13.0-6-g733f9e1 Length-Boundary Violation Causes Out-of-Bounds Read During Incomplete JSON Parsing",
      "x_gcve": [
        {
          "recordType": "advisory",
          "relationships": [],
          "vulnId": "GCVE-1988-2026-0078",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Aug/106",
            "automated": true,
            "contentSha256": "03c25d20f7df6472c3b422f80972411affc74955c0bf6de1f890b7714e6658c8",
            "evidenceScore": 9,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Aug/106",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-08-22T12:44:03Z"
          }
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-09-07T13:20:21Z",
    "dateUpdated": "2026-09-11T08:13:07Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0078"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…

Loading…