Omniscia AllianceBlock Audit

CCIPProvider Manual Review Findings

CCIPProvider Manual Review Findings

Description:

The referenced EVMExtraArgsV1 definition contradicts the structure's implementation based on the various official releases of CCIP on their repository.

Impact:

The severity of this exhibit will be adjusted based on whether the code is indeed incorrect or not after the AllianceBlock team's analysis.

Example:

contracts/providers/CCIPProvider/CCIPProvider.sol
367extraArgs = Client.EVMExtraArgsV1({ gasLimit: 0, strict: false });

Recommendation:

We advise the code to be updated to reflect the latest release of the CCIP protocol by Chainlink.

Alleviation (54fd570de24631ca65a7cea022aebe43225a08c7):

The code was updated throughout to reflect the latest CCIP release, rendering this exhibit alleviated.

CCI-02M: Inexistent Uniqueness Validation

Description:

The CCIPProvider::constructor and CCIPProvider::config functions do not guarantee that the MPC IDs and chain selectors introduced are unique, permitting duplicate entries to exist within the _supportedChains array as well as multiple mpcIds / ccipChainSelectors entries to point to the same MPC ID / CCIP chain selector respectively.

Impact:

The main corrupted data entry of this bug is the _supportedChains array which is relatively inconsequential, rendering this exhibit to be of minor severity.

Example:

contracts/providers/CCIPProvider/CCIPProvider.sol
249/**
250 * @dev Configures the CCIPProvider contract with the provided configuration data.
251 * @param configData The configuration data to be decoded and used to set the CCIPProvider parameters.
252 * @notice Only callable by the Teleport contract.
253 * @notice The `params.MPCIds` and `params.ccipChainSelectors` arrays must have the same length.
254 * @notice For each `MPCId` in `params.MPCIds`, sets the corresponding `ccipChainSelector` in the `ccipChainSelectors` mapping.
255 * @notice For each `ccipChainSelector` in `params.ccipChainSelectors`, sets the corresponding `MPCId` in the `mpcIds` mapping.
256 * @notice If `params.routerAddress` is not the zero address, sets the `i_router` address to `params.routerAddress`.
257 */
258function config(bytes calldata configData) external override onlyTeleport {
259 ConfigCallParamsV1 memory params = _decodeConfigMessage(configData);
260
261 if (params.MPCIds.length != params.ccipChainSelectors.length) revert ArraysLenMismatch();
262
263 // Set the router address only if a value is provided. Otherwise, keep the current address.
264 if (params.routerAddress != address(0)) {
265 i_router = params.routerAddress;
266 }
267
268 // Set the chain mappings only if some values are provided. Otherwise, keep the current mappings.
269 if (params.MPCIds.length > 0) {
270 // Reset mappings
271 for (uint8 i = 0; i < _supportedChains.length; i++) {
272 delete mpcIds[ccipChainSelectors[_supportedChains[i]]];
273 delete ccipChainSelectors[_supportedChains[i]];
274 }
275
276 // Reset _supportedChains
277 delete _supportedChains;
278 for (uint256 i = 0; i < params.MPCIds.length; ) {
279 ccipChainSelectors[params.MPCIds[i]] = params.ccipChainSelectors[i];
280 mpcIds[params.ccipChainSelectors[i]] = params.MPCIds[i];
281 _supportedChains.push(params.MPCIds[i]);
282 unchecked {
283 i += 1;
284 }
285 }
286 }
287
288 // Set the gas limit only if a value is provided. Otherwise, keep the current value.
289 if (params.gasLimit != 0) {
290 _gasLimit = params.gasLimit;
291 }
292}

Recommendation:

We advise uniqueness to be guaranteed, either by ensuring the input array is in a sorted order or by ensuring that the entries being written to are properly zeroed out.

We consider either of the two approaches sufficient in rectifying this vulnerability.

Alleviation (54fd570de24631ca65a7cea022aebe43225a08c7):

A uniqueness validation check has been introduced in the form of an if-revert pattern validation, alleviating this exhibit in full.

CCI-03M: Incorrect Fee Validation

Description:

The CCIPProvider::send function will ensure that the msg.value is greater-than-or-equal-to the value of fees, however, it will solely forward fees to the router rendering the remainder permanently locked within the contract.

Impact:

Any surplus funds sent to the CCIPProvider will be permanently locked within it with no way of rescuing them.

Example:

contracts/providers/CCIPProvider/CCIPProvider.sol
163/**
164 * @notice Transmits the `payload` to the validators by emitting the `Transmission` event
165 * @param targetChainId The chainID where the message should be delivered to
166 * @param transmissionTeleportReceiver The address of the contract in the target chain to receive the transmission
167 * @param dappTranmissionInfo The Id and data for the dApp that the message belongs to
168 */
169function send(
170 uint8 targetChainId,
171 bytes calldata transmissionTeleportReceiver,
172 DappTransmissionInfo calldata dappTranmissionInfo,
173 bytes calldata extraOptionalArgs_
174) external payable override onlyTeleport {
175 (
176 uint256 fees,
177 Client.EVM2AnyMessage memory evm2AnyMessage,
178 IRouterClient router,
179 uint64 _destinationChainSelector
180 ) = prepareMessage(
181 targetChainId,
182 transmissionTeleportReceiver,
183 dappTranmissionInfo,
184 extraOptionalArgs_
185 );
186
187 if (fees > msg.value) revert InsufficientValueSent(msg.value, fees);
188
189 // Send the CCIP message through the router. We ignore the returned message ID as we don't need it.
190 router.ccipSend{ value: fees }(_destinationChainSelector, evm2AnyMessage);
191}

Recommendation:

We advise the referenced check to be converted to an inequality check with msg.value, ensuring that only a msg.value equal to fees is permitted.

Alleviation (54fd570de24631ca65a7cea022aebe43225a08c7):

The code was updated to ensure that the msg.value precisely matches the fees that will ultimately be forwarded, disallowing funds from being locked and thus alleviating this exhibit.