[Bug]: Added protection (enforced simulations) overwrites the dapp's gas limit with a zero-margin estimate on non-Trusted contracts, even when the option is off
Describe the bug
When a dapp sends eth_sendTransaction with an explicit gas limit, MetaMask replaces that limit with a fresh eth_estimateGas result, with no buffer, whenever the contract being called is not rated Trusted by Blockaid's address scan (Benign included). We see this on Ethereum and Base. It happens as soon as the confirmation opens, whether or not the user enables "Added protection". The dapp's fees are kept; only the gas limit is overwritten.
For contracts whose gas use rises between the estimate and inclusion, a zero-margin limit makes transactions run out of gas. Lending markets such as Aave, Compound and Morpho update interest on the first transaction in each block, so a deposit estimated in one block can need 5-12% more gas when it lands a few blocks later. Our dapp sets the gas limit to estimate x 1.3 to prevent exactly this, and MetaMask discards it.
Where it happens in the source (v13.50.0):
- shared/lib/transaction/enforced-simulations.ts: isEnforcedSimulationsEligible() returns true when any recipient's cached address-scan result is anything other than Trusted.
- ui/pages/confirmations/components/rows/enforced-simulations-row/enforced-simulations-row.tsx: when eligible, calls applyTransactionContainersExisting() on load, with an empty container list when Added protection is not enabled by default.
- app/scripts/lib/transaction/containers/util.ts, applyTransactionContainers(): deletes gas and gasLimit from txParams, calls TransactionController:estimateGas, and writes the raw result back to txParams.gas, even when no container is applied.
Expected behavior
- When no container is applied (Added protection off), leave the dapp-supplied gas limit unchanged.
- When a container is applied, never set a gas limit below the one the dapp supplied, and add a margin to the new estimate. Wrapping adds gas, and state can change before inclusion.
Screenshots/Recordings
No response
Steps to reproduce
- On Ethereum or Base, use a dapp that sends eth_sendTransaction with an explicit gas value above the estimate (for example, estimate x 1.3) to a contract that Blockaid's address scan rates Benign rather than Trusted.
- When the confirmation opens, leave "Added protection" unticked.
- Open Edit network fee -> Advanced. The gas limit shown is the bare eth_estimateGas result, not the dapp's value.
- Confirm. The transaction is sent with the bare estimate as its gas limit. Per the code above, a recipient rated Trusted is not eligible, and its dapp-supplied limit is kept.
Error messages or log output
What a zero-margin limit does to these contracts, on Base, 13 September 2026: a USDC deposit into an ERC-4626 vault ran out of gas with its limit equal to the bare estimate (limit 547,111, gas used 541,288), failing inside the nested Morpho call:
https://basescan.org/tx/0x890f555ac73cc9ef1b82cfcf26360e38646173c0a7939cc65d8168ab8430fbee
(This one was sent before our dapp began supplying its own limit, so MetaMask's estimate was used as is.)
On forks of Ethereum and Base, every one of our 18 vault and portfolio deposits sent 30 seconds after its estimate with a zero-margin limit ran out of gas. With estimate x 1.3, all deposits and withdrawals succeeded, even when sent an hour after the estimate.Where was this bug found?
Live version (from official store)
Version
13.46.1
Build type
None
Browser
Chrome
Operating system
MacOS
Hardware wallet
No response
Additional context
We build ACCRUE (https://accrue.cc), a USDC vault platform on Ethereum and Base. Blockaid rates our contracts Benign but not Trusted, so every MetaMask user depositing with us is affected. We are happy to provide traces or test transactions.
Severity
No response
Source: MetaMask/metamask-extension