Reproduced Exploit
MetaMask MultiTokenPeriodEnforcer: getTermsInfo scans every record and the late token cannot be redeemed
getTermsInfo walks a packed bytes array in steps of 116 bytes until it finds the token. There is no index. A one-record call costs 3504 gas. The same token at record 200 of 200 costs 199182 gas. Inside a gas cap of gasFirst + 45000 — the gas a heavy redeemDelegations would have left — the early red…
Chain
Other
Category
dos
Date
Apr 2025
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: 56801-gettermsinfo-reverts-because-of-block-gas-limit-fixed-consen. Standalone Foundry PoC and full write-up: 56801-gettermsinfo-reverts-because-of-block-gas-limit-fixed-consen_exp in the
evm-hack-registrymirror.
Vulnerability classes: vuln/dos/gas-limit · vuln/dos/frozen-funds
Reproduction: cheatcode-free local synthetic.
getTermsInfois the audited loop. Full trace: output.txt. PoC: test/56801-gettermsinfo-reverts-because-of-block-gas-limit-fixed-consen_exp.sol.
AuditVault taxonomy: lang/solidity · sector/staking · sector/wallet · severity/high · ConsenSys MetaMask Delegation Framework, April 2025
Key info#
| Protocol | MetaMask Delegation Framework |
| Finding | ConsenSys Diligence, AuditVault 56801, high |
| Vulnerable code | MultiTokenPeriodEnforcer.getTermsInfo |
| Harm | 1000 DGT stays locked. The same gas cap redeems a one-record list and reverts on record 200 |
| Chain | local synthetic |
TL;DR#
getTermsInfo walks a packed bytes array in steps of 116 bytes until it finds the token. There is no index. A one-record call costs 3504 gas. The same token at record 200 of 200 costs 199182 gas. Inside a gas cap of gasFirst + 45000 — the gas a heavy redeemDelegations would have left — the early redeem pays 100 DGT and the late redeem reverts. 1000 DGT remains on the enforcer.
The fixed function takes _tokenIndex and reads one record. Redeeming record 199 moves the 1000 DGT and uses well under 200000 gas.
The vulnerable code#
for (uint256 offset_ = 0; offset_ < termsLength_;) {
// @> VULN: every record is scanned, so a token at the end blows the remaining gas
address token_ = address(bytes20(_terms[offset_:offset_ + 20]));
if (token_ == _token) {
// decode periodAmount, periodDuration, startDate and return
}
unchecked { offset_ += 116; }
}
Diagrams#
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 56801-gettermsinfo-reverts-because-of-block-gas-limit-fixed-consen_exp (evm-hack-registry mirror).
- AuditVault finding: 56801-gettermsinfo-reverts-because-of-block-gas-limit-fixed-consen.
Alerts & third-party analyses
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.