WEAVEParse/WEAVEStep trust wire indices — OOB read+write
dog/WEAVE.c's codec is a zero-copy, entirely UNVALIDATED view over a 'W' blob the header itself flags as "may be attacker-influenced", and the merge/next decoders then dereference the parsed inserter/remover indices as raw array subscripts. WEAVEStep reads a token's inserter straight from the 'I' column (WEAVE.c:165) and remover ids from 'M' (:174-176) with NO bound against the commit-table length; those indices flow into ordp[_ins]++ (ADV_IDH, WEAVE.c:410) — a controllable OOB WRITE — and into commits[0][li] / rmap[li] (wmerge_decode, :552,561,564) — OOB reads. Separately WEAVEParse aliases byte-aligned TLV values as tok32c*/u64c* (:55-58) with no length-multiple or alignment check, so a 'K'/'C' value of non-multiple length is read 1-3 bytes past its end and mis-aligned loads are UB. The sibling HUNKu8sDrain already does the right thing (validate tok32Offset, length, aligned copy) — this is the precedent to mirror. Method: Issues.
WEAVE.c:410 #define ADV_IDH(INS) ... ordp[_ins]++ with
_ins = cur.inserter, ordp sized u64bDataLen(out_cmts)+1 (:402).
wmerge_decode WEAVE.c:552 commits[0][li], :561/564
rmap[li]/rmap[*r] (both sized nc); li = tk.inserter, unchecked.
WEAVEStep :165 u8sDrain32(c->ins,&out->inserter) and
:174-176 remover u32cs — never compared to $len(commits).
WEAVEParse :55-58 casts v[0]→tok32c*/u64c*; loop
guard toks[0]>=toks[1] is a pointer compare, so a 3-byte 'K' still enters WEAVEStep and reads a full 4-byte tok32. HUNK rejects via HUNKTOKLEN.
weave_scope_alive :976, weave_emit_membership :1283) is safe
ONLY because it routes indices through bounds-checked u1At; decode bypasses it.
WEAVEAlive (:117-132) slices text with UNCHECKED offsets: hi=tok32Offset(t)
(24-bit, ≤16 MiB) then a_part(u8c,seg,text,lo,hi-lo) with no hi<=$len(text) and no monotonicity check (a_part's bound is an assert, gone in release). WEAVEStep has these guards (:152,155); WEAVEAlive does not → OOB read of ~16 MiB (large hi) or a ~4 GiB read from hi-lo underflow (hi<lo).
< $len(commits),
'K' length a multiple of sizeof(tok32), 'C'/'A' a multiple of 8, and $len(anc) == $len(toks); return WEAVEFAIL (never OK) on violation.
hunk_drain_toks does; no raw dereference of a u8c*-derived tok32c*.
'W' blob can NEVER produce an OOB access downstream.dog/ libdog, ABC style; error codes RON60, WEAVE-prefixed, 10 chars max.
(wmerge_decode :526-581, weave_emit_decode :936-966, the inline pass-1 loop in wnext_diff :350-364) into a single validated decoder so the index check lives once, not thrice.
fuzz/WEAVE.c (and property) case feeding malformed
'I'/'M'/'K'/'C' records straight into WEAVEParse→WEAVEMerge/Next; existing fuzz only round-trips well-formed blobs.
WEAVEStep/WEAVEParse (inserter/remover < ncommits);
add the same hi<=$len(text) + monotonic-offset guards to WEAVEAlive.
anc==toks count; fix alignment.
DOG-013 reuse note: also swap the hand-rolled u64map :610-631 for HASHx and fix its u64map_cap u32 overflow).
WEAVEScope (:95-109) must reject an undersized into bitmap up front
instead of silently no-oping via u1sSet, and its ok64 return made real.
security validation gap, not the style. DOG-003 owns the WEAVE core format.
79612854 — WEAVEStep unchecked inserter/removers WEAVE.c:163-176, ADV_IDH ordp[_ins]++ :410, WEAVEParse raw tok32c*/u64c* casts :56-58, WEAVEAlive unchecked hi :116-131. NOTHING landed (no DOG-008 in the log); a WIP fix sits UNLANDED in worktree ~/src/DOG-008 (WEAVE.c + test/WEAVE01,04 modified).