Skip to content

fix(serializer): throw on out-of-bounds reads in SigmaByteReader - #225

Open
Kshot3000 wants to merge 1 commit into
fleet-sdk:masterfrom
Kshot3000:fix/reader-out-of-bounds
Open

Kshot3000 wants to merge 1 commit into
fleet-sdk:masterfrom
Kshot3000:fix/reader-out-of-bounds

Conversation

@Kshot3000

Copy link
Copy Markdown

Problem

SigmaByteReader silently invented data when a parse ran past the end of the input:

  • readByte() returned undefined (typed as number) at EOF, so readBool() quietly became false and the type serializer's byte.toString(16) crashed with an unrelated TypeError.
  • readBytes(n) clamped to whatever remained and advanced the cursor past the end, so fixed-length fields (box/transaction ids, group elements, AVL digests, ErgoTree bodies) parsed as short values instead of failing.
  • readBits(n) read missing bytes as 0, inventing false bits for truncated SColl[Boolean] constants.
  • A VLQ whose last byte had the continuation bit set decoded to a partial value: readUInt/readBigUInt on [0x80] returned 0. The same applied to any length-prefixed field — readI256 with a declared length of 5 and only 2 bytes remaining returned a wrong bigint instead of an error.

The reference implementation this mirrors (scorex-util VLQByteBufferReader) fails closed here: getByte() is ByteBuffer.get (throws on underflow) and getBytes(size) requires size <= remaining.

Fix

readByte, readBytes, and readBits now throw a RangeError naming the position and input length when the read would go out of bounds (including a negative readBytes length, which previously moved the cursor backwards). This makes truncated VLQs and truncated length-prefixed fields fail at the point of the bad read.

Deliberate non-changes:

  • peek()/match() keep their clamping semantics — they don't advance the cursor and the existing tests document peek returning "all bytes if length is greater than available bytes".
  • readVLQ/readBigVLQ still return 0 for a reader that is empty before the read starts (their existing explicit isEmpty check); only a VLQ truncated mid-sequence now throws, via readByte.

Tests

Five new tests in sigmaByteReader.spec.ts, all of which fail on pristine master and pass with this change: byte past EOF, byte-slice past the remainder (with the exact remainder still readable), bits past EOF, continuation-truncated VLQs for both readUInt and readBigUInt, and a truncated length-prefixed readI256.

Full monorepo suite: 1137/1137 tests pass (66 files), so no in-repo parse path was relying on the lenient behavior.


@Kshot9000 · Donations (ERG): 9fcM5RWnAjmP4vx5bnW6yohB6H9bLq8sJbaPLHtwZLtQPB32Pvy

@changeset-bot

changeset-bot Bot commented Oct 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4f8832f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@fleet-sdk/serializer Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant