EEA EthTrust Certification is a claim by a security reviewer that the Tested Code is not vulnerable to a number of known attacks or failures to operate as expected, based on the reviewer's assessment against those specific requirements.
No amount of security review can guarantee that a smart contract is secure against **all possible** vulnerabilities, as explained in . However reviewing a smart contract according to the requirements in this specification provides assurance that it is not vulnerable to a known set of potential attacks. This assurance is backed not only by the reputation of the reviewer, but by the collective reputations of the multiple experts in security from many competing organizations, who collaborated within the EEA to ensure this specification defines protections against a real and significant set of known vulnerabilities.Example of a link to [M] Document Special Code Use
Variables, introduced to be described further on in a statement or requirement, are formatted as var . Occasional explanatory notes, presented as follows, are not normative and do not specify formal requirements.Tested code MUST NOT make tests that ether balance is equal to (i.e. `==`) a specified amount or the value of a variable.Following the requirement is a brief explanation of the relevant vulnerability, and links to further discussion, in this case a Related Requirement, a relevant subsection of , a link to the "Smart Contract Weakness Classification Registry" [[swcregistry]] that includes test cases, and a link to the description of a related general vulnerability in the "Common Weakness Enumeration" [[CWE]].
Good Practices are formatted the same way as Requirements, with an apparent level of [GP]. However, as explained in meeting them is not necessary and does not in itself change conformance to this specification.
Overriding Requirements enable simpler testing for common simple cases.
For more complex Tested Code, that uses features which need to be handled
with extra care to avoid introducing vulnerabilities, they ensure such usage is
appropriately checked.
In a typical case of an Overriding Requirement for a Security Level [S] requirement,
they apply in relatively unusual cases or where automated systems are generally unable
to verify that Tested Code meets the requirement. Further verification
of the applicable Overriding Requirement(s) can determine that the
Tested Code is using a feature appropriately, and therefore passes the
Security Level [S] requirement.
If there is not an Overriding Requirement for a requirement
that the Tested code does not meet, the Tested code
is not eligible for EEA EthTrust Certification. However, even for such cases,
note the Recommended Good Practice
[**[GP] Meet as many requirements as possible**](#req-R-meet-all-possible); meeting
any requirements in this specification will improve the security of smart contracts.
In the following requirement:
- the Security Level is "**[S]**",
- the name is "**No `tx.origin`**", and
- the Overriding Requirement is "[Q] Verify tx.origin
usage".
The requirement that the tested code does not contain a `tx.origin` instruction
is automatically verifiable.
Tested Code that does have a valid use for tx.origin
,
as decided by the auditor, and meets the Security Level [Q] Overriding Requirement
[Q] Verify tx.origin
usage
conforms to this Security Level [S] requirement.
In principle anyone can submit a smart contract for verification. However submitters should be aware of any restrictions on usage arising from copyright conditions or the like. In addition, meeting certain requirements can be more difficult to demonstrate in a situation of limited control over the development of the smart contract.
The Working Group expects its own members, who wrote the specification, to behave to a high standard of integrity and to know the specification well, and notes that there are many others who also do so. The Working Group or EEA MAY seek to develop an auditor certification program for subsequent versions of the EEA EthTrust Security Levels Specification.A common feature of Ethereum networks is the use of Oracles; functions that can be called to provide information from outside a blockchain, from weather forecasts to random number generation. This specification contains requirements to check that smart contracts are sufficiently robust to deal appropriately with whatever information is returned (including the possibility of mal-formed data, that can potentially be delibrately crafted as an attack). However, determining whether data produced by an Oracle is actually true is beyond the scope of this specification, and it is possible that an Oracle provides misinformation or even actively produces harmful disinformation.
Some requirements in the document refer to Malleable Signatures. These are signatures created according to a scheme constructed so that, given a message and a signature, it is possible to efficiently compute the signature of a different message - usually one that has been transformed in specific ways. While there are very valuable use cases that such signature schemes allow, if not used carefully they can lead to vulnerabilites, which is why this specfication seeks to constrain their use appropriately.
For more information on this topic, and the potential for exploitation, see also [[chase]].Gas Griefing is the deliberate abuse of the Gas mechanism that Ethereum uses to regulate the consumption of computing power, to cause an unexpected or adverse outcome much in the style of a Denial of Service attack. Because Ethereum is designed with the Gas mechanism as a regulating feature, it is insufficient to simply check that a transaction has enough Gas; checking for Gas Griefing needs to take into account the goals and business logic that the Tested Code implements.
In addition, a common feature of Ethereum network upgrades is to change the Gas Price of specific operations. EEA EthTrust certification only applies for the EVM version(s) specified; it is not valid for other versions. Thus it is important to recheck code to ensure its security properties remain the same across network upgrades, or take remedial action.MEV, used in this document to mean "Maliciously Extracted Value", refers to the potential for block producers or other paticipants in a blockchain to extract value that is not intentionally given to them, in other words to steal it, by maliciously reordering transactions, as in Timing Attacks, or suppressing them.
The term MEV is commonly expanded as "Miner Extracted Value", and sometimes "Maximum Extractable Value". As in the example above, sometimes block miners can take best advantage of a vulnerability. But MEV can be exploited by other participants, for example duplicating most of a submitted transaction, but offering a higher fee so it is processed first.
Some MEV attacks can be prevented by careful consideration of the information that is included in a transaction, including the parameters required by a contract. Other strategies include the use of hash commitment schemes [[hash-commit]], batch execution, private transactions [[EEA-clients]], Layer 2 [[EEA-L2]], or an extension to establish the ordering of transactions before releasing sensitive information to all nodes participating in a blockchain. The Ethereum Foundation curates up to date information on MEV [[EF-MEV]].Timing Attacks are a class of MEV attacks where an adversary benefits from placing their or a victim's transactions earlier or later in a block. They include Front-Running, Back-Running, and Sandwich Attacks.
Front-Running is based on the fact that transactions are visible to the participants in the network before they are added to a block. This allows a malicious participant to submit an alternative transaction, frustrating the aim of the original transaction.
Back-Running is similar to Front-Running, except the attacker places their transactions after the one they are attacking.
In Sandwich Attacks, an attacker places a victim's transaction undesirably between two other transactions.
EEA EthTrust Certification is available at three Security Levels. The Security Levels describe minimum requirements for certifications at each Security Level: [S], [M], and [Q]. These Security Levels provide successively stronger assurance that a smart contract does not have specific security vulnerabilities.
- [Security Level [S]](#sec-levels-one) is designed so that for most cases, where common features of Solidity are used following well-known patterns, Tested Code can be certified by an automated "static analysis" tool. - [Security Level [M]](#sec-levels-two) mandates a stricter static analysis. It includes requirements where a human auditor is expected to determine whether use of a feature is necessary, or whether a claim about the security properties of code is justified. - [Security Level [Q]](#sec-levels-three) provides analysis of the business logic the Tested Code implements, and that the code not only does not exhibit known security vulnerabilities, but also correctly implements what it claims to do. The optional [Recommended Good Practices](#sec-good-practice-recommendations), correctly implemented, further enhance the Security of smart contracts. However it is not necessary to test them to conform to this specification. The vulnerabilities addressed by this specification come from a number of sources, including Solidity Security Alerts [[solidity-alerts]], the Smart Contract Weakness Classification [[swcregistry]], TMIO Best practices [[tmio-bp]], various sources of Security Advisory Notices, discussions in the Ethereum community and academics presenting newly discovered vulnerabilities, and the extensive practical experience of participants in the Working Group.EEA EthTrust Certification at Security Level [S] is intended to allow an unguided automated tool to analyze most contracts' bytecode and source code, and determine whether they meet the requirements. For some situations that are difficut to verify automatically, usually only likely to arise in a small minority of contracts, there are higher-level Overriding Requirements that can be fulfilled to meet a requirement for this Security Level.
To be eligible for EEA EthTrust Certification for Security Level [S], Tested code MUST fulfil all Security Level [S] requirements, unless it meets the applicable Overriding Requirement(s) for any Security Level [S] requirement it does not meet.[S] Encode hashes with chainid
Tested code MUST create hashes for transactions that incorporate chainid
values
following the recommendation described in [[!EIP-155]]
[S] No CREATE2
Tested code MUST NOT contain a CREATE2
instruction.
unless it meets the Set of Overriding Requirements
CREATE2
opcode provides the ability to interact with addresses
that do not exist yet on-chain but could possibly eventually contain code.
While this can be useful for deployments and counterfactual interactions with contracts,
it may allow external calls to code that is not yet known, and could turn out to be
malicous or insecure due to errors or weak protections.
[S] No tx.origin
Tested code MUST NOT contain a tx.origin
instruction
unless it meets the Overriding Requirement
[Q] Verify tx.origin
usage
tx.origin
is a global variable in Solidity which returns the address
of the account that sent the transaction. A contract using tx.origin
can allow an authorized account to call into a malicious contract,
enabling the malicious contract to pass authorization checks in unintended cases. Use
msg.sender
for authorization instead of tx.origin
.
[S] No Exact Balance Check
Tested code MUST NOT test that the balance of an account is exactly equal to
(i.e. ==
) a specified amount or the value of a variable.
[S] No Conflicting Inheritance
Tested code MUST NOT include more than one variable, or operative function with
different code, with the same name
unless it meets the
Overriding Requirement:
[M] Document Name Conflicts.
[S] No Hashing Consecutive Variable Length Arguments
Tested Code MUST NOT use abi.encodePacked()
with consecutive variable length arguments.
abi.encodePacked()
are packed in order prior to hashing.
Hash collisions are possible by rearranging the elements between consecutive,
variable length arguments while maintaining that their concatenated order is the same.
[S] No Self-destruct
Tested code MUST NOT contain the selfdestruct()
instruction
or its now-deprecated alias suicide()
unless it meets the Set of Overriding Requirements
[S] No assembly {}
Tested Code MUST NOT contain the assembly {}
instruction
unless it meets the Set of Overriding Requirements
assembly {}
Attack Vectors,
[S] No Unicode Direction Control Characters
Tested code MUST NOT contain any of the Unicode Direction Control Characters
U+2066
, U+2067
, U+2068
, U+2029
,
U+202A
, U+202B
, U+202C
, U+202D
,
or U+202E
unless it meets the Overriding Requirement
[M] No Unnecessary Unicode Controls.
See also the Related Requirements: [M] Protect External Calls, [M] Handle External Call Returns, and [Q] Verify External Calls.
[S] Check External Calls Return
Tested Code that makes external calls using the Low-level Call Functions (i.e. call
,
delegatecall
, staticcall
, send
, and transfer
)
MUST check the returned value from each usage to determine whether the call failed.
call()
,
- delegatecall()
,
- staticcall()
,
- `send()`, and
- `transfer()`.
Calls using these functions behave differently. They return a boolean indicating whether the call completed successfully.
Not testing explicitly whether these calls fail may lead to unexpected behavior in the caller contract.
See also [SWC-104](https://swcregistry.io/docs/SWC-104) in [[swcregistry]],
error handling documentation in [[error-handling]], unchecked return value as described in [[CWE-252]],
and the Related Requirements:
[S] Use Check-Effects-Interaction,
[M] Handle External Call Returns,
[Q] Verify External Calls
[S] Use Check-Effects-Interaction
Tested code that makes external calls MUST use the
Checks-Effects-Interactions
pattern to protect against Re-entrancy Attacks
unless it meets the Set of Overriding Requirements
or it meets the Set of Overriding Requirements
[S] No delegatecall()
Tested Code MUST NOT contain the delegatecall()
instruction
unless it meets the Overriding Requirement:
[M] Protect External Calls.
or it meets the Set of Overriding Requirements
[S] No Overflow/Underflow
Tested code MUST NOT use a version of Solidity older than 0.8.0
unless it meets the Set of Overriding Requirements
[S] Explicit Storage
Tested code MUST NOT use a version of Solidity older than 0.5.0
unless it meets the Overriding Requirement:
[M] Declare storage
Explicitly.
[S] Explicit Constructors
Tested code MUST NOT use a version of Solidity older than 0.4.22
unless it meets the Overriding Requirement:
[M] Declare Constructors Explicitly.
[S] Compiler Bug SOL-2022-6
Tested code that ABI-encodes a tuple (including a `struct`, `return` value, or paramater list)
with the ABIEncoderV2, that includes a dynamic component and whose last element is a
calldata
static array of base type `uint` or `bytes32`
MUST NOT use a version of Solidity between 0.5.8 and 0.8.15 (inclusive).
[S] Compiler Bug SOL-2022-5 with .push()
Tested code that copies `bytes` arrays from calldata
or
memory
whose size is not a multiple of 32 bytes, and has an empty `.push()`
instruction that writes to the resulting array,
MUST NOT use a version of Solidity older than 0.8.15.
[S] Compiler Bug SOL-2022-3
Tested code that
MUST NOT use a version of Solidity between 0.6.9 and 0.8.13 (inclusive).
[S] Compiler Bug SOL-2022-2
Tested code with a nested array that
abi.encode()
, orMUST NOT use a version of Solidity between 0.6.9 and 0.8.13 (inclusive).
[S] Compiler Bug SOL-2022-1
Tested code that
and passes such literals to abi.encodeCall()
as the first parameter,
MUST NOT use version 0.8.11 nor 0.8.12 of Solidity.
bytesNN
or Fixed-length Variable types,
that specify the length of the variable as a fixed number of bytes, following the pattern
- `bytes1`
- `bytes2`
- ...
- `bytes10`
- ...
- `bytes32`
Compilers from 0.8.11 and 0.8.12 had a bug that meant literal parameters were incorrectly
encoded by `abi.encodeCall()` in certain circumstances.
See also the 16 March 2022
[security alert](https://blog.soliditylang.org/2022/03/16/encodecall-bug/).
[S] Compiler Bug SOL-2021-4 Tested Code that uses custom value types shorter than 32 bytes SHOULD not use version 0.8.8 of Solidity.
Compiler version 0.8.8 had a bug that assigned a full 32 bytes of storage to custom types that did not need it. This can be misused to enable reading arbitrary storage, as well as causing errors if the Tested Code contains code compiled using different Compiler versions. See also the 29 September 2021 [security alert](https://blog.soliditylang.org/2021/09/29/user-defined-value-types-bug/)
[S] Compiler Bug SOL-2021-2
Tested code that uses abi.decode()
on byte arrays as `memory`,
MUST NOT use the ABIEncoderV2 with a version of Solidity between 0.4.16 and 0.8.3
(inclusive).
[S] Compiler Bug SOL-2021-1
Tested code that has 2 or more occurrences of an instruction
keccak(mem,length)
where
MUST NOT use the Optimizer with a version of Solidity older than 0.8.3.
[S] Compiler Bug SOL-2020-11-push
Tested code that copies an empty byte array to storage, and subsequently increases
the size of the array using push()
MUST NOT a use version of Solidity
older than 0.7.4.
[S] Compiler Bug SOL-2020-10
Tested code that copies an array of types shorter than 16 bytes to a longer array
MUST NOT a use version of Solidity older than 0.7.3.
[S] Compiler Bug SOL-2020-9
Tested code that defines Free Functions MUST NOT use version 0.7.1 of Solidity.
executed in the context of a contract. They still have access to the variable this, can call other contracts, send them Ether and destroy the contract that called them, among other things. The main difference to functions defined inside a contract is that free functions do not have direct access to storage variables and functions not in their scope. https://docs.soliditylang.org/en/latest/contracts.html#functionsThe 0.7.1 compiler did not correctly distinguish overlapping Free Function declarations, meaning that the wrong function could be called. See examples of a [passing contract](https://entethalliance.github.io/eta-registry/examples/SOL-2020-9-fail.sol) and a [failing contract](https://entethalliance.github.io/eta-registry/examples/SOL-2020-9-fail.sol) for this requirement.
[S] Compiler Bug SOL-2020-8
Tested code that calls internal library functions with calldata parameters
called via using for
MUST NOT use version 0.6.9 of Solidity.
[S] Compiler Bug SOL-2020-6
Tested code that accesses an array slice using an expression for the starting index
that can evaluate to a value other than zero
MUST NOT use the ABIEncoderV2 with a version of Solidity between 0.6.0 and 0.6.7 (inclusive).
[S] Compiler Bug SOL-2020-7
Tested code that passes a string literal containing two consecutive backslash ("\")
characters to an encoding function or an external call
MUST NOT use the ABIEncoderV2 with a version of Solidity between 0.5.14 and 0.6.7 (inclusive).
[S] Compiler Bug SOL-2020-5
Tested code that defines a contract that does not include a constructor but
has a base contract that defines a constructor not defined as `payable`
MUST NOT use a version of Solidity between 0.4.5 and 0.6.7 (inclusive),
unless it meets the Overriding Requirement
[M] Check Constructor Payment.
[S] Compiler Bug SOL-2020-4
Tested code that makes assignments to tuples that
MUST NOT use a version of Solidity older than 0.6.4.
[S] Compiler Bug SOL-2020-3
Tested code that declares arrays of size larger than 2^256-1 MUST NOT use a version
of Solidity older than 0.6.5.
[S] Compiler Bug SOL-2020-1
Tested code that declares variables inside a `for` loop that contains a `break`
or `continue` statement MUST NOT use the Yul Optimizer with version 0.6.0 nor a version
of Solidity between 0.5.8 and 0.5.15 (inclusive).
[S] Compiler Bug SOL-2020-11-length
Tested code that copies an empty byte array to storage, and subsequently increases
the size of the array by assigning the length
attribute MUST NOT
use a version of Solidity older than 0.6.0.
[S] Compiler Bug SOL-2019-10
Tested code MUST NOT use the combination of all of
[S] Compiler Bugs SOL-2019-3,6,7,9
Tested code that uses `struct` or arrays MUST NOT use the ABIEncoderV2 option
with a version of Solidity between 0.4.16 and 0.5.10 (inclusive).
[S] Compiler Bug SOL-2019-8
Tested code that assigns an array of signed integers to an array of a different type
MUST NOT use a version of Solidity between 0.4.7 and 0.5.9 (inclusive).
[S] Compiler Bug SOL-2019-5
Tested code that calls an uninitialized internal function pointer
in the constructor
MUST NOT use a version between 0.4.5 and 0.4.25 (inclusive) nor a version between
0.5.0 and 0.5.7 (inclusive) of Solidity.
[S] Compiler Bug SOL-2019-4
Tested code that uses events containing contract types, in libraries,
MUST NOT use a version of Solitidy between 0.5.0 and 0.5.7.
[S] Compiler Bug SOL-2019-2
Tested code that makes index access to bytesNN types with a second parameter
(not the index) whose compile-time value evaluates to 31
MUST NOT use the Optimizer with versions 0.5.5 nor 0.5.6 of Solitidy.
[S] Compiler Bug SOL-2019-1
Tested code that nests bitwise shifts to produce a total shift of more than 256 bits
and compiles for the Constantinople
or later EVM version
MUST NOT use the Optimizer option with version 0.5.5 of Solidity.
[S] Compiler Bug SOL-2018-4
Tested code that has a match for the regexp `[^/]\\*\\* *[^/0-9 ]`
MUST NOT use a version of Solidity older than 0.4.25.
[S] Compiler Bug SOL-2018-3
Tested code that uses a struct
in events
MUST NOT use a version of Solidity between 0.4.17 and 0.4.24 (inclusive).
[S] Compiler Bug SOL-2018-2
Tested code that calls a function matching the regexp
`returns[^;{]*\\[\\s*[^\\] \\t\\r\\n\\v\\f][^\\]]*\\]\\s*\\[\\s*[^\\] \\t\\r\\n\\v\\f][^\\]]*\\][^{;]*[;{]`
MUST NOT use a version of Solidity older than 0.4.22.
[S] Compiler Bug SOL-2018-1
Tested code that uses both a new-style constructor with the constructor
keyword, and an old-style constructor (a function with the same name as the contract),
which are not exactly the same MUST NOT use version 0.4.22 of Solidity.
[S] Compiler Bug SOL-2017-5
Tested code with a function that is `payable` whose name consists only of
any number of zeros ("0"), and does not have a fallback function,
MUST NOT use a version of Solidity older than 0.4.18.
[S] Compiler Bug SOL-2017-4
Tested code that uses the delegatecall()
instruction
MUST NOT use a version of Solidity older than 0.4.15.
[S] Compiler Bug SOL-2017-3
Tested code that uses the ecrecover()
pre-compile
MUST NOT use a version of Solidity older than 0.4.14
unless it meets the Overriding Requirement
[M] Validate ecrecover()
Input.
[S] Compiler Bug SOL-2017-2
Tested code with functions that accept 2 or more parameters, of which any but the last are of bytesNN type
MUST NOT use a version of Solidity older than 0.4.12.
[S] Compiler Bug SOL-2017-1
Tested code that contains any number that either begins with `0xff` and ends
with `00`, or begins with `0x00` and ends with `ff`, twice, OR
uses such a number in the constructor,
MUST NOT use the Optimizer with a version of Solidity older than 0.4.11.
[S] Compiler Bug SOL-2016-11
Tested code that uses a version older than 0.4.7 of Solidity MUST NOT
call the Identity Contract
UNLESS it meets the Overriding Requirement
[M] Compiler Bug Check Identity Calls.
[S] Compiler Bug SOL-2016-10
Tested code MUST NOT use the Optimizer option with version 0.4.5 of Solidity.
[S] Compiler Bug SOL-2016-9
Tested code that use variables of a type shorter than 17 bytes
MUST NOT use a version of Solidity older than 0.4.4.
[S] Compiler Bug SOL-2016-8
Tested code that uses the sha3()
instruction
MUST NOT use the Optimizer option with a version of Solidity older than 0.4.3.
[S] Compiler Bug SOL-2016-7
Tested code that uses delegatecall()
from a function that can receive
Ether to call a Library Function MUST NOT use versions 0.4.0 or 0.4.1 of Solidity.
[S] Compiler Bug SOL-2016-6
Tested code that sends Ether MUST NOT use a version of Solidity older than 0.4.0
unless it meets the overriding requirement
[M] Compiler Bug No Zero Ether Send.
[S] Compiler Bug SOL-2016-5
Tested code that creates a dynamically sized array with a `length` that can be zero
MUST NOT use a version of Solidity older than 0.3.6.
[S] Compiler Bug SOL-2016-4
Tested code that creates a `Jump Destination` opcode
MUST NOT use the Optimizer with versions of Solidity older than 0.3.6.
[S] Compiler Bug SOL-2016-3
Tested code that compares the values of data of type bytesNN
MUST NOT use a version of Solidity older than 0.3.3.
[S] Compiler Bug SOL-2016-2
Tested code that uses arrays, with data types whose size is less than 17 bytes
MUST NOT use a version of Solidity older than 0.3.1.
[S] No Ancient Compilers
Tested code MUST NOT use a version of Solidity older than 0.3.
EEA EthTrust Certification at Security Level [M] means that the Tested Code has been carefully reviewed by a human auditor or team, doing a "manual analysis", and important security issues have been addressed to their satisfaction.
This level includes a number of Overriding Requirements for cases when Tested Code does not meet a Security Level [S] requirement directly, because it uses an uncommon feature that introduces higher risk, or because in certain circumstsances testing that the requirement has been met requires human judgement. Passing the relevant Overriding Requirement tests that the feature has been implemented sufficiently well to satisfy the auditor that it does not expose the Tested Code to the known vulnerabilities identified in this Security Level.
[M] Pass Security Level [S]
To be eligible for EEA EthTrust certification at Security Level [M],
Tested code MUST meet the requirements for .
[M] Explicitly Disambiguate Evaluation Order
Tested code MUST NOT contain statements where variable evaluation order
can result in different outcomes
[M] No failing `assert()` statements
assert()
statements in Tested Code MUST NOT fail.
[M] No Unnecessary Unicode Controls
Tested code MUST NOT use Unicode direction control characters
unless they are necessary to render text appropriately,
and the resulting text does not mislead readers.
This is an Overriding Requirement for
[S] No Unicode Direction Control Characters.
Security Level [M] permits the use of Unicode direction control characters in text strings, subject to analysis of whether they are necessary.
[M] No Homoglyph-style Attack
Tested code MUST not use homoglyphs, Unicode control characters, combining characters, or characters from multiple
Unicode blocks if the impact is misleading.
[M] Protect External Calls
For Tested code that makes external calls:
unless it meets the Set of Overriding Requirements
This is an Overriding Requirement for [S] Use Check-Effects-Interaction.
EEA EthTrust Certification at Security Level [M] allows calling within a set of contracts that form part of the Tested Code. This ensures all contracts called are audited as a group at this Security Level. The same level of protection against Re-entrancy Attacks has to be provided to the Tested Code overall as for the Security Level [S] requirement.
[M] Handle External Call Returns
Tested Code that makes external calls MUST reasonably handle possible errors.
[M] Document Special Code Use
Tested Code MUST document the need for each instance of:
selfdestruct()
or its deprecated alias suicide()
,assembly {}
,CREATE2
,block.number
or block.timestamp
,and MUST describe how the Tested Code protects against misuse or errors in these cases, and the documentation MUST be available to anyone who can call the Tested Code.
This is part of several Sets of Overriding Requirements, one for each of
See also the Related requirements:
[Q] Document Contract Logic,
[Q] Document System Architecture,
[Q] Implement as Documented,
[Q] Verify External Calls,
[M] Avoid Common assembly {}
Attack Vectors,
[M] Compiler Bug SOL-2022-5 in `assembly {}`,
[M] Compiler Bug SOL-2022-4,
[M] Compiler Bug SOL-2021-3, and
[M] Compiler Bug SOL-2019-2 in `assembly {}`.
[M] Ensure Proper Rounding Of Computations Affecting Value
Tested code may implement mathematical formulas over real numbers using integer
arithmetic. Such code typically introduces rounding errors because
integers and rational numbers cannot precisely represent real numbers.
Tested code MUST handle the rounding properly:
[M] Protect Self-destruction
Tested code that contains the selfdestruct()
or suicide()
instructions MUST
This is an Overriding Requirement for [S] No Self-destruct.
[M] Avoid Common assembly {}
Attack Vectors
Tested Code MUST NOT use the assembly {}
instruction to change a variable
unless the code cannot:
This is part of a Set of Overriding Requirements for
[S] No assembly {}
.
[M] Protect CREATE2
Calls
For Tested Code that uses the CREATE2
instruction,
any contract to be deployed using CREATE2
selfdestruct()
, delegatecall()
nor
callcode()
instructions, andunless it meets the Set of Overriding Requirements
CREATE2
.CREATE2
opcode's ability to interact with addresses
whose code does not exist yet on-chain mandates protections to prevent external calls to
malicous or insecure contract code that is not yet known.
The Tested code needs to include any code that can be deployed using
CREATE2
to verify protections are in place and the code behaves
as the contract author claims. This includes ensuring opcodes that can change the
immutability or forward calls in the contracts deployed with CREATE2
,
such as selfdestruct()
, delegatecall()
and
callcode()
, are not present.
If any of these opcodes are present, the additional protections and documentation
required by the Overriding Requirements are necessary.
[M] Declare storage
Explicitly
Tested code that uses a version of Solidity older than 0.5.0
MUST explicitly declare storage
or memory
for storage objects,
and must justify the need for any storage
item.
This is an Overriding Requirement for
[S] Explicit Storage.
Solidity's default way of providing uninitialised storage can be and has been exploited
[[storage-honeypots]], because it can enable access to an unnitiatilized pointer
[[CWE-824]]. This was addressed by checking that storage is explicitly declared,
from version 0.5.0, but for older compilers it is important to test for this exploit.
[M] No Overflow/Underflow
Tested code MUST NOT contain calculations that can overflow or underflow unless
This is an Overriding Requirement for [S] No Overflow/Underflow.
[M] Declare Explicit Constructors
Tested code that uses a version of Solidity older than 0.4.22
MUST declare constructor
methods explicitly.
This is an Overriding Requirement for
[S] Explicit Constructors.
[M] Document Name Conflicts
Tested code MUST clearly document the order of inheritance for each function or variable that shares a name with another function or variable.
This is an Overriding Requirement for
[S] No Conflicting Inheritance.
[M] Sources of Randomness
Sources of randomness used in Tested Code MUST be
sufficiently resistant to prediction that their purpose is met.
[M] Don't misuse block data
Block numbers and timestamps used in Tested Code MUST not introduce vulnerabilities
to MEV or similar attacks.
[M] Proper Signature Verification
Tested Code MUST use proper signature verification to ensure authenticity of messages
that were signed off-chain, e.g. by using ecrecover()
.
Some smart contracts process messages that were signed off-chain to increase flexibility, while maintaining authenticity. Smart contracts performing their own signature verification must ensure that they are correctly verifying message authenticity.
See also SWC-122 [[swcregistry]]. For code that does use `ecrecover()`, see the Related Requirements [S] Compiler Bug SOL-2017-3 and [M] Validateecrecover()
input
[M] No Improper Usage of Malleable Signatures for Replay Attack Protection
Tested Code using signatures to prevent replay attacks MUST NOT rely on
Malleable Signatures.
[M] Compiler Bug Storage Write Removal Bug on Conditional Early Termination
Tested code that uses a version of Solidity between 0.8.13 and 0.8.17 inclusive,
MUST NOT not have storage writes followed by conditional early terminations
from inline assembly functions containing return()
or stop()
instructions.
This is part of the Set of Overriding Requirements for
[S] No assembly {}
.
[M] Compiler Bug SOL-2022-5 in `assembly {}`
Tested code that copies `bytes` arrays from calldata or memory whose size is not
a multiple of 32 bytes, and has an `assembly {}` instruction that reads that data
without explicitly matching the length that was copied,
MUST NOT use a version of Solidity older than 0.8.15.
This is part of the Set of Overriding Requirements for
[S] No assembly {}
.
assembly {}
Attack Vectors,
[M] Document Special Code Use,
[M] Compiler Bug SOL-2022-4,
[M] Compiler Bug SOL-2021-3, and
[M] Compiler Bug SOL-2019-2 in `assembly {}`.
[M] Compiler Bug SOL-2022-4
Tested code that has at least two `assembly {}` instructions, such that one writes
to memory e.g. by storing a value in a variable, but does not access that memory again,
and code in a another `assembly {}` instruction refers to that memory,
MUST NOT use the yulOptimizer with versions 0.8.13 or 0.8.14 of Solidity.
This is part of the Set of Overriding Requirements for
[S] No assembly {}
.
assembly {}
Attack Vectors,
[M] Document Special Code Use,
[M] Compiler Bug SOL-2022-7,
[M] Compiler Bug SOL-2022-5 in `assembly {}`,
[M] Compiler Bug SOL-2021-3, and
[M] Compiler Bug SOL-2019-2 in `assembly {}`.
[M] Compiler Bug SOL-2021-3
Tested code that reads an `immutable` signed integer of a `type` shorter than
256 bits within an `assembly {}` instruction MUST NOT use a version of Solidity
between 0.6.5 and 0.8.8 (inclusive).
This is part of the Set of Overriding Requirements for
[S] No assembly {}
.
assembly {}
,
[M] Document Special Code Use,
[M] Compiler Bug SOL-2022-5 in `assembly {}`,
[M] Compiler Bug SOL-2022-4, and
[M] Compiler Bug SOL-2019-2 in `assembly {}`.
[M] Compiler Bug Check Constructor Payment
Tested code that allows payment to a constructor function that is
MUST NOT use a version of Solidity between 0.4.5 and 0.6.7 (inclusive).
This is an Overriding Requirement for
[S] Compiler Bug SOL-2020-5.
[M] Compiler Bug SOL-2020-2
Tested code that declares multiple functions with the same name MUST NOT
use a version of Solidity older than 0.5.17.
[M] Compiler Bug SOL-2019-2 in `assembly {}`
Tested code that uses the Optimizer with a version 0.5.5 nor 0.5.6 of Solitidy
MUST NOT contain inline `assembly {}` that uses the `byte` instruction with a second parameter
whose compile-time value evaluates to 31.
This is part of the Set of Overriding Requirements for
[S] No assembly {}
.
assembly {}
Attack Vectors,
[M] Document Special Code Use, and
[M] Compiler Bug SOL-2021-3.
[M] Compiler Bug Check Identity Calls
In Tested code that uses a version of Solidity older than 0.4.7,
calls to the Identity Contract MUST explicitly check the return value.
This is an Overriding Requirement for
[S] Compiler Bug SOL-2016-11.
[M] Validate ecrecover()
input
Tested code that uses the ecrecover()
pre-compile in a version of
Solidity older than 0.4.14 MUST ensure that input is well-formed before making the call.
This is an Overriding Requirement for
[S] Compiler Bug SOL-2017-3.
[M] Compiler Bug No Zero Ether Send
Tested code that uses a version of Solidity older than 0.4.0,
MUST NOT make Ether transfers that can send a value of zero.
This is an Overriding Requirement for
[S] Compiler Bug SOL-2016-6.
A bug fixed in Solidity version 0.4.0 meant that transactions that explicity send
zero Ether would automatically cause an exception, due to insufficient gas being passed on.
[Q] Pass Security Level [M]
To be eligible for EEA EthTrust certification at Security Level [Q],
Tested code MUST meet the requirements for .
[Q] Code Linting
Tested code
assert()
statements, and
[Q] Manage Gas Use Increases
Sufficient Gas MUST be available to work with data structures in the Tested Code
that grow over time, in accordance with descriptions provided for
[Q] Document Contract Logic.
[Q] Protect against Front-Running
Tested Code MUST NOT require information
in a form that can be used to enable a Front-Running attack.
[Q] Protect against MEV Attacks
Tested Code that is susceptible to MEV attacks MUST follow appropriate
design patterns to mitigate this risk.
MEV refers to the potential that a block producer can maliciously reorder or suppress transactions, or another participant in a blockchain can propose a transaction or take other action to gain a benefit that was not intended to be available to them.
This requirement entails a careful judgement by the auditor, of how the Tested Code is vulnerable to MEV attacks, and what mitigation strategies are appropriate. Some approaches are discussed further in . See also the Related Requirements [S] No Exact Balance Check, [M] Sources of Randomness, and [M] Don't misuse block data.
[Q] Process All Inputs
Tested Code MUST validate inputs, and function correctly whether the input
is as designed or malformed.
[Q] State Changes Trigger Events
Tested code MUST emit a contract event for all transactions that cause state changes.
[Q] No Private Data
Tested code MUST NOT store Private Data on the blockchain
Private data is used in this specification to refer to information that should not be generally available to the public. For example, an individual's home telephone number is generally private data, while a business' customer enquiries telephone number is generally not private data. Similarly, information identifying a person's account is normally private data, but there are circumstances where it is public data. In such cases, that public data can be recorded on-chain in conformance with this requirement.
PLEASE NOTE: In some cases regulation such as the [[GDPR]] imposes formal legal requirements on some private data. However, performing a test for this requirement results in an expert technical opinion on whether data that the auditor considers private is exposed. A statement about whether Tested Code meets this requirement does not represent any form of legal advice or opinion, attorney representation, or the like.
Security Level [Q] conformance requires a detailed description of how the Tested Code is intended to behave. Alongside detailed testing requirements to check that it does behave as described wth regard to specific known vulnerabililies, it is important that the claims made for it are accurate. This requirement underpins a Good Practice, that it fulfils claims made for it outside audit-specific documentation.
The combination of these requirements helps ensure there is no malicious code, such as malicious "back doors" or "time bombs" hidden in the Tested Code. Since there are legitimate use cases for code that behaves as e.g. a time bomb, or "phones home", this combination helps ensure that testing focuses on real problems. The requirements in this section extend the coverage required to meet the Security Level [M] requirement [**[M] Document Special Code Use**](#req-2-documented). As with that requirement, there are multiple requirements at this level that require the documentation mandated in this subsection.
[Q] Document Contract Logic
A specification of the business logic that the Tested code functionality is intended
to implement MUST be available to anyone who can call the Tested Code.
[Q] Document System Architecture
Documentation of the system architecture for the Tested code MUST be provided that
conveys the overrall system design, privileged roles, security assumptions and intended usage.
[Q] Annotate Code with NatSpec
All public interfaces contained in the Tested code MUST be annotated with inline
comments according to the [[NatSpec]] format that explain the intent behind each function, parameter,
event, and return variable, along with developer notes for safe usage.
[Q] Implement as Documented
The Tested code MUST behave as described in the documentation provided for
[Q] Document Contract Logic, and
[Q] Document System Architecture.
[Q] Implement Access Control
The Tested code MUST implement appropriate access control mechanisms,
based on the documentation provided for
[Q] Document Contract Logic.
[Q] Verify External Calls
Tested Code that contains external calls
This is part of a Set of Overriding Requirement for [S] Use Check-Effects-Interaction, and for [M] Protect External Calls.
[Q] Verify tx.origin
Usage
For Tested Code that uses tx.origin
, each instance
This is an Overriding Requirement for
[S] No tx.origin
.
[GP] Check For and Address New Security Bugs
Check [[!solidity-bugs-json]] and other sources for bugs announced after 15 July 2022
and address them.
[GP] Meet As Many Requirements As Possible
The Tested Code SHOULD meet as many requirements of this specification as possible
at Security Levels above the Security Level for which it is certified.
[GP] Use Latest Compiler
The Tested Code SHOULD use the latest available stable version
of the Solidity compiler.
[GP] Write clear, legible Solidity code
The Tested Code SHOULD be written for easy understanding.
[GP] Follow Accepted ERC Standards
The Tested Code SHOULD conform to finalized [[ERC]] standards when it is
reasonably capable of doing so for its use-case.
An ERC is a category of [[EIP]] (Ethereum Improvement Proposal) that defines application-level standards and conventions,
including smart contract standards such as token standards (EIP-20) and name registries (EIP-137).
[GP] Define a Software License The Tested Code SHOULD define a software license, which is commonly open-source for Solidity code deployed to public networks. A software license provides legal guidance on how contributors and users can interact with the code, including auditors and whitehats.
It is important to choose a [[software-license]] that best addresses the needs of the project, and clearly link to it throughout the Tested Code and documentation, e.g. using a prominent LICENSE file in the code repository, and referencing it from each source file.[GP] Disclose New Vulnerabilities Responsibly Security vulnerabilities that are not addressed by this specification SHOULD be brought to the attention of the Working Group and others through responsible disclosure as described in .
New security vulnerabilities are discovered from time to time. It helps the efforts to revise this specification to ensure the Working Group is aware of new vulnerabilities, or new knowledge regarding existing known vulnerabilities. The EEA has agreed to manage a specific email address for such notifications - and if that changes, to update this specification accordingly.[GP] Use Fuzzing As Part Of Testing Fuzzing is an automated software testing method that injects invalid, malformed, or unexpected inputs into a repeated activation of a contract to reveal defects and potential security vulnerabilities, and is therefore a good practice as part of any testing. Fuzzing could take days or even weeks to complete a proper assessment and therefore good practice is to be patient and not stop it prematurely. Corpus - A set of inputs for a fuzzing target. Good practice is to tweak the corpus to maximise code coverage whilst pruning unnecessary or duplicate inputs for efficiency. There are and will be many tools and input mutation methods when fuzzing, good practice is to build on and leverage community resources where possible. Always validate licensing restrictions. If any vulnerabilities are discovered in the contract, or even the compiler version itself, be sure to disclose them responsibly.
The following is a list of terms defined in this Specification.
chainid
.
- [M] Compiler Bug Storage Write Removal Bug on Conditional Early Termination,
- [M] Consistent Handling of Rounding.
- [M] Explicitly Disambiguate Evaluation Order.
- [S] Compiler Bug SOL-2022-6.
- [GP] Use Fuzzing As Part Of Testing