Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Users may lose their token when send tokens cross chain #162

Closed
code423n4 opened this issue Sep 6, 2023 · 13 comments
Closed

Users may lose their token when send tokens cross chain #162

code423n4 opened this issue Sep 6, 2023 · 13 comments
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working disagree with severity Sponsor confirms validity, but disagrees with warden’s risk assessment (sponsor explain in comments) downgraded by judge Judge downgraded the risk level of this issue duplicate-391 satisfactory satisfies C4 submission criteria; eligible for awards sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") sufficient quality report This report is of sufficient quality

Comments

@code423n4
Copy link
Contributor

Lines of code

https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/DestinationBridge.sol#L78-L114

Vulnerability details

Impact

If a user send token from Chain A to Chain C, and during the waiting for approval the user send the same amount of token from Chain B to Chain C, if Chain A and Chain B have the same nonce, users can lost their token from Chain A to Chain C forever.

Proof of Concept

_execute() function in DestinationBridge.sol record a transaction from a source chain by txnHash, and txnHash is keccak256(payload). payload is just a combination of VERSION, sender, amount and nonce. So if a user send transactions from two source chains which have the same nonce, the txnHash will be exactly same. Since when a transaction is received it need to wait for approval to complete, if at this time a transaction with same txnHash is sent to the same destination chain, it can overwrite the pending transaction, and user will lose that token forever.

A POC is here to illustrate this, simply add it to forge-tests/bridges/DestinationBridge.t.sol and run

function test_User_can_lost_money() public {
// We already add chain support for arbitrum in setUp(), now we add support for optimism
vm.prank(guardian);
destinationBridge.addChainSupport(
  "optimism",
  "0xce16F69375520ab01377ce7B88f5BA8C48F8D612"
);

// To better illustrate a new bridged transaction can overwrite the existing bridged transaction, we set the need of
// approval larger than 2
amounts.push(500e18);
numOfApprovers.push(5);

vm.startPrank(guardian);
destinationBridge.setThresholds(arb, amounts, numOfApprovers);
destinationBridge.setThresholds("optimism", amounts, numOfApprovers);
vm.stopPrank();

// First transaction is a bridged transaction from Arbitrum, Alice want to send 100e18 token
bytes memory payload = abi.encode(bytes32("1.0"), alice, 100e18, 1);
bytes32 cmdId = bytes32(
  0x9991faa1f435675159ffae64b66d7ecfdb55c29755869a18db8497b4392347e0
);
string memory srcChain = "arbitrum";
string memory srcAddress = "0xce16F69375520ab01377ce7B88f5BA8C48F8D666";

approve_message(
  cmdId,
  srcChain,
  srcAddress,
  address(destinationBridge),
  keccak256(payload)
);

destinationBridge.execute(cmdId, srcChain, srcAddress, payload);

// ondoSigner0 also approves this arbitrum transaction, so the total approval should be 2 now
vm.prank(ondoSigner0);
destinationBridge.approve(keccak256(payload));
assertEq(destinationBridge.getNumApproved(keccak256(payload)), 2);

// Now while Alice's arbitrum transaction is waiting for approval, there is a exactly same transaction from optimism
cmdId = bytes32(
  0x9991faa1f435675159ffae64b66d7ecfdb55c29755869a18db8497b4392347e0
);
srcChain = "optimism";
srcAddress = "0xce16F69375520ab01377ce7B88f5BA8C48F8D612";

approve_message(
  cmdId,
  srcChain,
  srcAddress,
  address(destinationBridge),
  keccak256(payload)
);

destinationBridge.execute(cmdId, srcChain, srcAddress, payload);

// Now the new optimism overwrites the pending arbitrum transaction! We can see the transaction is overwritten
// and the approval for the same txnHash changes from 2 to 1
assertEq(destinationBridge.getNumApproved(keccak256(payload)), 1);
}

Tools Used

Manual Review, Foundry

Recommended Mitigation Steps

Add srcChain when creating a payload, this can prevent two source chains have exactly same payload.

Assessed type

Other

@code423n4 code423n4 added 3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working labels Sep 6, 2023
code423n4 added a commit that referenced this issue Sep 6, 2023
@c4-pre-sort
Copy link

