From df90c1bf1dfe2bbf6817443cf83d95c05d0bee00 Mon Sep 17 00:00:00 2001 From: rfxlamia <222023708+rfxlamia@users.noreply.github.com> Date: Thu, 23 Jul 2026 11:13:00 +0700 Subject: [PATCH 1/2] fix(protocol): size check before JSON parse in receiveEnvelope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorder receiveEnvelope() to match SPEC §4.3 step 1: reject wire > 64 KiB before parseOuterVersion (JSON.parse). Oversized v:2 wire now returns envelope_too_large instead of unsupported_version, aligning the protocol host receiver with relay (M2.6). Closes #49 --- .../protocol/src/crypto/receive-envelope.ts | 12 +++++----- .../protocol/src/receive-envelope.test.ts | 22 +++++++++++++++++-- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/packages/protocol/src/crypto/receive-envelope.ts b/packages/protocol/src/crypto/receive-envelope.ts index c40dad8..f875db8 100644 --- a/packages/protocol/src/crypto/receive-envelope.ts +++ b/packages/protocol/src/crypto/receive-envelope.ts @@ -75,17 +75,17 @@ export async function receiveEnvelope( selfId: string, deps: ReceiveEnvelopeDeps, ): Promise { - // Step 0: known wire version + // Step 1 (§4.3): pre-decode wire size cap — before any JSON.parse + if (utf8ToBytes(wire).length > MAX_ENVELOPE_WIRE_BYTES) { + return { ok: false, error: "envelope_too_large" }; + } + + // §4.1 wire version gate (between §4.3 steps 1 and 2) const outerVersion = parseOuterVersion(wire); if (outerVersion !== null && outerVersion !== 1) { return { ok: false, error: "unsupported_version" }; } - // Step 1: pre-decode wire size cap - if (utf8ToBytes(wire).length > MAX_ENVELOPE_WIRE_BYTES) { - return { ok: false, error: "envelope_too_large" }; - } - // Step 2: strict-decode outer + parse body JSON let outer: OuterEnvelope; try { diff --git a/packages/protocol/src/receive-envelope.test.ts b/packages/protocol/src/receive-envelope.test.ts index 38bf5f4..0fdfc6f 100644 --- a/packages/protocol/src/receive-envelope.test.ts +++ b/packages/protocol/src/receive-envelope.test.ts @@ -110,8 +110,8 @@ function tamperBody(wire: string, patch: (body: EnvelopeBody) => void): string { return serializeOuterEnvelope(tampered); } -describe("receiveEnvelope steps 0–6 (§4.3)", () => { - it("step 0: unknown wire version → unsupported_version, dispatch not called", async () => { +describe("receiveEnvelope steps 1–6 (§4.3)", () => { + it("§4.1 wire version: unknown version at valid size → unsupported_version, dispatch not called", async () => { const { wire, bob, bobId } = makeValidWire(); const deps = makeDeps(bob); const badWire = tamperOuter(wire, (outer) => { @@ -137,6 +137,24 @@ describe("receiveEnvelope steps 0–6 (§4.3)", () => { expect(deps.seqStore.commitAccepted).not.toHaveBeenCalled(); }); + it("step 1: oversized wire with v:2 → envelope_too_large (not unsupported_version)", async () => { + const { wire, bob, bobId } = makeValidWire(); + const deps = makeDeps(bob); + const badWire = padWireToSize( + tamperOuter(wire, (outer) => { + outer.v = 2; + }), + MAX_ENVELOPE_WIRE_BYTES + 1, + ); + expect(wireUtf8Length(badWire)).toBeGreaterThan(MAX_ENVELOPE_WIRE_BYTES); + + const result = await receiveEnvelope(badWire, bobId, deps); + + expect(result).toEqual({ ok: false, error: "envelope_too_large" }); + expect(deps.dispatch).not.toHaveBeenCalled(); + expect(deps.seqStore.commitAccepted).not.toHaveBeenCalled(); + }); + it("step 1: wire === 65536 bytes passes size check", async () => { const { wire, bob, bobId } = makeValidWire(); const deps = makeDeps(bob); From 6d0390f0c96107a3c0d07256ce843dd7fb4eccc1 Mon Sep 17 00:00:00 2001 From: rfxlamia <222023708+rfxlamia@users.noreply.github.com> Date: Thu, 23 Jul 2026 11:21:00 +0700 Subject: [PATCH 2/2] =?UTF-8?q?test(protocol):=20align=20step=201=E2=80=93?= =?UTF-8?q?6=20wording=20in=20receiveEnvelope=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename leftover "steps 0–6" case label to match §4.3 numbering after issue #49 reorder (no step 0 in impl or suite). --- packages/protocol/src/receive-envelope.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol/src/receive-envelope.test.ts b/packages/protocol/src/receive-envelope.test.ts index 0fdfc6f..d368fc3 100644 --- a/packages/protocol/src/receive-envelope.test.ts +++ b/packages/protocol/src/receive-envelope.test.ts @@ -304,7 +304,7 @@ describe("receiveEnvelope steps 1–6 (§4.3)", () => { expect(deps.seqStore.commitAccepted).not.toHaveBeenCalled(); }); - it("valid wire passing steps 0–6 continues to step 7+ (not rejected early)", async () => { + it("valid wire passing steps 1–6 continues to step 7+ (not rejected early)", async () => { const { wire, bob, bobId } = makeValidWire(); const deps = makeDeps(bob);