Connext Amarok contest - csanuragjain's results

The interoperability protocol of L2 Ethereum.

General Information

Platform: Code4rena

Start Date: 08/06/2022

Pot Size: $115,000 USDC

Total HM: 26

Participants: 72

Period: 11 days

Judge: leastwood

Total Solo HM: 14

Id: 132

League: ETH

Connext

Findings Distribution

Researcher Performance

Rank: 4/72

Findings: 7

Award: $4,690.98

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: 0x52

Also found by: csanuragjain

Labels

bug
duplicate
2 (Med Risk)

Awards

1169.1572 USDC - $1,169.16

External Links

Lines of code

https://github.com/code-423n4/2022-06-connext/blob/main/contracts/contracts/core/connext/facets/BridgeFacet.sol#L279

Vulnerability details

Impact

A approved realyer can steal from sponsor vault by self initiating transaction via xcall with little to no relayer fees. Then Relayer can himself execute the transaction and claim the fees which he gave and also from the sponsor vault. Thus stealing from sponsor vault

Proof of Concept

  1. Relayer makes xcall using destination domain as his own or some other where he is the approved relayer and also have some sponsor vault

  2. Since relayer fees on this transaction is very low so no relayer would be interested in taking this transaction.

  3. The malicious Relayer simply execute his own transaction due to non competetion and also in process obtains the fees from sponsor vault for his own transaction

There should be a min cap for relayer fees

#0 - LayneHaber

2022-06-24T16:33:26Z

Duplicate of #234

Findings Information

🌟 Selected for report: GimelSec

Also found by: Czar102, Lambda, csanuragjain, minhquanym, shenwilly

Labels

bug
duplicate
2 (Med Risk)

Awards

255.6947 USDC - $255.69

External Links

Lines of code

https://github.com/code-423n4/2022-06-connext/blob/main/contracts/contracts/core/connext/libraries/LibDiamond.sol#L83

Vulnerability details

Impact

The rescindDiamondCut function will set acceptanceTimes of _diamondCut to 0 which is incorrect. This will simply bypass the delay at LibDiamond.sol#L101

Proof of Concept

  1. Admin calls proposeDiamondCut to set a new proposal
uint256 acceptance = block.timestamp + _delay; diamondStorage().acceptanceTimes[keccak256(abi.encode(_diamondCut))] = acceptance;
  1. Ideally Admin has to wait till block.timestamp + _delay to execute this Diamond cut

  2. But this can be bypaased

  3. Admin can simply call rescindDiamondCut function which sets

diamondStorage().acceptanceTimes[keccak256(abi.encode(_diamondCut))] = 0;
  1. Now if Admin calls diamondCut then delay gets bypassed since 0<block.timestamp is true
require( diamondStorage().acceptanceTimes[keccak256(abi.encode(_diamondCut))] < block.timestamp, "LibDiamond: delay not elapsed" );

Revise the condition at LibDiamond.sol#L100 to

require( diamondStorage().acceptanceTimes[keccak256(abi.encode(_diamondCut))] != 0 && diamondStorage().acceptanceTimes[keccak256(abi.encode(_diamondCut))] < block.timestamp, "LibDiamond: delay not elapsed" );

#0 - LayneHaber

2022-06-26T01:15:47Z

Duplicate of #215

Findings Information

🌟 Selected for report: Chom

Also found by: csanuragjain

Labels

bug
duplicate
2 (Med Risk)

Awards

1169.1572 USDC - $1,169.16

External Links

Lines of code

https://github.com/code-423n4/2022-06-connext/blob/main/contracts/contracts/core/connext/facets/BridgeFacet.sol#L839

Vulnerability details

Impact

In case the asset id used in the xcall takes transfer fees while transferring then execution will fail causing DOS

Proof of Concept

  1. User A makes an xcall with an asset id taking transfer fees

  2. Relayer executes this transaction

  3. s.sponsorVault.reimburseLiquidityFees at BridgeFacet.sol#L836 will initiate reimburseLiquidityFees function on SponsorVault.sol#L196

  4. IERC20(_token).safeTransfer(msg.sender, sponsoredFee); will transfer the sponsoredFee to BridgeFacet.sol

  5. Since _token has a transfer fees so amount transferred to BridgeFacet.sol will be sponsoredFee-delta

  6. This becomes a problem at BridgeFacet.sol#L839 which will fail since (IERC20(_asset).balanceOf(address(this)) != starting + sponsored) because of the transfer fees

  7. Hence fast execution will not be possible on this transaction

Sponsored vault should return the actual amount which is transferred in the sponsored variable

#0 - LayneHaber

2022-06-26T00:58:56Z

Duplicate of #196

Findings Information

🌟 Selected for report: xiaoming90

Also found by: csanuragjain

