From 3b2af2b232fa3e10402dee8f107604b410c4cc71 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 12 Oct 2026 01:50:05 +0200 Subject: [PATCH] cultcache-ts: previewPayload reads through decodeBoundedPayload (the inspector's one walk site); the map32 and array32 counts are pinned above 65535 The wide-count test announced map32 as 32770 pairs, which fits in 16 bits, so a count read as its low 16 bits survived. map32 now announces 65537 pairs and array32 65540 children; both low halves close the container early. Builds: yes. Co-Authored-By: Claude Sonnet 5.5 --- packages/cultcache-ts/src/cult-cache-inspector.ts | 3 +-- packages/cultcache-ts/test/payload-depth.test.ts | 9 +++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/cultcache-ts/src/cult-cache-inspector.ts b/packages/cultcache-ts/src/cult-cache-inspector.ts index f1f13bbb..56a0f6e3 100644 --- a/packages/cultcache-ts/src/cult-cache-inspector.ts +++ b/packages/cultcache-ts/src/cult-cache-inspector.ts @@ -295,8 +295,7 @@ function decodeBoundedPayload(payload: Uint8Array): unknown { function previewPayload(payload: Uint8Array): Pick { try { - checkPayloadDepth(payload); - return { payloadPreview: toJsonSafe(decode(payload)) }; + return { payloadPreview: toJsonSafe(decodeBoundedPayload(payload)) }; } catch (error) { return { payloadPreview: { diff --git a/packages/cultcache-ts/test/payload-depth.test.ts b/packages/cultcache-ts/test/payload-depth.test.ts index 1a95924b..02e55ab3 100644 --- a/packages/cultcache-ts/test/payload-depth.test.ts +++ b/packages/cultcache-ts/test/payload-depth.test.ts @@ -222,8 +222,13 @@ test("a 32-bit length or count is read whole: the walk skips a 65539-byte scalar assert.doesNotThrow(() => checkPayloadDepth(cat(bytes(0x92), scalar, arrays(L - 1))), `${name} of 65539 bytes then a chain at the limit`); refused(cat(bytes(0x92), scalar, arrays(L)), `${name} of 65539 bytes then a chain past it`); } - const nils = repeat(bytes(0xc0), 65540); - for (const [name, header] of [["array32", cat(bytes(0xdd), be32(65540))], ["map32", cat(bytes(0xdf), be32(32770))]] as const) { + // Both counts exceed 65535 and their low sixteen bits are small (4 children; 1 pair), so a count cut to 16 bits closes the container early. + const wide: [string, Uint8Array, number][] = [ + ["array32", cat(bytes(0xdd), be32(65540)), 65540], + ["map32", cat(bytes(0xdf), be32(65537)), 2 * 65537], + ]; + for (const [name, header, children] of wide) { + const nils = repeat(bytes(0xc0), children); refused(cat(bytes(0x92), header, nils, arrays(L)), `${name} announcing more than 65535: the sibling chain past the limit`); assert.doesNotThrow(() => checkPayloadDepth(cat(bytes(0x92), header, nils, arrays(L - 1))), `${name}: the sibling chain at the limit`); }