First, the BranchBridgeAgent._normalizeDecimals(...) and BranchPort._denormalizeDecimals(...) methods, which are both part of the Ulysses Omnichain protocol, act exactly inverse to what they are supposed to do. For example, the _normalizeDecimals method should normalize any amount with given decimals to 18 decimals, e.g. calling with amount = 1e17 and decimals = 17 should return 1e18, but the actual result of the method is 1e16. The _denormalizeDecimals method should denormalize any amount with 18 decimals to given decimals, e.g. calling with amount = 1e18 and decimals = 17 should return 1e17, but the actual result of the method is 1e19.
Now this was only a mild example, considering there are legitimate tokens with only 6 decimals like USDT and USDC, the impacts of this bug can range from simple DoS to stuck funds or even loss of funds for user/protocol.
The following PoC adds 2 new test cases to demonstrate the above issues in a simple omnichain deposit & redeem example using an underlying token with 17 (instead of 18) decimals. Both test cases will fail on token transfer from user due to incorrect/missing token amount normalization & denormalization. Note that the test cases will pass and become more clear once the recommended mitigation steps below are applied.
Just apply the following diff and run all Ulysses Omnichain tests with forge test --match-path test/ulysses-omnichain/**:
The diff below corrects the invalid normalization & denormalization methods as well as additionally normalizes token amounts where it was still missing (at the above mentioned instances).
Lines of code
https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/ulysses-omnichain/BranchBridgeAgent.sol#L1335-L1342 https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/ulysses-omnichain/BranchPort.sol#L383-L390 https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/ulysses-omnichain/BranchBridgeAgent.sol#L269 https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/ulysses-omnichain/BranchBridgeAgent.sol#L313 https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/ulysses-omnichain/BranchBridgeAgent.sol#L696 https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/ulysses-omnichain/BranchBridgeAgent.sol#L745
Vulnerability details
Impact
First, the BranchBridgeAgent._normalizeDecimals(...) and BranchPort._denormalizeDecimals(...) methods, which are both part of the Ulysses Omnichain protocol, act exactly inverse to what they are supposed to do. For example, the
_normalizeDecimals
method should normalize any amount with given decimals to 18 decimals, e.g. calling withamount = 1e17
anddecimals = 17
should return1e18
, but the actual result of the method is1e16
. The_denormalizeDecimals
method should denormalize any amount with 18 decimals to given decimals, e.g. calling withamount = 1e18
anddecimals = 17
should return1e17
, but the actual result of the method is1e19
.Now this was only a mild example, considering there are legitimate tokens with only 6 decimals like USDT and USDC, the impacts of this bug can range from simple DoS to stuck funds or even loss of funds for user/protocol.
Second, the
BranchBridgeAgent
contract's methods callOutSignedAndBridge(...), callOutSignedAndBridgeMultiple(...), _callOutAndBridge(...) and _callOutAndBridgeMultiple fail to normalize the deposit token amounts before forwarding the call via_depositAndCall(...)
/_depositAndCallMultiple(...)
which subsequently calls ArbitrumBranchPort.bridgeOut(...)/ArbitrumBranchPort.bridgeOutMultiple(...). These last-mentioned methods denormalize the deposit token amounts and transfer the assets from the user. Therefore, it is crucial to normalize the token amounts before in order to avoid DoS, stuck funds or even loss of funds for user/protocol depending on given approvals and actual amounts.Proof of Concept
The following PoC adds 2 new test cases to demonstrate the above issues in a simple omnichain deposit & redeem example using an underlying token with 17 (instead of 18) decimals. Both test cases will fail on token transfer from user due to incorrect/missing token amount normalization & denormalization.
Note that the test cases will pass and become more clear once the recommended mitigation steps below are applied.
Just apply the following diff and run all Ulysses Omnichain tests with
forge test --match-path test/ulysses-omnichain/**
:Tools Used
VS Code, Foundry
Recommended Mitigation Steps
The diff below corrects the invalid normalization & denormalization methods as well as additionally normalizes token amounts where it was still missing (at the above mentioned instances).
Assessed type
Decimal