raymondfam marked the issue as primary issue

@c4-pre-sort c4-pre-sort added the primary issue Highest quality submission among a set of duplicates label Sep 7, 2023
@c4-pre-sort
Copy link

raymondfam marked the issue as sufficient quality report

@c4-sponsor
Copy link

tom2o17 marked the issue as disagree with severity

@c4-sponsor c4-sponsor added the disagree with severity Sponsor confirms validity, but disagrees with warden’s risk assessment (sponsor explain in comments) label Sep 11, 2023
@tom2o17
Copy link

tom2o17 commented Sep 11, 2023

So agree with this issue,
I am curious given the hoops that a user must jump through to invoke this error if this can be downgraded.

Basically I feel that given a user must wait for the nonce to be the same between src chains and must pass the message using the same wallet and amount.

tldr: ilf the user really needs to put in work to invoke this error.

@c4-sponsor
Copy link

ypatil12 (sponsor) confirmed

@c4-sponsor c4-sponsor added the sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") label Sep 12, 2023
@kirk-baird
Copy link

I'm inclined to accept this as high severity.

There are requirements for this attack / bug to have the same:

  • address
  • amount
  • nonce

If these conditions are met there will be significant loss of funds.

@c4-judge
Copy link
Contributor

kirk-baird marked the issue as satisfactory

@c4-judge c4-judge added the satisfactory satisfies C4 submission criteria; eligible for awards label Sep 17, 2023
@c4-judge
Copy link
Contributor

kirk-baird marked issue #391 as primary and marked this issue as a duplicate of 391

@c4-judge c4-judge added duplicate-391 and removed primary issue Highest quality submission among a set of duplicates labels Sep 17, 2023
@tom2o17
Copy link

tom2o17 commented Sep 19, 2023

@kirk-baird

Agree with the above more so a comment that the conditions to induce the bug are sufficiently difficult to produce, given that the user will have to be listening to cross chain state and be subject to race conditions, all so that the user ....checks notes.... burns their funds.

Generally think that when working with invalid state paths it is worth considering the difficulty of producing said bug in the wild, when weighting the severity, but defer to y'all. 🤠

@stalinMacias
Copy link

@kirk-baird
I think this issue fits more the judging description of a medium severity than a high severity. As explained by @tom2o17 , to me it looks like it matches the exact description of medium severity issue: "the function of the protocol or its availability could be impacted, or leak value with a hypothetical attack path with stated assumptions, but external requirements."
image

@0xnirlin
Copy link

Came to comment the same as stalin, the condition required to make this happen are not too straight forward.

@kirk-baird
Copy link

The debate here for this issue and new primary #391 is whether the likelihood of this issue is high enough to qualify for high severity vs medium severity.

Looking at each aspect

  • amount:
    • an EOA user to send same amounts from multiple chains to a single destination chain
    • a smart contract allowing users to bridge funds (note this would require the equivalent address on the receiving chain, smart contracts are not the intended users for this protocol)
  • address:
    • if account is an EOA then they own keys on both chains
    • smart contract would only occur if it is deployed to the same address on both chains
  • nonce:
    • to be equal on both chains. Anyone can spam calls to burnAndCallAxelar() to increment the lower nonce such that they match. However, this requires front-running and organizing the mem pool so would realistically need to be a block producer to exploit this.
  • timing: attacks can only be performed while txs are pending

I'm going to consider the opinions from the sponsor and other wardens here, that this is not sufficient likelihood to qualify for a high severity and downgrade it to medium.

@c4-judge c4-judge added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value downgraded by judge Judge downgraded the risk level of this issue and removed 3 (High Risk) Assets can be stolen/lost/compromised directly labels Sep 26, 2023
@c4-judge
Copy link
Contributor

kirk-baird changed the severity to 2 (Med Risk)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working disagree with severity Sponsor confirms validity, but disagrees with warden’s risk assessment (sponsor explain in comments) downgraded by judge Judge downgraded the risk level of this issue duplicate-391 satisfactory satisfies C4 submission criteria; eligible for awards sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") sufficient quality report This report is of sufficient quality
Projects
None yet
Development

No branches or pull requests

8 participants