1.. _security_considerations:
2
3#######################
4Security Considerations
5#######################
6
7While it is usually quite easy to build software that works as expected,
8it is much harder to check that nobody can use it in a way that was **not** anticipated.
9
10In Solidity, this is even more important because you can use smart contracts
11to handle tokens or, possibly, even more valuable things. Furthermore, every
12execution of a smart contract happens in public and, in addition to that,
13the source code is often available.
14
15Of course you always have to consider how much is at stake:
16You can compare a smart contract with a web service that is open to the
17public (and thus, also to malicious actors) and perhaps even open source.
18If you only store your grocery list on that web service, you might not have
19to take too much care, but if you manage your bank account using that web service,
20you should be more careful.
21
22This section will list some pitfalls and general security recommendations but
23can, of course, never be complete.  Also, keep in mind that even if your smart
24contract code is bug-free, the compiler or the platform itself might have a
25bug. A list of some publicly known security-relevant bugs of the compiler can
26be found in the :ref:`list of known bugs<known_bugs>`, which is also
27machine-readable. Note that there is a bug bounty program that covers the code
28generator of the Solidity compiler.
29
30As always, with open source documentation, please help us extend this section
31(especially, some examples would not hurt)!
32
33NOTE: In addition to the list below, you can find more security recommendations and best practices
34`in Guy Lando's knowledge list <https://github.com/guylando/KnowledgeLists/blob/master/EthereumSmartContracts.md>`_ and
35`the Consensys GitHub repo <https://consensys.github.io/smart-contract-best-practices/>`_.
36
37********
38Pitfalls
39********
40
41Private Information and Randomness
42==================================
43
44Everything you use in a smart contract is publicly visible, even
45local variables and state variables marked ``private``.
46
47Using random numbers in smart contracts is quite tricky if you do not want
48miners to be able to cheat.
49
50Re-Entrancy
51===========
52
53Any interaction from a contract (A) with another contract (B) and any transfer
54of Ether hands over control to that contract (B). This makes it possible for B
55to call back into A before this interaction is completed. To give an example,
56the following code contains a bug (it is just a snippet and not a
57complete contract):
58
59.. code-block:: solidity
60
61    // SPDX-License-Identifier: GPL-3.0
62    pragma solidity >=0.6.0 <0.9.0;
63
64    // THIS CONTRACT CONTAINS A BUG - DO NOT USE
65    contract Fund {
66        /// @dev Mapping of ether shares of the contract.
67        mapping(address => uint) shares;
68        /// Withdraw your share.
69        function withdraw() public {
70            if (payable(msg.sender).send(shares[msg.sender]))
71                shares[msg.sender] = 0;
72        }
73    }
74
75The problem is not too serious here because of the limited gas as part
76of ``send``, but it still exposes a weakness: Ether transfer can always
77include code execution, so the recipient could be a contract that calls
78back into ``withdraw``. This would let it get multiple refunds and
79basically retrieve all the Ether in the contract. In particular, the
80following contract will allow an attacker to refund multiple times
81as it uses ``call`` which forwards all remaining gas by default:
82
83.. code-block:: solidity
84
85    // SPDX-License-Identifier: GPL-3.0
86    pragma solidity >=0.6.2 <0.9.0;
87
88    // THIS CONTRACT CONTAINS A BUG - DO NOT USE
89    contract Fund {
90        /// @dev Mapping of ether shares of the contract.
91        mapping(address => uint) shares;
92        /// Withdraw your share.
93        function withdraw() public {
94            (bool success,) = msg.sender.call{value: shares[msg.sender]}("");
95            if (success)
96                shares[msg.sender] = 0;
97        }
98    }
99
100To avoid re-entrancy, you can use the Checks-Effects-Interactions pattern as
101outlined further below:
102
103.. code-block:: solidity
104
105    // SPDX-License-Identifier: GPL-3.0
106    pragma solidity >=0.6.0 <0.9.0;
107
108    contract Fund {
109        /// @dev Mapping of ether shares of the contract.
110        mapping(address => uint) shares;
111        /// Withdraw your share.
112        function withdraw() public {
113            uint share = shares[msg.sender];
114            shares[msg.sender] = 0;
115            payable(msg.sender).transfer(share);
116        }
117    }
118
119Note that re-entrancy is not only an effect of Ether transfer but of any
120function call on another contract. Furthermore, you also have to take
121multi-contract situations into account. A called contract could modify the
122state of another contract you depend on.
123
124Gas Limit and Loops
125===================
126
127Loops that do not have a fixed number of iterations, for example, loops that depend on storage values, have to be used carefully:
128Due to the block gas limit, transactions can only consume a certain amount of gas. Either explicitly or just due to
129normal operation, the number of iterations in a loop can grow beyond the block gas limit which can cause the complete
130contract to be stalled at a certain point. This may not apply to ``view`` functions that are only executed
131to read data from the blockchain. Still, such functions may be called by other contracts as part of on-chain operations
132and stall those. Please be explicit about such cases in the documentation of your contracts.
133
134Sending and Receiving Ether
135===========================
136
137- Neither contracts nor "external accounts" are currently able to prevent that someone sends them Ether.
138  Contracts can react on and reject a regular transfer, but there are ways
139  to move Ether without creating a message call. One way is to simply "mine to"
140  the contract address and the second way is using ``selfdestruct(x)``.
141
142- If a contract receives Ether (without a function being called),
143  either the :ref:`receive Ether <receive-ether-function>`
144  or the :ref:`fallback <fallback-function>` function is executed.
145  If it does not have a receive nor a fallback function, the Ether will be
146  rejected (by throwing an exception). During the execution of one of these
147  functions, the contract can only rely on the "gas stipend" it is passed (2300
148  gas) being available to it at that time. This stipend is not enough to modify
149  storage (do not take this for granted though, the stipend might change with
150  future hard forks). To be sure that your contract can receive Ether in that
151  way, check the gas requirements of the receive and fallback functions
152  (for example in the "details" section in Remix).
153
154- There is a way to forward more gas to the receiving contract using
155  ``addr.call{value: x}("")``. This is essentially the same as ``addr.transfer(x)``,
156  only that it forwards all remaining gas and opens up the ability for the
157  recipient to perform more expensive actions (and it returns a failure code
158  instead of automatically propagating the error). This might include calling back
159  into the sending contract or other state changes you might not have thought of.
160  So it allows for great flexibility for honest users but also for malicious actors.
161
162- Use the most precise units to represent the wei amount as possible, as you lose
163  any that is rounded due to a lack of precision.
164
165- If you want to send Ether using ``address.transfer``, there are certain details to be aware of:
166
167  1. If the recipient is a contract, it causes its receive or fallback function
168     to be executed which can, in turn, call back the sending contract.
169  2. Sending Ether can fail due to the call depth going above 1024. Since the
170     caller is in total control of the call depth, they can force the
171     transfer to fail; take this possibility into account or use ``send`` and
172     make sure to always check its return value. Better yet, write your
173     contract using a pattern where the recipient can withdraw Ether instead.
174  3. Sending Ether can also fail because the execution of the recipient
175     contract requires more than the allotted amount of gas (explicitly by
176     using :ref:`require <assert-and-require>`, :ref:`assert <assert-and-require>`,
177     :ref:`revert <assert-and-require>` or because the
178     operation is too expensive) - it "runs out of gas" (OOG).  If you
179     use ``transfer`` or ``send`` with a return value check, this might
180     provide a means for the recipient to block progress in the sending
181     contract. Again, the best practice here is to use a :ref:`"withdraw"
182     pattern instead of a "send" pattern <withdrawal_pattern>`.
183
184Call Stack Depth
185================
186
187External function calls can fail any time because they exceed the maximum
188call stack size limit of 1024. In such situations, Solidity throws an exception.
189Malicious actors might be able to force the call stack to a high value
190before they interact with your contract. Note that, since `Tangerine Whistle <https://eips.ethereum.org/EIPS/eip-608>`_ hardfork, the `63/64 rule <https://eips.ethereum.org/EIPS/eip-150>`_ makes call stack depth attack impractical. Also note that the call stack and the expression stack are unrelated, even though both have a size limit of 1024 stack slots.
191
192Note that ``.send()`` does **not** throw an exception if the call stack is
193depleted but rather returns ``false`` in that case. The low-level functions
194``.call()``, ``.delegatecall()`` and ``.staticcall()`` behave in the same way.
195
196Authorized Proxies
197==================
198
199If your contract can act as a proxy, i.e. if it can call arbitrary contracts
200with user-supplied data, then the user can essentially assume the identity
201of the proxy contract. Even if you have other protective measures in place,
202it is best to build your contract system such that the proxy does not have
203any permissions (not even for itself). If needed, you can accomplish that
204using a second proxy:
205
206.. code-block:: solidity
207
208    // SPDX-License-Identifier: GPL-3.0
209    pragma solidity ^0.8.0;
210    contract ProxyWithMoreFunctionality {
211        PermissionlessProxy proxy;
212
213        function callOther(address _addr, bytes memory _payload) public
214                returns (bool, bytes memory) {
215            return proxy.callOther(_addr, _payload);
216        }
217        // Other functions and other functionality
218    }
219
220    // This is the full contract, it has no other functionality and
221    // requires no privileges to work.
222    contract PermissionlessProxy {
223        function callOther(address _addr, bytes memory _payload) public
224                returns (bool, bytes memory) {
225            return _addr.call(_payload);
226        }
227    }
228
229tx.origin
230=========
231
232Never use tx.origin for authorization. Let's say you have a wallet contract like this:
233
234.. code-block:: solidity
235
236    // SPDX-License-Identifier: GPL-3.0
237    pragma solidity >=0.7.0 <0.9.0;
238    // THIS CONTRACT CONTAINS A BUG - DO NOT USE
239    contract TxUserWallet {
240        address owner;
241
242        constructor() {
243            owner = msg.sender;
244        }
245
246        function transferTo(address payable dest, uint amount) public {
247            // THE BUG IS RIGHT HERE, you must use msg.sender instead of tx.origin
248            require(tx.origin == owner);
249            dest.transfer(amount);
250        }
251    }
252
253Now someone tricks you into sending Ether to the address of this attack wallet:
254
255.. code-block:: solidity
256
257    // SPDX-License-Identifier: GPL-3.0
258    pragma solidity >=0.7.0 <0.9.0;
259    interface TxUserWallet {
260        function transferTo(address payable dest, uint amount) external;
261    }
262
263    contract TxAttackWallet {
264        address payable owner;
265
266        constructor() {
267            owner = payable(msg.sender);
268        }
269
270        receive() external payable {
271            TxUserWallet(msg.sender).transferTo(owner, msg.sender.balance);
272        }
273    }
274
275If your wallet had checked ``msg.sender`` for authorization, it would get the address of the attack wallet, instead of the owner address. But by checking ``tx.origin``, it gets the original address that kicked off the transaction, which is still the owner address. The attack wallet instantly drains all your funds.
276
277.. _underflow-overflow:
278
279Two's Complement / Underflows / Overflows
280=========================================
281
282As in many programming languages, Solidity's integer types are not actually integers.
283They resemble integers when the values are small, but cannot represent arbitrarily large numbers.
284
285The following code causes an overflow because the result of the addition is too large
286to be stored in the type ``uint8``:
287
288.. code-block:: solidity
289
290  uint8 x = 255;
291  uint8 y = 1;
292  return x + y;
293
294Solidity has two modes in which it deals with these overflows: Checked and Unchecked or "wrapping" mode.
295
296The default checked mode will detect overflows and cause a failing assertion. You can disable this check
297using ``unchecked { ... }``, causing the overflow to be silently ignored. The above code would return
298``0`` if wrapped in ``unchecked { ... }``.
299
300Even in checked mode, do not assume you are protected from overflow bugs.
301In this mode, overflows will always revert. If it is not possible to avoid the
302overflow, this can lead to a smart contract being stuck in a certain state.
303
304In general, read about the limits of two's complement representation, which even has some
305more special edge cases for signed numbers.
306
307Try to use ``require`` to limit the size of inputs to a reasonable range and use the
308:ref:`SMT checker<smt_checker>` to find potential overflows.
309
310.. _clearing-mappings:
311
312Clearing Mappings
313=================
314
315The Solidity type ``mapping`` (see :ref:`mapping-types`) is a storage-only
316key-value data structure that does not keep track of the keys that were
317assigned a non-zero value.  Because of that, cleaning a mapping without extra
318information about the written keys is not possible.
319If a ``mapping`` is used as the base type of a dynamic storage array, deleting
320or popping the array will have no effect over the ``mapping`` elements.  The
321same happens, for example, if a ``mapping`` is used as the type of a member
322field of a ``struct`` that is the base type of a dynamic storage array.  The
323``mapping`` is also ignored in assignments of structs or arrays containing a
324``mapping``.
325
326.. code-block:: solidity
327
328    // SPDX-License-Identifier: GPL-3.0
329    pragma solidity >=0.6.0 <0.9.0;
330
331    contract Map {
332        mapping (uint => uint)[] array;
333
334        function allocate(uint _newMaps) public {
335            for (uint i = 0; i < _newMaps; i++)
336                array.push();
337        }
338
339        function writeMap(uint _map, uint _key, uint _value) public {
340            array[_map][_key] = _value;
341        }
342
343        function readMap(uint _map, uint _key) public view returns (uint) {
344            return array[_map][_key];
345        }
346
347        function eraseMaps() public {
348            delete array;
349        }
350    }
351
352Consider the example above and the following sequence of calls: ``allocate(10)``,
353``writeMap(4, 128, 256)``.
354At this point, calling ``readMap(4, 128)`` returns 256.
355If we call ``eraseMaps``, the length of state variable ``array`` is zeroed, but
356since its ``mapping`` elements cannot be zeroed, their information stays alive
357in the contract's storage.
358After deleting ``array``, calling ``allocate(5)`` allows us to access
359``array[4]`` again, and calling ``readMap(4, 128)`` returns 256 even without
360another call to ``writeMap``.
361
362If your ``mapping`` information must be deleted, consider using a library similar to
363`iterable mapping <https://github.com/ethereum/dapp-bin/blob/master/library/iterable_mapping.sol>`_,
364allowing you to traverse the keys and delete their values in the appropriate ``mapping``.
365
366Minor Details
367=============
368
369- Types that do not occupy the full 32 bytes might contain "dirty higher order bits".
370  This is especially important if you access ``msg.data`` - it poses a malleability risk:
371  You can craft transactions that call a function ``f(uint8 x)`` with a raw byte argument
372  of ``0xff000001`` and with ``0x00000001``. Both are fed to the contract and both will
373  look like the number ``1`` as far as ``x`` is concerned, but ``msg.data`` will
374  be different, so if you use ``keccak256(msg.data)`` for anything, you will get different results.
375
376***************
377Recommendations
378***************
379
380Take Warnings Seriously
381=======================
382
383If the compiler warns you about something, you should change it.
384Even if you do not think that this particular warning has security
385implications, there might be another issue buried beneath it.
386Any compiler warning we issue can be silenced by slight changes to the
387code.
388
389Always use the latest version of the compiler to be notified about all recently
390introduced warnings.
391
392Messages of type ``info`` issued by the compiler are not dangerous, and simply
393represent extra suggestions and optional information that the compiler thinks
394might be useful to the user.
395
396Restrict the Amount of Ether
397============================
398
399Restrict the amount of Ether (or other tokens) that can be stored in a smart
400contract. If your source code, the compiler or the platform has a bug, these
401funds may be lost. If you want to limit your loss, limit the amount of Ether.
402
403Keep it Small and Modular
404=========================
405
406Keep your contracts small and easily understandable. Single out unrelated
407functionality in other contracts or into libraries. General recommendations
408about source code quality of course apply: Limit the amount of local variables,
409the length of functions and so on. Document your functions so that others
410can see what your intention was and whether it is different than what the code does.
411
412Use the Checks-Effects-Interactions Pattern
413===========================================
414
415Most functions will first perform some checks (who called the function,
416are the arguments in range, did they send enough Ether, does the person
417have tokens, etc.). These checks should be done first.
418
419As the second step, if all checks passed, effects to the state variables
420of the current contract should be made. Interaction with other contracts
421should be the very last step in any function.
422
423Early contracts delayed some effects and waited for external function
424calls to return in a non-error state. This is often a serious mistake
425because of the re-entrancy problem explained above.
426
427Note that, also, calls to known contracts might in turn cause calls to
428unknown contracts, so it is probably better to just always apply this pattern.
429
430Include a Fail-Safe Mode
431========================
432
433While making your system fully decentralised will remove any intermediary,
434it might be a good idea, especially for new code, to include some kind
435of fail-safe mechanism:
436
437You can add a function in your smart contract that performs some
438self-checks like "Has any Ether leaked?",
439"Is the sum of the tokens equal to the balance of the contract?" or similar things.
440Keep in mind that you cannot use too much gas for that, so help through off-chain
441computations might be needed there.
442
443If the self-check fails, the contract automatically switches into some kind
444of "failsafe" mode, which, for example, disables most of the features, hands over
445control to a fixed and trusted third party or just converts the contract into
446a simple "give me back my money" contract.
447
448Ask for Peer Review
449===================
450
451The more people examine a piece of code, the more issues are found.
452Asking people to review your code also helps as a cross-check to find out whether your code
453is easy to understand - a very important criterion for good smart contracts.
454