Problem
encodeVarint() in worker/cursor.ts uses value >>> 0 to clamp the input to a 32-bit unsigned integer:
function encodeVarint(value: number): Uint8Array {
let current = value >>> 0;
// ...
}
If a protobuf tag (fieldNumber << 3) | wireType ever reaches or exceeds 2³², the value silently truncates, corrupting the encoded message.
Currently all field numbers are < 256, so this is not exploitable today. But it is a correctness bug in the encoding layer — the function signature implies it handles arbitrary non-negative integers.
Location
worker/cursor.ts — encodeVarint() (near end of file)
Proposed Fix
Add a range check that throws if the value exceeds the safe encoding limit for JavaScript numbers, or switch to bigint-based encoding for full correctness. A pragmatic fix:
function encodeVarint(value: number): Uint8Array {
if (value < 0 || !Number.isInteger(value)) {
throw new Error(`encodeVarint: expected non-negative integer, got ${value}`);
}
if (value >= 2 ** 32) {
throw new Error(`encodeVarint: value ${value} exceeds 32-bit limit`);
}
// ... rest unchanged
}
This is explicit about the limit rather than silently corrupting data. A future refactor could use bigint for arbitrary-length varints if needed.
Impact
- No API change
- No behavioral change for current field numbers (all < 256)
- Converts silent data corruption into a fail-loud error
Problem
encodeVarint()inworker/cursor.tsusesvalue >>> 0to clamp the input to a 32-bit unsigned integer:If a protobuf tag
(fieldNumber << 3) | wireTypeever reaches or exceeds 2³², the value silently truncates, corrupting the encoded message.Currently all field numbers are < 256, so this is not exploitable today. But it is a correctness bug in the encoding layer — the function signature implies it handles arbitrary non-negative integers.
Location
worker/cursor.ts—encodeVarint()(near end of file)Proposed Fix
Add a range check that throws if the value exceeds the safe encoding limit for JavaScript numbers, or switch to
bigint-based encoding for full correctness. A pragmatic fix:This is explicit about the limit rather than silently corrupting data. A future refactor could use
bigintfor arbitrary-length varints if needed.Impact