Transaction-level msg.value reused across multiple native wrap permits enables minting unbacked wrapped tokens
The msg.value >= recipient.amount check is evaluated per-permit instead of per-transaction, so the same native value satisfies multiple wrap permits in one call and the bridge mints unbacked wrapped tokens.
Description
When wrapping native token, the check
require(msg.value >= recipient.amount) at line 370 is evaluated per
recipient and per permit. Since msg.value is a transaction-level
constant that never decreases, the same msg.value can pass the check for
multiple wrap operations, minting more wrapped tokens than native tokens
received.
Root Cause
// Bridge.sol _handleWrap line 370require(msg.value >= recipient.amount, "Insufficient native token sent");
This check passes independently for each wrap recipient/permit.
Additionally, totalTransferred is reset to 0 at the start of each
permit (line 303), so cross-permit accounting is absent.
Vulnerable Scenario
- Attacker sends
msg.value = 100with two native permits, each containing one wrap recipient for 100 native tokens. - Permit 1:
require(msg.value(100) >= 100)passes. Bridge mints ~100 wrapped tokens.totalTransferred = 100 == permit.amount. Check passes. - Permit 2:
require(msg.value(100) >= 100)passes again. Bridge mints another ~100 wrapped tokens.totalTransferred = 100 == permit.amount. Check passes. - Result: Bridge received 100 native tokens, minted ~200 wrapped tokens. Solvency broken by 100 native tokens.
Impact
- Native token solvency invariant violation:
address(bridge).balance >= wrappedNativeToken.totalSupply()no longer holds. - Attacker can unwrap their excess wrapped tokens to steal other users' escrowed native tokens.
- Repeatable for arbitrary (N permits × msg.value).
Recommendation
Track cumulative native tokens usage across ALL permits in a single
transaction. Replace per-recipient msg.value check with a running
counter:
uint256 nativeTokenUsed = 0;nativeTokenUsed += recipient.amount;// In _handleWrap for native tokens:require(msg.value >= nativeTokenUsed, "Insufficient native tokens");
Resolution
YadaCoin, Confirmed.
Zealynx, Fixed.

