Every HUNK renderer treats tok32Offset(...) (a 27-bit value taken verbatim from the wire) as a byte index into hk->text, but the TXT ('X') and TOK ('K') TLV records are drained independently with no cross-check, so a relayed/received hunk whose token offsets exceed the text length drives a$part/pointer-walk reads past hk->text. Separately the 'K' value bytes are aliased directly as tok32c*, an unaligned-load + length-mismatch hazard. The goal is to validate (and align) the token record once at drain time so all renderers inherit a safe invariant.
Untrusted token offsets are never bounded to $len(hk->text); toks bytes are aliased unaligned.
dog/HUNK.c:1003-1091 HUNKu8sFeedLineBased — e = base + tok32Offset(...) then for (; p<e; p++) walks past hk->text.dog/HUNK.c:700-742 HUNKu8sFeedHtml and :500-533 HUNKu8sFeedColor — a$part(u8c,span,hk->text,lo,hi-lo) with hi from tok offset; a$part is unchecked (abc/S.h:73).dog/HUNK.c:374-401 hunk_feed_visible and :353-369 hunk_line_sides — build/return spans from the same unvalidated offsets.dog/HUNK.c:210-213 HUNKu8sDrain — hk->toks[0]=(tok32c*)val[0] aliases raw wire/mmap bytes: unaligned u32 loads (UB/SIGBUS) and silent drop of a non-4-multiple tail.HUNKu8sRelay (beagle/SUBS.c) and network frames (woof/CONN.c).None.
Centralize a drain-time validation+alignment, then drop the per-renderer trust.
tok32Offset exceeds the TXT byte length (and a 'K' record at a non-4 boundary / non-4-multiple length); feed via the relay/CONN path; confirm OOB read + misaligned load under ASan.HUNKu8sDrain, require the 'K' length to be a multiple of sizeof(tok32), copy into aligned arena scratch (a_lign(tok32,…)), and reject any tok32Offset > $len(hk->text) (a hunk_toks_valid(hk) gate).hi/lo/span_hi to tlen in each renderer as belt-and-suspenders.