Skip to content

json2.decode infinite-loops on unterminated array inside object ({"a":[1,21) #2

Description

@hunterjsb

Summary

json2.decode hangs forever (spinning, allocating without bound) on certain truncated inputs — specifically an unterminated array nested inside an object. The input is 10 bytes. This is worse than the deep-nesting crash (#TBD): a hang that consumes memory is a harder-to-detect denial of service than a clean crash.

Reproduction

import json2

fn main() {
	_ := json2.decode[json2.Any]('{"a":[1,21') or { println('errored cleanly'); return }
	println('parsed')
}
$ v run hang.v
   ... never returns; RSS climbs until OOM

A bare unterminated array ([1,) errors correctly with EOF: expected array value. The pathology is the array unterminated inside an object value — the parser fails to propagate EOF and loops.

Expected

Return a syntax error on EOF, as the bare-array case already does.

Impact

Ten-byte denial-of-service against anything decoding untrusted JSON. Truncated request bodies are a normal occurrence (dropped connections), so this is reachable without a malicious client.

Environment

V 0.5.2 5889122, Linux x86_64.

Note

Surfaced via adversarial fuzzing of a JSON-decoding library. Worked around downstream by rejecting unbalanced/truncated documents in a pre-scan. Filing on the fork to track for upstream.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions