CertiK reviewed MAP Protocol (Map Protocol - Near) on 28 Nov 2022: 44 findings, 1 critical; 40 marked fixed, 4 open.
Report hosted on skynet.certik.com.
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 1 |
| High | 2 | 0 | 0 |
| Medium | 0 | 0 | 3 |
| Low | 2 | 0 | 36 |
In the contract `MCSToken` located in `mcs/near/mcs-token/src/lib.rs`, the accounts `controller` and `owner` have authority over the following functions: - `mint`: mint new tokens; - `burn`: burn tokens; - `set_metadata`: set fungible token metadata; - `set_owner`: set a new `owner`; - `set_controller`: set a new `controller`; - `upgrade_self`: upgrade contract code. --- In the contract `AdminControlled` located in `mcs/near/admin-controlled/src/macros.rs`, the account of contract itself has authority over the following functions: - set_paused(): Update mask with all paused events. --- In the contract `MapCrossChainService` located in `mcs/near/map-cross-chain-service/src/lib.rs`, the account pointed at the `owner` property has authority over the following functions: - `set_metadata`: Get the record information( validators, threshold and epoch) for the specified epoch. - `add_native_to_chain`: Add target chain for native token. - `remove_native_to_chain`: Remove target chain for native token. - `add_fungible_token_to_chain`: Allow the fungible token to be transferred to the target chain. - `remove_fungible_token_to_chain`: Remove the target chain id from the allow list of the fungible token. - `add_mcs_token_to_chain`: Allow the MCS token to be transferred to the target chain. - `remove_mcs_token_to_chain`: Remove the target chain id from the allow list of the MCS token. - `set_chain_type`: Set the type of a chain to bridge. - `set_owner`: Replace the current `owner`. - `set_map_light_client`: Set the account that works as on-chain light client. - `set_near_chain_id`: Set the chain ID for the Near end of the bridge. - `set_map_chain_id`: Set the chain ID for the Map Relay Chain end of the bridge. - `set_map_relay_address`: Set the address of the Map contracts on the Map Relay Chain. - `upgrade_self`: Upgrade the `MapCrossChainService` contract code. Any compromise to the privileged accounts may allow an hacker to take advantage of it and to, including but not limited to: - arbitrarily add or remove bridged token - mint token - pause pending transfers - replace the on-chain light client with a malicious one Besides, the deployer of the `MapCrossChainService` contract will have full access key over the `MapCrossChainService` contract and the `MCSToken` contracts deployed by calling the `deploy_mcs_token()` function. So the deployer has the ability to delete those two kinds of contracts and transfer the Near out of them to any other accounts.
Smart contracts on the Near blockchain are deployed in accounts backed by regular key pairs. So, the overall security of a smart contract is related to the correct usage and custodial of such a key pair. On the Near side of Map Protocol both `MapLightClient` and `MapCrossChainService` fill a paramount role for the system correct behavior. `MapCrossChainService` locks funds that are transferred from Near to the other mapped blockchain and mints and burn token from external chain that are bridged to Near. `MapLightClient` provides the source of truth for the `MapCrossChainService` to verify facts and event happened on the Map Relay Chain. As a result, any compromise to the `MapCrossChainService` or `MapLightClient` contract's accounts may allow a hacker to take advantage of this authority and arbitrary mint that are supposed to not exist or unlock funds that should remain under the contract custodial.
The cross-chain program `Messenger` listens for events emitted on the source chain and builds a proof for the respective event. Then it transmits the message of the event and receipt proof to the destination chain. However assume the following: 1. Alice on Ethereum transfers token A to herself on Near where there is not enough token A. 2. The `Messenger` submits the receipt proof by calling the `transfer_in()` function defined on Near. 3. Within the `transfer_in()` function, a failure appears. 4. The error message is reported by calling the `report_transfer_in_fail()` function. The `Messenger` would catch that error message. However Alice's tokens are locked on Ethereum.
The implementation of `MCSToken` contract wraps the `FungibleToken` struct from the `near_contract_standards` library. `FungibleToken` implements the `near_contract_standards::StorageManagement` that let any user to fund an `account_id` paying its staking storage deposit. If `account_id` already exists the deposited amount is refunded to the `env::predecessor_account_id()` that invoked `storage_deposit`. When an amount of `MCSToken` needs to be minted because of a transfer incoming into the Near side of the bridge, the `MapCrossChainService` contract issues a `Promise` to call the `MCSToken::mint` function, attaching a deposit for the staking storage, whose amount is configured in `MapCrossChainService::mcs_storage_transfer_in_required`. Problem resides in the fact that if the account that should benefit the minted amount already exists on the `MCSToken` instance, the refund is payed to the `env::predecessor_account_id()`, so to the `MapCrossChainService` contract. However, no functionality is provided to let the `transfer_in` caller redeem the unused deposit. Since *Messengers* are in charge of notifying cross-chain assets movements, this issue can unwillingly drain their resources moving NEAR token from them to the `MapCrossChainService` contract. In a practical example:\ let's assume that Alice wants to transfer to Bob an amount of "TokenA" from the Map Relay Chain to the Near blockchain and that "TokenA" is mapped on Near as an `MCSToken`. Bob already owns some "TokenA" so he is already registered in the `MCSToken` contract.\ Alice locks `MCS` tokens on the Map Relay Chain. One of the available *Messengers* will relay the event to the `MapCrossChainService` contract on the Near side, calling the `transfer_in` function. Within the `process_transfer_in()` function, an amount of `MCS` tokens will be minted to Bob by calling the `mint()` function of `MCSToken` contract along with the attached deposit `self.mcs_storage_transfer_in_required` which is paid by the *Messenger*. Such a deposit will be refunded to the `MapCrossChainService` contract because Bob is already registered. However, the refunded deposit for `Messenger` does not include the refunded storage deposit from the `MCSToken` contract. In fact, `self.mcs_storage_transfer_in_required` is already subtracted from `ret_deposit` before the `finish_transfer_in()` function is called. Eventually, *Messengers* will see their funds moved to the `MapCrossChainService` contract without a real justification.
The report names a repository or files. Open the report to see its scope.
1,044 projects reviewed · 1,375 reports · latest May 2025
See CertiK’s auditsSomething wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.
Tell us