ReviewOS

zig-utils/zig-js

JSON.stringify: securely seed replacer property-list deduplication

#757
Closed chris opened this 9 days ago ·
9 days ago

Parents: #493, #473 Related: #755, #756

Problem

JSON.stringify builds the replacer-array PropertyList with std.StringHashMapUnmanaged, whose default string context has a process-predictable seed. Every accepted String/Number property name comes from observable, attacker-controlled input, so an adversary can precompute collision-heavy replacer lists and force avoidable worst-case deduplication cost.

Scope

  • Replace only the replacer PropertyList membership index with an exact-byte custom hash context.
  • Lazily draw one secure seed per stringify invocation when the first accepted property name is deduplicated; no replacer, callable replacer, empty array, and ignored-only arrays must not request entropy or allocate the membership table.
  • Reuse the interpreter-owned cryptographic seed stream and fail closed if its initial entropy request fails.
  • Preserve first-occurrence ordering, duplicate suppression, String/Number wrapper coercion and abrupt completion, encoded NUL keys, integer-like names, wide keys, GC lifetimes, and OOM behavior.

No-workaround rules

  • No input blacklist, property-count cap, deterministic fallback seed, hash-only equality, skipped duplicate suppression, reordered coercion, or reduced replacer semantics.
  • No stack, queue, job, Promise, Worker, or Map/Set iterator implementation changes.

Acceptance

  • Replacer PropertyList membership uses a non-default per-stringify secure hash context.
  • Non-array/callable/empty/ignored-only paths remain lazy and allocate no membership hash table.
  • Duplicate, escaped, NUL-bearing, integer-like, wrapper-derived, and adversarial-width keys retain exact output/coercion order.
  • Focused normal and TSan tests pass without leaks or races.
  • Exact-parent JSON Test262 inventory has zero regressions.

Implemented by 36ad04d4.

Evidence: JSON units 16/16 with zero leaks; focused native witness 1/1; focused TSan witness and observable end-to-end paths 2/2 with zero races; exact-parent test/built-ins/JSON remains 165 pass, 0 fail (0 flips, 0 regressions).

9 days ago

Completed on main by 36ad04d4. The implementation uses one lazy secure context per accepted replacer PropertyList, exact-byte equality, and allocation-failure-atomic context publication; it adds no deterministic fallback, input cap, or semantic shortcut.

Sign in to comment on this issue.