From fbee8f48bac154aeb6edfbd79792181ac19914a3 Mon Sep 17 00:00:00 2001 From: august Date: Sun, 23 Aug 2026 08:01:54 -0700 Subject: [PATCH] Reject raw NUL bytes in the parser instead of silently truncating tokens (#3606) --- src/jv_parse.c | 5 +++++ tests/shtest | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/jv_parse.c b/src/jv_parse.c index 0fb4247b..ceccc4d6 100644 --- a/src/jv_parse.c +++ b/src/jv_parse.c @@ -563,6 +563,11 @@ typedef enum { static chclass classify(char c) { switch (c) { + case '\0': + // RFC 8259 forbids raw NUL in JSON text. Treating it as a literal lets it + // slip into the token buffer, where check_literal() reads the buffer as a + // NUL-terminated C string and silently truncates the token. Reject it. + return INVALID; case ' ': case '\t': case '\r': diff --git a/tests/shtest b/tests/shtest index 47741390..7e34dc52 100755 --- a/tests/shtest +++ b/tests/shtest @@ -119,6 +119,27 @@ printf '" ~\\u007f"\n' > $d/expected printf "\"$(printf '\\%03o' 32 126 127)\"" | $JQ '.' > $d/out 2>&1 cmp $d/out $d/expected +# Regression test for #3110: a raw NUL byte outside of a string must be a clean +# parse error, not silently truncate the surrounding token. Previously +# `printf '12\0003'` printed 12 and dropped the trailing 3. +cat > $d/expected < $d/out 2>&1; then + printf 'Error expected but jq exited successfully\n' 1>&2 + exit 2 +fi +cmp $d/out $d/expected +# A NUL at the very start of the input is rejected too. +cat > $d/expected < $d/out 2>&1; then + printf 'Error expected but jq exited successfully\n' 1>&2 + exit 2 +fi +cmp $d/out $d/expected + ## Test --exit-status data='{"i": 1}\n{"i": 2}\n{"i": 3}\n' printf "$data" | $JQ --exit-status 'select(.i==1)' > /dev/null 2>&1