Platform: Code4rena
Start Date: 08/09/2023
Pot Size: $70,000 USDC
Total HM: 8
Participants: 84
Period: 6 days
Judge: gzeon
Total Solo HM: 2
Id: 285
League: ETH
Rank: 30/84
Findings: 2
Award: $296.01
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Kow
Also found by: 0xRobsol, 0xfuje, 0xkazim, 0xpiken, Aymen0909, T1MOH, bin2chen, codegpt, gumgumzum, josephdara, lsaudit, nmirchev8, ravikiranweb3, rvierdiiev
132.8565 USDC - $132.86
https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/token/ERC20.sol#L48 https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/token/ERC20.sol#L71
DOMAIN_SEPARATOR
of ERC20
is incorrectly calculated and usedpermit()
of ERC20
doesn't work as intented, implementation of EIP-1271 _isValidSignature()
will use incorrect digest
_DOMAIN_SEPARATOR
of ERC20
is incorrectly calculated. _DOMAIN_SEPARATOR
is used as DOMAIN_SEPARATOR
in permit()
and passed in the _isValidSignature()
function.
Since block.chainId
will always equal deploymentChainId
as we see in the constructor: this means in permit()
always the incorrectly calculated _DOMAIN_SEPARATOR
will be used since the expression block.chainid == deploymentChainId ? _DOMAIN_SEPARATOR
is always true.
src/token/ERC.20.sol
- constructor
constructor(uint8 decimals) { ... deploymentChainId = block.chainId _DOMAIN_SERATOR = _calculateDomainSeparator(block.chainid) }
src/token/ERC20.sol
- _calculateDomainSeparator()
function _calculateDomainSeparator(uint256 chainId) private view returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256(bytes(version)), chainId, address(this) ) ); }
The problem is that the _calculateDomainSeparator()
will use the empty name
when it is not yet set in the constructor, only later via file()
. Even after the name
was set, the incorrectly calculated _DOMAIN_SEPARATOR
(set in constructor) remains to be used.
Manual review
Set name
in the constructor before calculating _DOMAIN_SEPARATOR
via _calculateDomainSeparator()
. Consider setting symbol
in the constructor as well for convenience.
Timing
#0 - c4-pre-sort
2023-09-15T04:51:54Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2023-09-15T04:52:16Z
raymondfam marked the issue as duplicate of #146
#2 - c4-judge
2023-09-26T18:08:26Z
gzeon-c4 marked the issue as satisfactory
🌟 Selected for report: castle_chain
Also found by: 0xAadi, 0xHelium, 0xLook, 0xblackskull, 0xfuje, 0xmystery, 0xnev, 0xpiken, 7ashraf, BARW, Bauchibred, Bughunter101, Ch_301, JP_Courses, Kaysoft, Krace, MohammedRizwan, SanketKogekar, Sathish9098, alexzoid, ast3ros, btk, catellatech, degensec, fatherOfBlocks, grearlake, imtybik, jkoppel, jolah1, klau5, lsaudit, m_Rassska, merlin, mrudenko, nobody2018, rokinot, rvierdiiev, sandy
163.1547 USDC - $163.15
https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/gateway/Gateway.sol#L285-L366
Various impacts depending on the type of the transaction: e.g.: extra tokens can be gained, tranche can be updated to a deprecated price which can be exploited
From Axelar Message Parsing Docs:
Occasionally, transactions can get “stuck” in the pipeline from a source to destination chain (e.g. due to one-off issues that arise with relayers that operate on top of the network).
Transactions have typically gotten “stuck” in the pipeline due to: (A) The transaction failing to relay from the source chain into the Axelar network for processing. (B) The transaction failing to get executed on the destination chain.
For example in the case of B
, the transaction can be manually executed on the destination chain by anyone or anyone can increase the gas payment by sending it to the gas receiver of Axelar to replay these transactions.
The problem is while at the original sent time the cross-chain transaction was relevant, it's possible to do damage with it to the system at a later time. Two malicious examples are: updating tranche token price to an old value and transferring tokens that were already sent back to the user on source chain via an admin.
src/gateway/Gateway.sol
- handle()
function handle(bytes calldata message) external onlyIncomingRouter pauseable { ... } else if (Messages.isUpdateTrancheTokenPrice(message)) { (uint64 poolId, bytes16 trancheId, uint128 currencyId, uint128 price) = Messages.parseUpdateTrancheTokenPrice(message); investmentManager.updateTrancheTokenPrice(poolId, trancheId, currencyId, price); } else if (Messages.isTransfer(message)) { (uint128 currency, address recipient, uint128 amount) = Messages.parseIncomingTransfer(message); poolManager.handleTransfer(currency, recipient, amount); } ... }
LiquidityPool.sol
has a price of 100_000
10_000
10_000
deposit
into LiquidityPool
and get 10x more share
s in the next epoch)transfer()
on PoolManager.sol
currency
gets transferred to escrow
on source chainescrow
from Centrifuge
Admin
who has auth
on Root
rescues from escrow
and sends the tokens back to himManual review, Axelar Docs
Consider monitoring the failed transactions, determining what is an appropriate time when a failed cross-chain transaction can still be replayed and not cause any harm. If they are in the appropriate timeframe: replay the transactions via the planned centrifuge relay gas bot. If they are out of time: call validateContractCall()
on Axelar Gateway with the transaction's params to prevent the transaction from any possible replaying.
Other
#0 - c4-pre-sort
2023-09-15T15:50:06Z
raymondfam marked the issue as low quality report
#1 - c4-pre-sort
2023-09-15T15:50:15Z
raymondfam marked the issue as duplicate of #26
#2 - c4-pre-sort
2023-09-17T09:08:57Z
raymondfam marked the issue as sufficient quality report
#3 - c4-pre-sort
2023-09-17T09:09:03Z
raymondfam marked the issue as not a duplicate
#4 - c4-pre-sort
2023-09-17T09:09:08Z
raymondfam marked the issue as primary issue
#5 - c4-pre-sort
2023-09-17T16:55:27Z
raymondfam marked the issue as duplicate of #348
#6 - c4-judge
2023-09-25T16:16:56Z
gzeon-c4 marked the issue as unsatisfactory: Out of scope
#7 - c4-judge
2023-09-26T16:45:50Z
gzeon-c4 marked the issue as not a duplicate
#8 - c4-judge
2023-09-26T16:45:56Z
gzeon-c4 removed the grade
#9 - gzeon-c4
2023-09-26T16:47:04Z
Crosschain message can be executed out-of-order in certain edge case, seems unlikely to be exploited tho
#10 - c4-sponsor
2023-09-26T17:18:19Z
hieronx (sponsor) acknowledged
#11 - c4-sponsor
2023-09-26T17:18:24Z
hieronx marked the issue as disagree with severity
#12 - c4-judge
2023-09-26T17:29:11Z
gzeon-c4 changed the severity to QA (Quality Assurance)
#13 - c4-judge
2023-09-26T17:29:17Z
gzeon-c4 marked the issue as grade-a