The CCIP documentation states that "This function(ccipReceive) should never revert, all errors should be handled internally in this contract." It also states that this is because CCIP doesn't revert.(https://docs.chain.link/ccip/tutorials/programmable-token-transfers-defensive)
However, the protocol performs complex processing in the ccipReceive function, and there are a great many parts that can be revert.
In this report, I will list as examples those areas where I believe a revert is realistically possible.
fees is exceeded if (fees > maxLINKFee) revert FeeExceedsLimit(fees);
https://github.com/Cyfrin/2023-12-stake-link/blob/549b2b8c4a5b841686fceb9c311dca9ac58225df/contracts/core/ccip/SDLPoolCCIPControllerPrimary.sol#L329
This is a normal occurrence depending on the maxLINKFee setting value.
If an error occurs here, ccipReceive will fail because of the process in_ccipSendUpdate, which is called by the _ccipReceive function.
ccipSend failed bytes32 messageId = router.ccipSend(_destinationChainSelector, evm2AnyMessage);
https://github.com/Cyfrin/2023-12-stake-link/blob/549b2b8c4a5b841686fceb9c311dca9ac58225df/contracts/core/ccip/SDLPoolCCIPControllerPrimary.sol#L330
ccipSend fails for a variety of reasons.(https://docs.chain.link/ccip/api-reference/errors)
If an error occurs here, ccipReceive will fail because of the process in _ccipSendUpdate, which is called by the _ccipReceive function.
Because of the possibility of failure due to external factors, ccipSend should be able to supplement errors with try/catch and then resend.
whitelistedDestinations[sourceChainSelector] is deleted if (sender != whitelistedDestinations[sourceChainSelector]) revert SenderNotAuthorized();
https://github.com/Cyfrin/2023-12-stake-link/blob/549b2b8c4a5b841686fceb9c311dca9ac58225df/contracts/core/ccip/SDLPoolCCIPControllerPrimary.sol#L376
With removeWhitelistedChain, the owner can remove the whitelistedDestinations[sourceChainSelector] at any time.
In other words, ccipReceive will fail if it is removed at a time when messages are being exchanged.
This may seem like a rare case, but assuming that the protocol is active and CCIP messages are constantly being exchanged, it is quite possible.
It might be a good idea to introduce a pause function in the protocol that would stop the exchange of CCIP messages.
ISDLPoolSecondary(sdlPool).distributeTokens(rewardTokens);
https://github.com/Cyfrin/2023-12-stake-link/blob/549b2b8c4a5b841686fceb9c311dca9ac58225df/contracts/core/ccip/SDLPoolCCIPControllerSecondary.sol#L156C17-L156C75
Within the _ccipReceive function, distributeTokens is executed.
The processing inside distributeTokens is outside the scope of the audit, but if a token scheduled for distribution is removed from the whitelist, it is reverted.
This in itself does not seem likely, but since distributeTokens handles the distribution of multiple tokens at once, _ccipReceive will revert if an anomaly occurs with any one token.
The situation is serious because an error in one token will also prevent the distribution of rewards for other tokens.
In addition to the above, there are other places where revert is described and other processes where revert may occur. Although not described because no realistic pattern could be found, all possible error cases must be handled appropriately.
If ccipSend worked but ccipReceive failed. Improper state handling will have occurred, and the chain will not be consistent with each other, making the protocol fundamentally unworkable.
Manual
Error handling should be done so that it never reverts.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.