payable(target).transfer() forwards only 2300 gas stipend
The contract uses payable(target).transfer(amount) to send ETH to recipients. This pattern was historically considered safe because the 2300 gas stipend it forwards is too small to execute most re-entrancy attacks. However, since EIP-1884 (Istanbul hard fork, 2019), the gas cost of SLOAD and several other opcodes was increased significantly. This means that many contract fallback and receive functions now consume more than 2300 gas during normal operation — not because they are malicious, but simply because they read from storage or emit events.
As a result, any time payable(target).transfer() is used and target is a smart contract (such as a multisig wallet, a DAO treasury, a gnosis safe, or any contract with a non-trivial receive function), the transfer will revert unconditionally. This is not a theoretical concern — Gnosis Safe and many other widely-used treasury contracts are affected. If a project treasury or a fee recipient is a multisig, all fund withdrawals will permanently fail, locking ETH in the contract with no recovery path.
The Solidity documentation itself deprecated .transfer() and .send() after EIP-1884, recommending .call{value: amount}("") as the replacement. The low-level call forwards all remaining gas by default and allows the recipient to perform complex operations in their fallback.
Likelihood:
This vulnerability is rated Medium likelihood. The issue only manifests when the recipient address is a smart contract with a non-trivial fallback. For EOA recipients this is a non-issue. However, in practice, project treasuries and fee recipients are very commonly multisigs or DAO contracts. The probability of this causing a production failure is moderate to high depending on the ecosystem the project operates in.
Impact:
This vulnerability is rated High impact. If triggered, ETH sent to a contract recipient will revert, and depending on whether the calling function handles the revert, funds may become permanently locked inside the pass contract. There is no administrative override — once ETH is trapped with no fallback withdrawal mechanism, it is irrecoverable without an upgrade. This represents both a direct financial loss and a critical operational failure.
The ExpensiveReceiver contract writes to storage inside its receive() function. An SSTORE operation costs at minimum 2900 gas post-EIP-1884, which alone exceeds the 2300 gas stipend forwarded by .transfer(). The transaction reverts with an out-of-gas error even though the recipient contract is not doing anything malicious. Any real-world multisig or contract wallet will exhibit the same behavior.
Replace all .transfer() calls with the low-level .call{value: amount}("") pattern, and always check the boolean return value. Since .call forwards all remaining gas and does not revert automatically on failure, the explicit require(success) is mandatory. Importantly, switching to .call re-opens the re-entrancy attack surface that .transfer()'s gas limit accidentally prevented — so all ETH-sending functions must follow the checks-effects-interactions pattern or use OpenZeppelin's ReentrancyGuard.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.