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: 88/113
Findings: 1
Award: $0.12
🌟 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/DecentEthRouter.sol#L302-L310 https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L20-L22
By exploiting this vulnerability, an attacker is able to steal all the native ETH
locked in the bridge. The assets belong to legitimate users, meaning a loss of user funds, insolvency for the protocol and profit for the attacker.
The issue leading to the vulnerability can be exploited in a different way with a different impact but the following scenario is the most impactful
The DecentEthRouter.sol
contract stores users native ETH
belonging to users using the addLiquidityEth()
function.
The function redeemEth()
can be used to withdraw WETH
but only if the msg.sender
owns the dcntEth
token and has approve()
the router to use it.
function redeemEth( uint256 amount ) public onlyIfWeHaveEnoughReserves(amount) { dcntEth.transferFrom(msg.sender, address(this), amount); weth.withdraw(amount); payable(msg.sender).transfer(amount); }
The mint()
function of DcntEth.sol
contract is protected by the onlyRouter
modifier, giving the ability to mint tokens to DecentEthRouter
only.
https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L8-L11 https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L24-L26
modifier onlyRouter() { require(msg.sender == router); _; } // ... function mint(address _to, uint256 _amount) public onlyRouter { _mint(_to, _amount); }
In order to set the router address, the function setRouter()
is used but as you can see, it has no access control meaning anyone can call it and become the router
function setRouter(address _router) public { router = _router; }
An attacker can set himself as the router using the setRouter()
function, mint()
a huge amount of tokens for himself, approve()
the legitimate DecentEthRouter
to spend it and call redeemEth()
to steal all the ETH
(converted from WETH
) from the router before calling setRouter()
again to set the protocol to its initial state.
The scenario exposed makes use of the redeemEth()
function but the issue impacts all the functions used to retrieve funds
Manual review
Add access control to the setRouter()
function
ETH-Transfer
#0 - c4-pre-sort
2024-01-24T08:23:28Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-01-24T08:23:38Z
raymondfam marked the issue as duplicate of #14
#2 - c4-judge
2024-02-03T13:23:29Z
alex-ppg marked the issue as satisfactory