Reproduced Exploit
Hinkal: Tree capacity guard uses `!=` instead of `<=`, letting an overflow overwrite an earlier commitment
Chain
Other
Category
untagged
Date
Jan 1970
Source
AuditVault
EVM Playground
Source-level debugger — step opcodes and Solidity in sync
The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.
Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 60150-commitments-can-be-overwritten-by-overflowing-the-tree-quant. The historical source/toolchain is unavailable; this entry is documentation only and claims no executable Forge PoC.
Vulnerability classes: vuln/off-by-one · vuln/state-corruption · vuln/merkle-tree
Reproduction: a faithful minimal reproduction of the vulnerable finding — the vulnerable function is reproduced verbatim (marked
@>) with faithful minimal doubles; local deploy, no fork.
Root cause#
The full-tree guard checks require(newIndex != 2**LEVELS) (line 59) instead of <=, so once the tree is full an insert with newIndex > 2**LEVELS passes. The overflowing leaf is then written at an index that aliases an earlier position, and its parent (index/2) wraps back into the leaf region (onto MINIMUM_INDEX) — overwriting a previously-stored commitment and invalidating that depositor's funds.
// VERBATIM buggy capacity guard from the finding: uses `!=` instead of `<`.
function insert(bytes32 leaf) public {
uint256 newIndex = m_index;
require(newIndex != uint256(2) ** LEVELS, "Tree is full."); // @>
_insert(leaf);
Why it's exploitable here#
require(newIndex != 2**LEVELS)passes for anynewIndex > 2**LEVELS, so the tree is not actually capacity-bounded.- The overflowing leaf's parent (
index/2) aliasesMINIMUM_INDEX, so a previously-stored commitment slot is overwritten. - The overwritten commitment is silently invalidated — that depositor's funds become unspendable.
Attack path#
Marked-line walkthrough (Playground)#
The EVM Playground pins each step to the exact executed source line in MerkleBase:
- Line 60 — the
!=guard (line 59) lets_insertrun even though the tree is already full. - Line 43 — VULN. nodes[newIndex] is set for the overflowing index, which aliases (overwrites) an earlier commitment's slot.
- Line 47 — the parent index (index/2) lands on MINIMUM_INDEX, corrupting a previously-stored commitment.
PoC#
Registry (Foundry, local deploy — exploit path + a fixed-variant control):
cd 60150-commitments-can-be-overwritten-by-overflowing-the-tree-qua_exp
forge test -vv
Expected: both tests PASS — the exploit test overflows the tree and asserts the first depositor's commitment slot was overwritten; the fixed <= guard reverts the overflowing insert. The browser EVM Playground is served at /hacks/60150-commitments-can-be-overwritten-by-overflowing-the-tree-qua/.
Remediation#
Use require(newIndex <= 2**LEVELS, "Tree is full") so the tree can never be overflowed.
References#
- AuditVault finding: https://github.com/Auditware/AuditVault/blob/main/findings/60150-commitments-can-be-overwritten-by-overflowing-the-tree-quant.md
Sources & further analysis#
Reproductions & code
- No executable Forge reproduction is claimed; the historical source/toolchain was unavailable for this finding.
- AuditVault finding: 60150-commitments-can-be-overwritten-by-overflowing-the-tree-quant.
- Upstream DeFiHackLabs PoC directory: src/test.
Alerts & third-party analyses
- DeFiHackLabs incident explorer: search "Hinkal: Tree capacity guard uses
!=instead of<=, letting an overflow overwrite an earlier commitment". - Web3Sec X hacked database: search.
- Rekt leaderboard: search.
- Solodit incident search: search.
These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.