|
| 1 | +# Stake Holder Threat Model |
| 2 | + |
| 3 | +## Introduction |
| 4 | + |
| 5 | +This threat model document for the [Stake Holder](../../contracts/staking/README.md) contract has been created in preparation for external audit. |
| 6 | + |
| 7 | +## Rationale |
| 8 | + |
| 9 | +Immutable operates a system whereby people can place native IMX in a holding contract, do some actions (which are outside of the scope of this threat model), and then are paid a reward. The people, known as stakers, have full custody of their tokens they place in the holding contract; they can withdraw deposited IMX at any time. Anyone can choose to distribute rewards to stakers at any time. |
| 10 | + |
| 11 | +## Threat Model Scope |
| 12 | + |
| 13 | +The threat model is limited to the following Solidity file at GitHash [`fd982abc49884af41e05f18349b13edc9eefbc1e`](https://github.com/immutable/contracts/blob/fd982abc49884af41e05f18349b13edc9eefbc1e/contracts/staking/README.md): |
| 14 | + |
| 15 | +* [StakeHolder.sol](https://github.com/immutable/contracts/blob/fd982abc49884af41e05f18349b13edc9eefbc1e/contracts/staking/StakeHolder.sol) |
| 16 | + |
| 17 | +## Background |
| 18 | + |
| 19 | +See the [README](https://github.com/immutable/contracts/blob/fd982abc49884af41e05f18349b13edc9eefbc1e/contracts/staking/README.md) file for information about the usage and design of the `StakeHolder` contract. |
| 20 | + |
| 21 | +### Other Information |
| 22 | + |
| 23 | +This section provides links to test plans and test code. |
| 24 | + |
| 25 | +#### Test Plans and Test Code |
| 26 | + |
| 27 | +The test plan is available here: [Test Plan](../test/staking/README.md). The test code is contained in the same directory at the test plan. |
| 28 | + |
| 29 | +#### Continuous Integration |
| 30 | + |
| 31 | +Each time a commit is pushed to a pull request, the [continuous integration loop executes](https://github.com/immutable/contracts/actions). |
| 32 | + |
| 33 | +#### Building, Testing, Coverage and Static Code Analysis |
| 34 | + |
| 35 | +For instructions on building the code, running tests, coverage, and Slither, see the [BUILD.md](https://github.com/immutable/contracts/blob/main/BUILD.md). |
| 36 | + |
| 37 | +## Attack Surfaces |
| 38 | + |
| 39 | +The following sections list attack surfaces evaluated as part of this threat modelling exercise. |
| 40 | + |
| 41 | +### Externally Visible Functions |
| 42 | + |
| 43 | +An attacker could formulate an attack in which they send one or more transactions that execute one or more of the externally visible functions. |
| 44 | + |
| 45 | +The list of functions and their function selectors was determined by the following command. The additional information was obtained by reviewing the code. |
| 46 | + |
| 47 | +``` |
| 48 | +forge inspect StakeHolder --pretty methods |
| 49 | +``` |
| 50 | + |
| 51 | +Functions that *change* state: |
| 52 | + |
| 53 | +| Name | Function Selector | Access Control | |
| 54 | +| --------------------------------------- | ----------------- | ------------------- | |
| 55 | +| `distributeRewards((address,uint256)[])`| 00cfb539 | Permissionless | |
| 56 | +| `grantRole(bytes32,address)` | 2f2ff15d | Role admin | |
| 57 | +| `initialize(address,address)` | 485cc955 | Can only be called once during deployment | |
| 58 | +| `renounceRole(bytes32,address)` | 36568abe | `msg.sender` | |
| 59 | +| `revokeRole(bytes32,address)` | d547741f | Role admin | |
| 60 | +| `stake()` | 3a4b66f1 | Operations based on msg.sender | |
| 61 | +| `unstake(uint256)` | 2e17de78 | Operations based on msg.sender | |
| 62 | +| `upgradeStorage(bytes)` | ffd0016f | Can only be called once during upgrade | |
| 63 | +| `upgradeTo(address)` | 3659cfe6 | Upgrade role only | |
| 64 | +| `upgradeToAndCall(address,bytes)` | 4f1ef286 | Upgrade role only | |
| 65 | + |
| 66 | + |
| 67 | +Functions that *do not change* state: |
| 68 | + |
| 69 | +| Name | Function Selector | |
| 70 | +| -------------------------------- | ----------------- | |
| 71 | +| `DEFAULT_ADMIN_ROLE()` | a217fddf | |
| 72 | +| `UPGRADE_ROLE()` | b908afa8 | |
| 73 | +| `getBalance(address)` | f8b2cb4f | |
| 74 | +| `getNumStakers()` | bc788d46 | |
| 75 | +| `getRoleAdmin(bytes32)` | 248a9ca3 | |
| 76 | +| `getRoleMember(bytes32,uint256)` | 9010d07c | |
| 77 | +| `getRoleMemberCount(bytes32)` | ca15c873 | |
| 78 | +| `getStakers(uint256,uint256)` | ad71bd36 | |
| 79 | +| `hasRole(bytes32,address)` | 91d14854 | |
| 80 | +| `hasStaked(address)` | c93c8f34 | |
| 81 | +| `proxiableUUID()` | 52d1902d | |
| 82 | +| `supportsInterface(bytes4)` | 01ffc9a7 | |
| 83 | +| `version()` | 54fd4d50 | |
| 84 | + |
| 85 | + |
| 86 | +### Admin Roles |
| 87 | + |
| 88 | +Accounts with administrative privileges could be used by attackers to facilitate attacks. This section analyses what each role can do. |
| 89 | + |
| 90 | +#### Accounts with `DEFAULT_ADMIN` role on StakeHolder contract |
| 91 | + |
| 92 | +This role is granted to the `roleAdmin` specified in the `initialize` function of the contract. Accounts with the `DEFAULT_ADMIN` account can: |
| 93 | + |
| 94 | +* Grant administrator roles to any account, including the `DEFAULT_ADMIN` role |
| 95 | +* Revoke administrator roles from any account, including the `DEFAULT_ADMIN` role |
| 96 | + * The `DEFAULT_ADMIN` role cannot be revoked from an account if it the only account with the `DEFAULT_ADMIN` role |
| 97 | +* Renounce the `DEFAULT_ADMIN` role for itself, unless it is the only account with the `DEFAULT_ADMIN` role |
| 98 | + |
| 99 | +Exploiting this attack surface requires compromising an account with `DEFAULT_ADMIN` role. |
| 100 | + |
| 101 | +#### Accounts with `UPGRADE` role on StakeHolder contract |
| 102 | + |
| 103 | +An account with `UPGRADE` role can: |
| 104 | + |
| 105 | +* Upgrade the implementation contract. |
| 106 | + |
| 107 | +Exploiting this attack surface requires compromising an account with `UPGRADE` role. |
| 108 | + |
| 109 | + |
| 110 | +### Upgrade and Storage Slots |
| 111 | + |
| 112 | +The table was constructed by using the command described below, and analysing the source code. |
| 113 | + |
| 114 | +``` |
| 115 | +forge inspect StakeHolder --pretty storage |
| 116 | +``` |
| 117 | + |
| 118 | +| Name | Type | Slot | Offset | Bytes | Source File | |
| 119 | +| --------------------------------- | -------------------------------------------------------------- | ---- | ------ | ----- | ----------- | |
| 120 | +| \_initialized | uint8 | 0 | 0 | 1 | OpenZeppelin Contracts v4.9.3: proxy/utils/Initializable.sol | |
| 121 | +| \_initializing | bool | 0 | 1 | 1 | OpenZeppelin Contracts v4.9.3: proxy/utils/Initializable.sol | |
| 122 | +| \_\_gap | uint256[50] | 1 | 0 | 1600 | OpenZeppelin Contracts v4.9.3: utils/Context.sol | |
| 123 | +| \_\_gap | uint256[50] | 51 | 0 | 1600 | OpenZeppelin Contracts v4.9.3: utils/introspection/ERC165.sol | |
| 124 | +| \_roles | mapping(bytes32 => struct AccessControlUpgradeable.RoleData) | 101 | 0 | 32 | OpenZeppelin Contracts v4.9.3: access/AccessControlUpgradeable.sol | |
| 125 | +| \_\_gap | uint256[49] | 102 | 0 | 1568 | OpenZeppelin Contracts v4.9.3: access/AccessControlUpgradeable.sol | |
| 126 | +| \_roleMembers | mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet) | 151 | 0 | 32 | OpenZeppelin Contracts v4.9.3: access/AccessControlEnumerableUpgradeable.sol | |
| 127 | +| \_\_gap | uint256[49] | 152 | 0 | 1568 | OpenZeppelin Contracts v4.9.3: access/AccessControlEnumerableUpgradeable.sol | |
| 128 | +| \_\_gap | uint256[50] | 201 | 0 | 1600 | OpenZeppelin Contracts v4.9.3: proxy/ERC1967/ERC1967Upgrade.sol | |
| 129 | +| \_\_gap | uint256[50] | 251 | 0 | 1600 | OpenZeppelin Contracts v4.9.3: proxy/utils/UUPSUpgradeable.sol | |
| 130 | +| balances | mapping(address => struct StakeHolder.StakeInfo) | 301 | 0 | 32 | StakeHolder.sol | |
| 131 | +| stakers | address[] | 302 | 0 | 32 | StakeHolder.sol | |
| 132 | +| version | uint256 | 303 | 0 | 32 | StakeHolder.sol | |
| 133 | +| \_\_StakeHolderGap | uint256[50] | 304 | 0 | 640 | StakeHolder.sol | |
| 134 | + |
| 135 | + |
| 136 | +## Perceived Attackers |
| 137 | + |
| 138 | +This section lists the attackers that could attack the `StakeHolder` contract. |
| 139 | + |
| 140 | +It is assumed that all attackers have access to all documentation and source code of all systems related to the Immutable zkEVM, irrespective of whether the information resides in a public or private GitHub repository, email, Slack, Confluence, or any other information system. |
| 141 | + |
| 142 | +### Spear Phisher |
| 143 | + |
| 144 | +This attacker compromises accounts of people by using Spear Phishing attacks. For example they send a malicious PDF file to a user, which the user opens, the PDF file then installs malware on the user's computer. At this point, it is assumed that the Spear Phisher Attacker can detect all key strokes, mouse clicks, see all information retrieved, see any file in the user's file system, and execute any program on the user's computer. |
| 145 | + |
| 146 | +### Immutable zkEVM Block Proposer |
| 147 | + |
| 148 | +An operator of an Immutable zkEVM Block Proposer could, within narrow limits, alter the block timestamp of the block they produce. |
| 149 | + |
| 150 | +### Insider |
| 151 | + |
| 152 | +This attacker works for a company helping operate the Immutable zkEVM. This attacker could be being bribed or blackmailed. They can access the keys that they as an individual employee have access to. For instance, they might be one of the signers of the multi-signer administrative role. |
| 153 | + |
| 154 | +### General Public |
| 155 | + |
| 156 | +This attacker targets the public API of the `StakeHolder` contract. |
| 157 | + |
| 158 | +## Attack Mitigation |
| 159 | + |
| 160 | +This section outlines possible attacks against the attack surfaces by the attackers, and how those attacks are mitigated. |
| 161 | + |
| 162 | +### Public API Attack |
| 163 | + |
| 164 | +**Detection**: Staker funds are stolen. |
| 165 | + |
| 166 | +An attacker could target the public API in an attempt to steal funds. As shown in the `Externally Visible Functions` section, all functions that update state are protected by access control methods (`grantRole`, `revokeRole`, `upgradeTo`, `upgradeToAndCall`), operate on value owned by msg.sender (`distributeRewards`, `stake`, `unstake`), operate on state related to msg.sender (`renounceRole`), or are protected by state machine logic (`initialize`, `upgradeStorage`). As such, there is no mechanism by which an attacker could attack the contract using the public API. |
| 167 | + |
| 168 | + |
| 169 | +### `DEFAULT_ADMIN` Role Account Compromise |
| 170 | + |
| 171 | +**Detection**: Monitoring role change events. |
| 172 | + |
| 173 | +The mitigation is to assume that the role will be operated by multi-signature addresses such that an attacker would need to compromise multiple signers simultaneously. As such, even if some keys are compromised due to the Spear Phishing Attacker or the Insider Attacker, the administrative actions will not be able to be executed as a threshold number of keys will not be available. |
| 174 | + |
| 175 | +### `UPGRADE` Role Account Compromise |
| 176 | + |
| 177 | +**Detection**: Monitoring upgrade events. |
| 178 | + |
| 179 | +The mitigation is to assume that the role will be operated by multi-signature addresses such that an attacker would need to compromise multiple signers simultaneously. As such, even if some keys are compromised due to the Spear Phishing Attacker or the Insider Attacker, the administrative actions will not be able to be executed as a threshold number of keys will not be available. |
| 180 | + |
| 181 | +### Immutable zkEVM Block Proposer Censoring Transactions |
| 182 | + |
| 183 | +**Detection**: A staker could attempt to unstake some or all of their IMX. The block proposer could refuse to include this transaction. |
| 184 | + |
| 185 | +The mitigation for this attack is that Immutable zkEVM Block Proposers software is written such that no transactions are censored unless the transaction has been signed by an account on [OFAC's Sanctions List](https://ofac.treasury.gov/sanctions-list-service). |
| 186 | + |
| 187 | + |
| 188 | +## Conclusion |
| 189 | + |
| 190 | +This threat model has presented the architecture of the system, determined attack surfaces, and identified possible attackers and their capabilities. It has walked through each attack surface and based on the attackers, determined how the attacks are mitigated. |
0 commit comments