Platform: Code4rena
Start Date: 19/01/2024
Pot Size: $36,500 USDC
Total HM: 9
Participants: 113
Period: 3 days
Judge: 0xsomeone
Id: 322
League: ETH
Rank: 6/113
Findings: 3
Award: $1,234.58
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: NPCsCorp
Also found by: 0x11singh99, 0xAadi, 0xBugSlayer, 0xE1, 0xPluto, 0xSimeon, 0xSmartContract, 0xabhay, 0xdice91, 0xprinc, Aamir, Aymen0909, CDSecurity, DadeKuma, DarkTower, EV_om, Eeyore, GeekyLumberjack, GhK3Ndf, Giorgio, Greed, Inference, JanuaryPersimmon2024, Kaysoft, Krace, Matue, MrPotatoMagic, NentoR, Nikki, PUSH0, Soliditors, Tendency, Tigerfrake, Timeless, Timenov, ZanyBonzy, ZdravkoHr, abiih, adeolu, al88nsk, azanux, bareli, boredpukar, cu5t0mpeo, d4r3d3v1l, darksnow, deth, dutra, ether_sky, haxatron, ke1caM, kodyvim, m4ttm, mgf15, mrudenko, nmirchev8, nobody2018, nuthan2x, peanuts, piyushshukla, ravikiranweb3, rouhsamad, seraviz, simplor, slylandro_star, stealth, th13vn, vnavascues, wangxx2026, zaevlad
0.1172 USDC - $0.12
https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L20 https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L294
function setRouter(address _router) public { router = _router; }
Any attacker can set any address as router, and can mint/burn DcntEth
tokens which can be redeemed for WETH at DecentEthRouter::redeemWeth and DecentEthRouter::redeemEth
DcntEth
contract allows minting and burning of DcntEth
tokens directly pegged to WETH
.DecentEthRouter
mints tokens to router itself, if a user provides WETH as liquidity to DecentEthRouter::addLiquidityEth and DecentEthRouter::addLiquidityEth, some DcntEth
toeksn are minted.DcntEth
tokens can convert into WETH if the liquidity is available.DcntEth
supply to himself by calling DcntEth::mintmanual review
Modify DcntEth::setRouter to only allow owner to set router.
- function setRouter(address _router) public { + function setRouter(address _router) onlyOwner public { router = _router; }
Access Control
#0 - c4-pre-sort
2024-01-25T01:33:38Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-01-25T01:33:46Z
raymondfam marked the issue as duplicate of #14
#2 - c4-judge
2024-02-03T13:11:40Z
alex-ppg marked the issue as satisfactory
🌟 Selected for report: iamandreiski
Also found by: EV_om, NPCsCorp, nuthan2x, windhustler
871.3837 USDC - $871.38
Although 100k GAS_FOR_RELAY
is applied as minimum
This is an issue that affects all the contracts that inherit from NonBlockingLzApp due to incorrect overriding of the lzSend function and lack of input validation and the ability to specify whatever adapterParams you want.
The consequence of this is that anyone can with a low cost and high frequency keep on blocking the pathway between any two chains, making the whole system unusable.
Layer Zero minimum gas showcase While sending messages through LayerZero, the sender can specify how much gas he is willing to give to the Relayer to deliver the payload to the destination chain. This configuration is specified in relayer adapter params. All the invocations of lzSend inside the DentEth contracts pass 100k+ gas on the destination.
As a showcase, The transaction below proves , an application that has the intention of using the NonBlockingApp can end up in a situation where there is a StoredPayload and the pathway is blocked.
Transaction Hashes for the example mentioned above:
LayerZero Scan: https://layerzeroscan.com/106/address/0xe6772d0b85756d1af98ddfc61c5339e10d1b6eff/message/109/address/0x5285413ea82ac98a220dd65405c91d735f4133d8/nonce/1 Tenderly stack trace of the sending transaction hash: https://dashboard.tenderly.co/tx/avalanche-mainnet/0xe54894bd4d19c6b12f30280082fc5eb693d445bed15bb7ae84dfaa049ab5374d/debugger?trace=0.0.1 Tenderly stack trace of the receiving transaction hash: https://dashboard.tenderly.co/tx/polygon/0x87573c24725c938c776c98d4c12eb15f6bacc2f9818e17063f1bfb25a00ecd0c/debugger?trace=0.2.1.3.0.0.0.0
copied from this issue.
Increase GAS_FOR_RELAY
to 200k and refund the unsed gas after the dest chain tx succeeds.
DoS
#0 - c4-pre-sort
2024-01-25T04:54:25Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-01-25T04:54:36Z
raymondfam marked the issue as duplicate of #212
#2 - c4-judge
2024-02-02T12:33:07Z
alex-ppg marked the issue as partial-50
🌟 Selected for report: windhustler
363.0765 USDC - $363.08
For any of the below reasons, if sgReceive reverts, then the funds can be sweeped by anyone. - The slippage of minOut/maxIn values doen't match, so post bridge swap with dexes failed. Or worse, the liquidity was low on the destination chain. - If stargate forwards less gas that it took to execute the tx, or pre bridge gas parameters were not enough to complete all state changes, so Out-Of-Gas error is thrown. - the approval call does not check for bool return, or USDT's approval race implementation, or improper Fee on transfer hadling can revert. - The refund address doesn't implement fallback function in a contract ..
If any of the above cases, primarily slippage/liquidity revert can make the funds locked in the contract.
Then an attacker can call sgReceive with any payload he pleases payload
and can sweep the locked tokens.
Manual review
Implement the try catch method in the sgReceive function
function sgReceive( uint16, // _srcChainid bytes memory, // _srcAddress uint256, // _nonce address, // _token uint256, // amountLD bytes memory payload ) external override onlyExecutor { ( SwapInstructions memory postBridge, address target, address paymentOperator, bytes memory utbPayload, address payable refund ) = abi.decode( payload, (SwapInstructions, address, address, bytes, address) ); SwapParams memory swapParams = abi.decode( postBridge.swapPayload, (SwapParams) ); IERC20(swapParams.tokenIn).approve(utb, swapParams.amountIn); - IUTB(utb).receiveFromBridge( - postBridge, - target, - paymentOperator, - utbPayload, - refund - ); + try IUTB(utb).receiveFromBridge(postBridge, target, paymentOperator, utbPayload, refund) returns () { + + } catch { + IERC20(swapParams.tokenIn).transfer(refund, swapParams.amountIn); + } }
Token-Transfer
#0 - c4-pre-sort
2024-01-25T04:08:34Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-01-25T04:08:41Z
raymondfam marked the issue as duplicate of #68
#2 - c4-judge
2024-02-02T14:38:52Z
alex-ppg marked the issue as not a duplicate
#3 - c4-judge
2024-02-02T14:39:04Z
alex-ppg marked the issue as duplicate of #665
#4 - alex-ppg
2024-02-02T14:40:11Z
A penalty has been applied as a MEV bot cannot craft a payload that is malicious (as inward transfers always match the swapped assets in the Stargate system).
#5 - c4-judge
2024-02-02T14:40:16Z
alex-ppg marked the issue as partial-50
#6 - c4-judge
2024-02-04T23:05:25Z
alex-ppg changed the severity to 2 (Med Risk)