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..push()
. (Its URL **in the editor's draft** as linked from the " 🔗 " character) is
https://entethalliance.github.io/eta-registry/security-levels-spec.html#req-1-compiler-SOL-2022-5-push.
The statement of requirement is
Tested code thatFollowing the requirement is a brief explanation of the relevant vulnerability, and links to further discussion.
- copies
bytes
arrays fromcalldata
ormemory
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 Solidity compiler version older than 0.8.15.
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 a Security Level [S] requirement,
an Overriding Requirement will 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 the Tested Code.
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 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 need to 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 provide information sourced from on-chain or off-chain data. Oracles solve a range of problems, from providing random number generation to asset data, managing the operation of liquidity pools, and enabling access to weather, sports, or other special-interest information. Oracles are used heavily in DeFi and gaming, where asset data and randomization are central to protocol design. This specification contains requirements to check that smart contracts are sufficiently robust to deal appropriately with whatever information is returned, including the possibility of malformed data that can be deliberately crafted for oracle-specific attacks. While some aspects of Oracles are within the scope of this specification, it is still possible that an Oracle provides misinformation or even actively produces harmful disinformation.
The two key considerations are the risk of corrupted or manipulated data, and the risk of oracle failure. Vulnerabilities related to these considerations - excessive reliance on TWAP, and unsafe management of oracle failure - have occurred repeatedly leading to the loss of millions of dollars of value on various DeFi protocols. While many high-quality and trusted Oracles are available, it is possible to suffer an attack even with legitimate data. When calling on an Oracle, data received needs to be checked for staleness to avoid Front-running attacks. Even in non-DeFi scenarios, such as a source of randomness, it is often important to reset the data source for each transaction, to avoid arbitrage on the next transaction. A common strategy for pricing Oracles is to provide a time-weighted average price (known as TWAP). This provides some level of security against sudden spikes such as those created by a Flashloan attack, but at the cost of providing stale information. It is important to choose time windows carefully: when a time window is too wide, it won't reflect volatile asset prices, leaking opportunities to arbitrageurs. However the "instantaneous" price of an asset is often not a good data point: It is the most manipulable piece of Oracle data, and in any event it will almost always be stale by the time a transaction is executed. Oracles that collate a wide variety of source data, clean outliers from their data, and are well-regarded by the community, are more likely to be reliable. If an Oracle is off-chain, whether it reflects stale on-chain data or reliable and accurate data that is truly off-chain is an important consideration. Even an Oracle using a well-chosen TWAP can enable a liquidity pool or other DeFi structure to be manipulated, especially by taking advantage of flashloans and flashswaps to cheaply raise funds. If an asset targeted for manipulation has insufficient liquidity this can render it vulnerable to large price swings by an attacker holding only a relatively small amount of liquidity. The second important consideration when using Oracles is that of a graceful failure scenario. What happens if an Oracle no longer returns data, or suddenly returns an unlikely value? At least one protocol has suffered losses due to 'hanging' on a minimum value in the rare event of a price crash rather than truly dropping to zero, with traders who accumulated large amounts of a near zero-priced asset able to sell it back to the protocol. Hardcoding a minimum or maximum value can lead to problems reflecting reality.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 valuable use cases that such signature schemes allow, if not used carefully they can lead to vulnerabilities, which is why this specification seeks to constrain their use appropriately. In a similar vein, Hash Collisions could occur for hashed messages where the input used is malleable, allowing the same signature to be used for two distinct messages.
Other requirements in the document are related to exploits which take advantage of ambiguity in the input used to created the signed message. When a signed message does not include enough identifying information concerning where, when, and how many times it is intended to be used, the message signature could be used (or reused) in unintended functions, contracts, chains, or at unintended times.
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 protect against unexpected or adverse outcome such as 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.
Gas Siphoning is another abuse of the Gas mechanism that Ethereum uses to regulate the consumption of computing power, where attackers steal Gas from vulnerable contracts either to deny service or for their own gain (e.g. to mint Gas Tokens). Similar to Gas Griefing, checking for Gas Siphoning requires careful consideration of the goals and business logic that the Tested Code implements.
Gas Tokens use Gas when minted and free slightly less Gas when burned, provided the EVM refunds a sufficient quantity of Gas for clearing the state. Gas Tokens minted when Gas prices are low can be burned to subsidize Ethereum transactions when Gas prices are high. On Ethereum's main chain, Gas refunds were removed with the London hard fork that deployed [[EIP-3529]] in August 2021, effectively disabling Gas Tokens.
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 EVM 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 Ordering Attacks, or suppressing them.
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 mitigation strategies include those that protect against Ordering Attacks. The Ethereum Foundation maintains a set of information resources regarding MEV [[EF-MEV]].Based on transactions that are visible before they are added to a block, allowing a malicious participant to submit an alternative transaction, frustrating the aim of the original transaction.
An attacker places a victim's transaction undesirably between two other transactions.
pragma
statement.
This specification currently has no requirement for a specific pragma
,
but it is good practice to ensure that the pragma refers to a bounded set of Solidity compiler versions,
where it is known that those Solidity compiler versions produce identical bytecode
from the given source code.
There are some drawbacks to requiring Solidity Source code. The most obvious is that
some code that is not written in Solidity.
Different languages have different features and often support different coding styles.
Perhaps more important, it means that a deployed contract written
in Solidity cannot be tested directly without someone making the source code available.
Another important limitation introduced by reading source code is that it is subject to
Homoglyph Attacks, where characters that look the same but are different
such as Latin "p" and Cyrillic "р", can deceive people visually reading the source code,
to disguise malicious behaviour. There are related attacks that use features such as
Unicode Direction Control Characters or take advantage of inconsistent normalisation
of combining characters to achieve the same type of deceptions.
msg.sender
or other variables
in constructors and initializers need careful consideration.
This is discussed further in requirements.
Several libraries and tools exist specifically for safe proxy usage and safe contract deployment.
From command-line tools to libraries to sophisticated UI-based deployment tools, many solutions exist to
prevent unsafe proxy deployments and upgrades.
Using access control for a given contract's initializer, and limiting the number of times an initializer
can be called on or after deployment, can enhance safety and transparency for the protocol itself and its users.
Furthermore, a function that disables the ability to re-initialize an Execution Contract can prevent any
future initializer calls after deployment, preventing later attacks or accidents.
Although this specification does not require that Tested Code has been deployed, some requirements
are more easily tested when code has been deployed to a blockchain,
or possibly in some cases can only be thoroughly tested "in situ".
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 , 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 researchers 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 instead 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 each Security Level [S] requirement it does not meet directly.[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 can allow external calls to code that is not yet known or can be altered, 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.
It is better to 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
unless it meets the Overriding Requirement
[M] Verify Exact Balance Checks.
[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 selfdestruct()
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, 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()
, and send()
)
MUST check the returned value from each usage to determine whether the call failed,
unless it meets the Overriding Requirement
[M] Handle External Call Returns.
call()
,
- delegatecall()
,
- staticcall()
, and
- `send()`.
Calls using these functions behave differently. Instead of reverting on failure
they return a boolean indicating whether the call completed successfully.
Not testing explicitly for the return value could lead to unexpected behavior in the caller contract.
Relying on these calls reverting on failure will lead to unexpected behaviour when they are not successful.
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, and
[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 Set of Overriding Requirements:
Implementing the Recommended Good Practice [GP] Use Latest Compiler means that Tested Code passes the requirement in this subsection.
[S] No Overflow/Underflow
Tested code MUST NOT use a Solidity compiler version older than 0.8.0
unless it meets the Set of Overriding Requirements
Implementing the Recommended Good Practice [GP] Use Latest Compiler means that Tested Code passes all requirements in this subsection.
Some compiler-related bugs are in the as Security Level [M] requirements, either because they are Overriding Requirements for requirements in this subsection, or because they are part of a Set of Overriding Requirements for Security Level [S] requirements that already ensure that the bug cannot be triggered. Some bugs were introduced in known Solidity compiler versions, while others are known or assumed to have existed in all Solidity compiler versions until they were fixed.
[S] Compiler Bug SOL-2023-3
Tested code that includes Yul code and uses the `verbatim` instruction twice, in each case surrounded by identical code,
MUST disable the Block Deduplicator when using a Solidity compiler version between 0.8.5 and 0.8.22 (inclusive).
[S] Compiler Bug SOL-2022-6
Tested code that ABI-encodes a tuple (including a `struct`, `return` value, or a parameter list)
that includes a dynamic component with the ABIEncoderV2, and whose last element is a
calldata
static array of base type `uint` or `bytes32`,
MUST NOT use a Solidity compiler version between 0.5.8 and 0.8.15 (inclusive).
[S] Compiler Bug SOL-2022-5 with .push()
Tested code that
bytes
arrays from calldata
or memory
whose size is not a multiple of 32 bytes, and.push()
instruction that writes to the resulting array,MUST NOT use a Solidity compiler version older than 0.8.15.
[S] Compiler Bug SOL-2022-3
Tested code that
MUST NOT use a Solidity compiler version between 0.6.9 and 0.8.12 (inclusive).
[S] Compiler Bug SOL-2022-2
Tested code with a nested array that
abi.encode()
, orMUST NOT use a Solidity compiler version between 0.6.9 and 0.8.12 (inclusive).
[S] Compiler Bug SOL-2022-1
Tested code that
and passes such literals to abi.encodeCall()
as the first parameter,
MUST NOT use Solidity compiler version 0.8.11 nor 0.8.12.
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`
Solidity compiler versions 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 MUST NOT use Solidity compiler version 0.8.8.
[S] Compiler Bug SOL-2021-2
Tested code that uses abi.decode()
on byte arrays as `memory`
MUST NOT use the ABIEncoderV2 with a Solidity compiler version 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 Solidity compiler version 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 use a Solidity compiler version
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 use a Solidity compiler version older than 0.7.3.
[S] Compiler Bug SOL-2020-9
Tested code that defines Free Functions MUST NOT use Solidity compiler version 0.7.1.
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#functionsSolidity compiler version 0.7.1 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 Solidity compiler version 0.6.9.
calldata
parameters passed to
internal library functions with `using for` as if they were calling to
external library functions, leading to stack corruption and an incorrect jump destination.
See also a [Github issue with a code example](https://github.com/ethereum/solidity/issues/9172).
[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 Solidity compiler version 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 Solidity compiler version 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 Solidity compiler version 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 Solidity compiler version older than 0.6.6.
[S] Compiler Bug SOL-2020-3
Tested code that declares arrays of size larger than 2^256-1 MUST NOT use a Solidity compiler version 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 Solidity compiler version 0.6.0
nor a Solidity compiler version between 0.5.8 and 0.5.15 (inclusive).
[S] Use a Modern Compiler
Tested code MUST NOT use a Solidity compiler version older than 0.6.0,
unless it meets all the following requirements from the
EEA EthTrust Security Levels Specification Version 1,
as Overriding Requirements:
[S] No Ancient Compilers
Tested code MUST NOT use a Solidity compiler version 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] Verify Exact Balance Checks
Tested code that checks whether the balance of an account is exactly equal to
(i.e. ==
) a specified amount or the value of a variable.
MUST protect itself against transfers affecting the balance tested.
This is an Overriding Requirement for
[S] No Exact Balance Check.
[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 together at this Security Level. If a contract calls a well-known external contract that is not audited as part of the Tested Code, it is possible to certify conformance to this requirement through the Overriding Requirements, which allow the certifier to claim on their own judgement that the contracts called provide appropriate security. The extended requirements around documentation of the Tested Code that apply when claiming conformance through implementation of the Overriding Requirements in this case reflect the potential for very high risk if the external contracts are simply assumed by a reviewer to be secure because they have been widely used. Unless the Tested Code deploys contracts itself, and retrieves their address accurately for calling, it is necessary to check that the contracts are really deployed at the addresses assumed in the Tested Code. 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 [S] Use Check-Effects-Interaction.
[M] Avoid Read-only Re-entrancy Attacks
Tested Code that makes external calls MUST protect itself against Read-only Re-entrancy Attacks.
[M] Handle External Call Returns
Tested Code that makes external calls MUST reasonably handle possible errors.
This is an Overriding Requirement for
[S] Check External Calls Return.
[M] Document Special Code Use
Tested Code MUST document the need for each instance of:
CREATE2
,assembly {}
,selfdestruct()
or its deprecated alias suicide()
,delegatecall()
,block.number
or block.timestamp
, orand 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
if using Solidity compiler version 0.5.5 or 0.5.6,
[M]
Compiler Bug SOL-2019-2 in `assembly {}` in
[[EthTrust-sl-v1]].
[M] Ensure Proper Rounding of Computations Affecting Value
Tested code MUST identify and protect against exploiting rounding errors:
[M] Protect Self-destruction
Tested code that contains the selfdestruct()
or suicide()
instructions MUST
unless it meets the Overriding Requirement [Q] Enforce Least Privilege.
This is an Overriding Requirement for
[S] No selfdestruct()
.
[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
This is part of a Set of Overriding Requirements for
[S] No CREATE2
.
CREATE2
opcode's ability to interact with addresses
whose code does not yet exist on-chain makes it important 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 that 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] 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] 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.
Some smart contracts process messages that were signed off-chain to increase flexibility, while maintaining authenticity. Smart contracts performing their own signature verification need to verify such messages' authenticity.
Using `ecrecover()` for signature verification, it is important to validate the address returned against the expected outcome. In particular, a return value of `address(0)` represents a failure to provide a valid signature. See also SWC-122 [[swcregistry]]. For code that does use `ecrecover()` and a Solidity compiler version older than 0.4.14, see the Related Requirement [M] Use a Modern Compiler, specifically [M] Validate `ecrecover()` Input in [[EthTrust-sl-v1]][M] No Improper Usage of Signatures for Replay Attack Protection
Tested Code using signatures to prevent replay attacks MUST ensure that signatures cannot be reused:
unless it meets the Overriding Requirement [Q] Intended Replay. Additionally, Tested Code MUST verify that multiple signatures cannot be created for the same message, as is the case with Malleable Signatures.
Implementing the Recommended Good Practice [GP] Use Latest Compiler means that Tested Code passes all requirements in this subsection.
[M] Solidity Compiler Bug 2023-1
Tested code that contains a compound expression with side effects that uses `.selector`
MUST use the viaIR option with Solidity compiler versions between 0.6.2 and 0.8.20 inclusive.
[M] Compiler Bug SOL-2022-7
Tested code that has storage writes followed by conditional early terminations
from inline assembly functions containing return()
or stop()
instructions
MUST NOT use a Solidity compiler version between 0.8.13 and 0.8.16 inclusive.
This is part of the Set of Overriding Requirements for
[S] No assembly {}
.
[M] Compiler Bug SOL-2022-5 in `assembly {}`
Tested code that
bytes
arrays from calldata or memory whose size is not a multiple of 32 bytes, andMUST NOT use a Solidity compiler version 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, and
[M] Compiler Bug SOL-2021-3.
[M] Compiler Bug SOL-2022-4
Tested code that has at least two `assembly {}` instructions, such that
MUST NOT use the yulOptimizer with Solidity compiler versions 0.8.13 or 0.8.14.
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 {}`, and
[M] Compiler Bug SOL-2021-3.
[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 Solidity compiler version
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 {}`, and
[M] Compiler Bug SOL-2022-4.
[M] Compiler Bug Check Constructor Payment
Tested code that allows payment to a constructor function that is
MUST NOT use a Solidity compiler version between 0.4.5 and 0.6.7 (inclusive).
This is an Overriding Requirement for
[S] Compiler Bug SOL-2020-5.
[M] Use a Modern Compiler
Tested code MUST NOT use a Solidity compiler version older than 0.6.0,
unless it meets all the following requirements from the
EEA EthTrust Security Levels Specification Version 1,
as Overriding Requirements:
[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 that fail in normal operation, andassert()
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 Gas Usage
Tested Code MUST protect against malicious actors stealing or wasting gas.
[Q] Protect against Oracle Failure
Tested Code MUST protect itself against malfunctions in Oracles it relies on.
Some Oracles are known to be vulnerable to manipulation, for example because they derive the information they provide from information vulnerable to Read-only Re-entrancy Attacks, or manipulation of prices through the use of flashloans to enable an MEV attack, among other well-known attacks.
In addition, as networked software Oracles can potentially suffer problems ranging from latency issues to outright failure, or being discontinued. It is important to check the mechanism used by an Oracle to generate the information it provides, and the potential exposure of Tested Code that relies on that Oracle to the effects of it failing, or of malicious actors manipulating its inputs or code to enable attacks. See also the Related Requirements [Q] Protect against Ordering Attacks, and [Q] Protect against MEV Attacks.
[Q] Protect against Ordering Attacks
Tested Code MUST manage information
in such a way that it protects against Ordering Attacks.
[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 . Many attack types need to be considered, including Ordering Attacks. See also the Related Requirements [S] No Exact Balance Check, [M] Sources of Randomness, [M] Don't Misuse Block Data, and [Q] Protect against Oracle Failure, and [Q] Protect against Ordering Attacks.
[Q] Protect Against Governance Takeovers
Tested Code which includes a governance system MUST protect against one external
entity taking control via exploit of the governance design.
[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 is not intended to 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.
[Q] Intended Replay
If a signature within the Tested Code can be reused, the replay instance MUST be intended, documented,
and safe for re-use.
This is an Overriding Requirement for [M] No Improper Usage of Signatures for Replay Attack Protection.
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 helps ensure that the Tested Code 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 a "time bomb", "phones home", or the like, 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] Enforce Least Privilege
Tested code that enables privileged access MUST implement appropriate access control mechanisms that provide the least privilege necessary for those interactions,
based on the documentation provided for
[Q] Document Contract Logic.
This is an Overriding Requirement for
[M] Protect Self-destruction.
msg.sender
,
as that may leave a simple factory deployment contract as the insufficent new admininstrator of your protocol.
It is particularly important that appropriate access control applies to payments,
as noted in [SWC-105](https://swcregistry.io/docs/SWC-105),
but other actions such as overwriting data as described in
[SWC-124](https://swcregistry.io/docs/SWC-126), or changing specific access controls,
also need to be appropriately protected [[swcregistry]].
This requirement matches [[CWE-284]] Improper Access Control.
See also "[Access Restriction](https://fravoll.github.io/solidity-patterns/access_restriction.html)" in [[solidity-patterns]].
[Q] Use Revocable and Transferable Access Control Permissions
If the Tested code makes uses of Access Control for privileged actions, it MUST implement a mechanism
to revoke and transfer those permissions.
Privileged Accounts can perform administrative tasks on the Set of Contracts. If those accounts are compromised or responsibility to perform those tasks is assigned to different people, it is important to have a mechanism to revoke and transfer those permissions.
[Q] No Single Admin EOA for Privileged Actions
If the Tested code makes uses of Access Control for privileged actions, it MUST ensure that all critical administrative tasks require multiple signatures to be executed,
unless there is a multisg admin that has greater privileges and can revoke permissions in case of a compromised or rogue EOA and reverse any adverse action the EOA has taken.
[Q] Verify External Calls
Tested Code that contains external calls
This is part of a Set of Overriding Requirements 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 1 November 2023
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 Solidity compiler version.
[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.
[GP] Define a Software License
The Tested Code SHOULD define a software license
[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
.
[GP] Use Fuzzing
Fuzzing SHOULD be used to probe Tested Code for errors.
Fuzzing is an automated software testing method that repeatedly activates a contract, using a variety of invalid, malformed, or unexpected inputs, to reveal defects and potential security vulnerabilities.
Effective Fuzzing can take days or even weeks: it is better to be patient than to stop it prematurely. Fuzzing relies on a Corpus - A set of inputs for a fuzzing target. It is important to maintain the Corpus to maximise code coverage, and helpful to prune unnecessary or duplicate inputs for efficiency. Many tools and input mutation methods can help to build the Corpus for Fuzzing. Good practice is to build on and leverage community resources where possible, always checking licensing restrictions. Another important part of Fuzzing is the set of specification rules that is checked throughout the processes. While Corpus is the set of inputs for Fuzzing targets, the specification rules are business logic checks created specifically and evaluated for each Fuzzing input. This additional set of rules important as it gets triggered if Fuzzing finds an edge case. That way the process doesn't just rely on the checks and reverts already within the contracts and the compiler. Fuzzing rules and properties can be complex and depend on specific contracts, functions, variables, their values before and/or after execution, and potentially many other things. If any vulnerabilities are discovered in the Solidity compiler version by Fuzzing please disclose them responsibly.
[GP] Use Formal Verification
The Tested Code SHOULD undergo formal verification.
[GP] Select an Appropriate Threshold for Multisig Wallets
Multisignature requirements for privileged actions SHOULD have a sufficient number of signers, and NOT require "1 of N" nor all signatures.
[GP] Use TimeLock Delays for Sensitive Operations
Sensitive operations that affect all or a majority of users SHOULD use [[TimeLock]] delays.
The following is a list of terms defined in this Specification.
storage
Explicitlyassembly {}
ecrecover()
input