MetaMask / MetaMask/metamask-extension

[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

Open
#46,334 1 comment 0 reactions 0 assignees View on GitHub
cs-triaged external-contributor regression-prod-13.46.1 Sev2-normal team-confirmations type-bug
Dominant language
TypeScript
Stars
13.2k
Forks
5.6k
Avg merge
2d 5h
Merged PRs (30d)
451

Description

### 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

1. When no container is applied (Added protection off), leave the dapp-supplied gas limit unchanged.
2. 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

1. 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.
2. When the confirmation opens, leave "Added protection" unticked.
3. Open Edit network fee -> Advanced. The gas limit shown is the bare eth_estimateGas result, not the dapp's value.
4. 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

```shell
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_

Contributor guide

Open the contributing guide

Research direction

Start in shared/lib/transaction/enforced-simulations.ts and trace the confirmation path in ui/pages/confirmations/components/rows/enforced-simulations-row/enforced-simulations-row.tsx into app/scripts/lib/transaction/containers/util.ts. Reproduce with an explicit gas value and Added protection off, then verify that an empty container list preserves the dapp's gas limit and that an applied container never lowers it or removes its margin.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
blockchain, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.