Summary
hardhat_*/anvil_* state mutation handlers accept JSON integer params through parseU256, but negative integers are bitcast into u256 instead of being rejected. This can turn malformed negative inputs into very large balances/storage/base-fee values.
Why this matters
This is a correctness and safety bug at an RPC boundary: malformed quantity inputs are accepted and interpreted as huge state mutations instead of failing with -32602.
Normative contract
docs/specs/json-rpc-contract.md:102 malformed quantities must map to -32602.
docs/specs/json-rpc-contract.md:763-767 these mutation methods are part of the contract surface (zevm_setBalance/zevm_setStorageAt with hardhat/anvil aliases).
Evidence
Handlers rely on parseU256:
src/rpc/dev_handlers.zig:31-40 (handleHardhatSetBalance)
src/rpc/dev_handlers.zig:69-79 (handleHardhatSetStorageAt)
src/rpc/dev_handlers.zig:93-101 (handleHardhatSetNextBlockBaseFeePerGas)
parseU256 integer branch performs signed-to-unsigned bitcast:
src/rpc/dev_handlers.zig:135-139
fn parseU256(value: std.json.Value) ?u256 {
const s = switch (value) {
.string => |str| str,
.integer => |i| return @intCast(@as(u256, @bitCast(@as(i256, i)))),
else => return null,
};
So an input like -1 becomes 0xffff...ffff (u256::MAX) instead of invalid params.
Suggested scope
- Reject negative numeric inputs in
parseU256 (and normalize numeric parsing semantics to QuantityHex expectations).
- Add regression tests that negative numeric params for balance/storage/base-fee mutation methods return
-32602.
- Audit all dev-control numeric parsers for the same signed/unsigned conversion pattern.
Summary
hardhat_*/anvil_*state mutation handlers accept JSON integer params throughparseU256, but negative integers are bitcast intou256instead of being rejected. This can turn malformed negative inputs into very large balances/storage/base-fee values.Why this matters
This is a correctness and safety bug at an RPC boundary: malformed quantity inputs are accepted and interpreted as huge state mutations instead of failing with
-32602.Normative contract
docs/specs/json-rpc-contract.md:102malformed quantities must map to-32602.docs/specs/json-rpc-contract.md:763-767these mutation methods are part of the contract surface (zevm_setBalance/zevm_setStorageAtwith hardhat/anvil aliases).Evidence
Handlers rely on
parseU256:src/rpc/dev_handlers.zig:31-40(handleHardhatSetBalance)src/rpc/dev_handlers.zig:69-79(handleHardhatSetStorageAt)src/rpc/dev_handlers.zig:93-101(handleHardhatSetNextBlockBaseFeePerGas)parseU256integer branch performs signed-to-unsigned bitcast:src/rpc/dev_handlers.zig:135-139So an input like
-1becomes0xffff...ffff(u256::MAX) instead of invalid params.Suggested scope
parseU256(and normalize numeric parsing semantics to QuantityHex expectations).-32602.