Labels

bug
duplicate
2 (Med Risk)
sponsor acknowledged

Awards

1169.1572 USDC - $1,169.16

External Links

Lines of code

https://github.com/code-423n4/2022-06-connext/blob/main/contracts/contracts/core/connext/facets/BridgeFacet.sol#L411

Vulnerability details

Impact

Relayer and Router can combine to steal funds by taking over most incoming transactions

Proof of Concept

  1. Relayer checks the mempool for any user who has called xcall function

  2. Once relayer gets a transaction with heavy amount, relayer can note all args passed in the xcall by the user

  3. Now assuming both Relayer and Router are working together on this fraud, Relayer already has the Router signature

  4. Relayer can simply use execute function to complete this transaction using the args obtained in frontrun which will result in same transaction id.

  5. This bypasses the Sequencer bid and give unfair advantage to this Relayer

  6. Relayer can gain all the fees now once user transaction arrives via nomad and can share his fees profit between himself and router. All other relayers will be disadvantaged

Keep a tab on total number of transactions relayer is able to execute. If only certain relayer are executing most transactions, probably check if above issue is not happening

#0 - jakekidd

2022-06-25T00:47:59Z

This is 100% correct and is also largely why we have relayer whitelist. In the current design, there is a trusted partnership between the network and the relayer that they will only accept requests from the sequencer agent.

This is a Low Risk / QA issue, since there's no losses - it would just grief the router network of some potential returns.

EDIT: Removing disagree with severity tag as level 2 / Med Risk seems appropriate in hindsight.

#1 - 0xleastwood

2022-08-15T08:18:49Z

Duplicate of #147.

Findings Information

🌟 Selected for report: SmartSek

Also found by: csanuragjain, hansfriese

Labels

bug
duplicate
2 (Med Risk)

Awards

701.4943 USDC - $701.49

External Links

Lines of code

https://github.com/code-423n4/2022-06-connext/blob/main/contracts/contracts/core/connext/facets/StableSwapFacet.sol#L279 https://github.com/code-423n4/2022-06-connext/blob/main/contracts/contracts/core/connext/facets/StableSwapFacet.sol#L305

Vulnerability details

Impact

Even when contract is in pause state both swapExactOut and addSwapLiquidity can still be called due to missing modifier check whenNotPaused

Proof of Concept

  1. Observe the swapExactOut function

  2. Observe that the function is missing whenNotPaused modifier

  3. This means that swapping will be possible even when Admin has kept the contract in paused state (due to some emergency). This is incorrect behaviour

Add modifier whenNotPaused for both swapExactOut and addSwapLiquidity function

function swapExactOut( bytes32 canonicalId, uint256 amountOut, address assetIn, address assetOut, uint256 maxAmountIn, uint256 deadline ) external payable nonReentrant deadlineCheck(deadline) whenNotPaused returns (uint256)

#0 - ecmendenhall

2022-06-20T15:54:41Z

Duplicate of #175

#1 - jakekidd

2022-06-26T18:37:54Z

Oracle returns Chainlink latestRoundData without proper validation

Lines of code

https://github.com/code-423n4/2022-06-connext/blob/main/contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol#L122

Vulnerability details

Impact

Oracle returns Chainlink latestRoundData without proper validation.

Issue

In getPriceFromChainlink function at ConnextPriceOracle.sol#L122, there is no check to see if returned price of aggregator.latestRoundData() is not stale. More details at https://docs.chain.link/docs/faq/#how-can-i-check-if-the-answer-to-a-round-is-being-carried-over-from-a-previous-round

Modify the function as below:

(uint80 round, int256 latestPrice, , uint256 latestTimestamp, uint80 answeredInRound) = aggregator.latestRoundData(); require(feedPrice > 0, "Chainlink price <= 0"); require(answeredInRound >= round, "Stale price"); require(latestTimestamp != 0, "Round not complete");

#0 - ecmendenhall

2022-06-20T05:30:07Z

Duplicate of #190

https://github.com/code-423n4/2022-06-connext/blob/main/contracts/contracts/core/connext/libraries/AssetLogic.sol#L226

Function swapFromLocalAssetIfNeededForExactOut: If _amount is 0 then no need to perform any other step in swapFromLocalAssetIfNeededForExactOut function

if (_amount == 0) { return (true, _amount, _asset); }

https://github.com/code-423n4/2022-06-connext/blob/main/contracts/contracts/core/shared/ProposedOwnable.sol#L161

_setOwner: This function can be defined as private instead of internal

#0 - 0xleastwood

2022-08-16T20:04:08Z

The first optimisation doesn't seem to be possible because this code path is not hit unless _amount != 0. See its use in _reconcileProcessPortal for context on why.

The second optimisation is minor.

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter