Comment on page
The following is a specific description of the types of vulnerabilities mentioned on the previous page.
During the process of auditing smart contracts, we have identified the following common types of vulnerabilities, which are described and illustrated below. However, our auditing work is not limited to these types.
Business Logic is the core of any smart contract application. Business logic vulnerabilities refer to issues related to the commercial logic in the implementation of a smart contract, resulting in the contract's behavior deviating from the expected outcome. These vulnerabilities do not involve technical implementation errors but rather pertain to the contract's objectives, rules, or logical consistency.
Access Control refers to the improper implementation or management of permissions and privilege mechanisms within a contract, resulting in vulnerabilities where unauthorized users can access, modify, or execute sensitive resources, systems, or information within the contract. Below are some common Access Control vulnerabilities in smart contracts:
- Inadequate access control: Contracts that are not properly configured for access control may allow unauthorized users to execute sensitive functions or operations within the contract, or prevent authorized users from accessing them, potentially leading to misuse or manipulation of the contract.
- Incorrect permission allocation: Granting inappropriate permissions or privileges to users allows them to access or modify resources or information that should not be accessed or modified.
- Authentication through tx.origin: tx.origin is a global variable in Solidity that returns the original initiator of a transaction, i.e., the address of an externally owned account (EOA). If a malicious contract initiates a call and uses tx.origin for authentication, it will not be able to verify intermediate contracts, potentially leading to the mistaken belief that the malicious contract has legitimate authorization. Therefore, using tx.origin for authentication poses a phishing risk to privileged users.
- Absence of proper access control lists: Failure to properly maintain or update access control lists can result in the inability to timely grant or revoke user access permissions.
Data Validation vulnerabilities refer to issues with verifying the integrity and correctness of the data that smart contracts rely on. If a smart contract fails to properly validate the data it depends on, it can lead to vulnerabilities and incorrect behavior. Here are some common smart contract Data Validation vulnerabilities:
- Insufficient input validation: Contracts that do not adequately validate input data or data ranges may allow users to submit incorrect or malicious data, which can affect the normal execution of the contract and compromise the accuracy and integrity of the data.
- Untrusted data sources: Contracts may rely on external data sources, such as oracles, to obtain data. If these data sources are untrusted or compromised, the contract may receive incorrect or tampered data, leading to incorrect decisions and behavior.
- Unchecked return values: When the return values of low-level calls are not checked, the code will continue to execute regardless of whether the call was successful or not, potentially resulting in unexpected behavior.
- Unchecked ecrecover zero address: ecrecover is a precompiled built-in function that can recover the address associated with a public key from a signature or return a zero address when there is an error. ecrecover is commonly used to verify if the signer is an authorized account, and it is common practice to set the address of the owner/administrator to the zero address when it is uninitialized or abandoned. This is the same as the return value when ecrecover verification fails, meaning that insecure contracts may allow malicious users to perform sensitive operations using invalid signatures.
- Insecure delegate call: Since delegatecall transfers all control to the called contract, delegatecall should never be used with untrusted contracts under any circumstances. It is important to note that completely different contracts can be deployed to the same address by using selfdestruct, create, and create2.
Numerics vulnerabilities refer to errors or inaccuracies that occur when handling and calculating numerical values. These vulnerabilities may be related to factors such as data types, arithmetic operations, and numerical precision, resulting in issues with the accuracy and precision of the calculated results. Here are some common Numerics vulnerabilities:
- Integer arithmetic errors caused by overflow and underflow: When performing integer arithmetic, if the calculated result exceeds the range that can be represented by the integer type, overflow or underflow occurs. This can lead to incorrect calculation results and may even cause contract execution issues or security vulnerabilities.
- Precision loss: Integer types are the primary numerical types in Solidity, and their calculation results are always rounded down. Therefore, using integers for division often leads to some degree of precision loss, which can result in varying degrees of impact.
- Failure to correctly handle token decimals: Different tokens may have different decimal places. Calculations that assume all tokens have the same decimal places or make incorrect estimations of the token's decimal places can lead to incorrect results.
One of the main dangers of external calls is that external contracts can take over control flow. In a reentrancy attack, a malicious contract calls back into the calling contract or other contracts before the first call completes. This can cause interactions between different calls to the function in unexpected ways, resulting in incorrect contract states or allowing attackers to execute unauthorized operations. There are different types of Reentrancy vulnerabilities:
- Single-Function Reentrancy: Malicious contracts exploit the reentrancy vulnerability of external function calls by repeatedly calling certain functions within the contract during the call. This can change the state and behavior of the contract. Since the contract state is not correctly updated before the external call, the attacker can enter the contract multiple times and perform malicious operations, leading to incorrect behavior or losses in the contract.
- Cross-Function Reentrancy: Attackers can call another function in the contract that shares state variables with the current function during the callback of a function call. This can tamper with the state or behavior of the contract, potentially leading to incorrect behavior or financial losses.
- Cross-Contract Reentrancy: Cross-contract reentrancy occurs when a state in one contract is used in another contract and is not fully updated before being called. This can result in unauthorized state changes, unexpected behavior, or financial losses.
- Read-Only Reentrancy: Read-only reentrancy vulnerabilities occur in view functions. Since view functions do not modify the contract state, they are often not protected by reentrancy locks. When a vulnerable contract's view function is called by the victim contract, the incomplete update of the contract state during the callback can result in incorrect data obtained by the victim contract through the view function. Depending on the returned value of the view function can lead to exceptional situations, such as incorrect collateral prices or reward calculations.
Cryptography vulnerabilities refer to issues that arise during the implementation of secure encryption algorithms and protocols to protect sensitive data, ensure confidentiality, integrity, and authentication. The use of cryptography in smart contracts is to ensure the security of transactions and the authenticity of identities. Here are common types of cryptography-related vulnerabilities in smart contracts:
- Lack of signature replay protection: If a contract fails to implement proper signature replay protection, attackers can obtain existing signatures and reuse them to execute transactions without the signer's authorization. This can lead to unauthorized state changes, unexpected behavior, or financial losses.
- Signature malleability: Attackers can exploit the malleability of signatures by making small modifications to the signature that do not affect its validity, resulting in a new signature. If a contract fails to handle signature malleability properly, it can lead to unauthorized state changes, unexpected behavior, or financial losses.
Denial of Service attacks aim to disrupt normal services, causing interruptions or suspensions that prevent legitimate users from accessing or using the services. Common types of Denial of Service vulnerabilities include:
- Infinite loops: Smart contracts can have vulnerabilities that lead to infinite loops. Attackers can trigger infinite loops by sending malicious transactions or invoking contract functions, consuming a significant amount of gas. When the gas usage of a transaction reaches the block's gas limit, the contract function becomes unavailable.
- Gas Griefing: Gas Griefing vulnerabilities typically involve two contracts: one contract that receives data and uses it for a sub-call, and a relay contract used to execute the transaction. Attackers can set the gas limit of the relay contract to provide just enough gas to execute the transaction itself but not enough for the sub-call to succeed. As a result, if the sub-call fails, the entire transaction is rolled back, resulting in a denial of service.
- Call blocking: Certain functions in a contract may be susceptible to abuse by attackers, such as passing malicious parameters or making malicious calls to trigger actions that cause other contract functions to roll back. This can block the invocation of other contract functions.
The proxy pattern allows smart contracts to upgrade their logic while retaining the address and state on the blockchain. Calls to the proxy contract modify the state of the proxy contract by executing the code in the logic contract. The proxy pattern is used for implementing upgradable contracts, but if not used correctly, it can introduce serious security issues to a project. Common vulnerabilities resulting from improper use of the proxy pattern include:
- Logic contract not initialized: In the UUPS(Upgradeable Unstructured Proxy System) proxy pattern, the contract state is initialized through the `initialize()` function, with input parameters provided by the caller through the proxy contract. If the `initialize()` function is called through the proxy contract instead of directly in the logic contract, the logic contract is not initialized. If the contract is not properly initialized, anyone can call the `initialize()` function, arbitrarily set state variables, and potentially take control of the logic contract. A compromised logic contract can be upgraded to a malicious contract, posing a threat to the assets held in the proxy contract.
- Storage collision: In a system with upgradable contracts, the proxy contract stores the values of the logic contract's state variables at relative positions declared by itself and uses pseudo-random storage slots to keep track of important data. If the proxy contract declares its own state variables and both the proxy contract and the logic contract attempt to use the same storage slot, a storage collision will occur, causing unexpected results during contract execution.
- Assigning values to state variables during construction or declaration: Assigning values to state variables during declaration or in the constructor only affects the values in the logic contract, while the proxy contract remains unaffected. Variables that are not properly initialized can disrupt the normal execution of the contract.
Inconsistency vulnerability refers to the situation where there is a discrepancy or difference between the actual implementation of a contract and the expected behavior described in the specification or documentation. These inconsistencies can lead to unexpected consequences, security vulnerabilities, or incorrect behavior of the contract. Here are some common examples of Inconsistency vulnerabilities:
- Implementation inconsistency with documentation: The actual code implementation is inconsistent with the specification or definition in the contract's documentation, which may result in incorrect contract execution or missing information, and can confuse users about the project.
- Implementation inconsistency with comments: The code implementation is inconsistent with the description in the related comments, which may cause the contract execution to deviate from expectations.
- Implementation inconsistency with error messages: The checks performed in the code are inconsistent with the error messages displayed when an error occurs, which may result in the contract execution not meeting expectations or affecting the troubleshooting of errors.
Front-running is a malicious behavior where a trader deliberately executes their own trades successfully before unconfirmed or unexecuted trades, in order to profit. This type of attack is commonly seen in decentralized financial applications, where malicious actors monitor transactions that have not yet been recorded on the blockchain, analyze the potential profits, and ensure that their own trades are executed before normal transactions, thereby profiting from them. This type of attack can lead to slippage issues and cause losses to normal users, while the malicious actors gain an unfair advantage.
The Sandwich attack is a specific type of Front-running attack. After monitoring an unconfirmed and profitable transaction, the attacker immediately initiates a new transaction and ensures that it is executed before the victim's transaction. Once the victim's transaction has been successfully executed and has had a certain impact on the market, the attacker initiates another transaction to take advantage of the market impact caused by the victim's transaction, thereby profiting from their initial trade.
Weak Randomness vulnerability refers to the use of insecure or unreliable methods or algorithms for generating random numbers, which poses a threat to the randomness of the contract. In smart contracts, random numbers are often used in various scenarios such as games, lotteries, and random allocation of resources. The Weak randomness vulnerability is typically caused by using deterministic chain properties to achieve pseudo-randomness, such as block.timestamp and blockhash. However, all available on-chain data is public and deterministic, allowing malicious users to infer the generated random numbers through smart contracts and exploit this information to gain unfair advantages.
Centralization vulnerability refers to the situation in which data, control, or authority is centralized in a contract or system, which may lead to potential single points of failure or vulnerabilities. The transparency and trustworthiness of the contract or system may be questioned. The Centralization vulnerability may bring the following risks and issues:
- Excessive authority: The ownership of the contract is concentrated in an individual or entity, which may lead to potential abuse of authority. If an attacker gains access to the private key of a highly privileged individual, it could have a significant impact on the contract.
- Unreasonable initial supply allocation: If the initial supply is overly concentrated in a few externally owned accounts (EOAs), it may result in abuse of power during allocation or affect the fairness of the contract.
- Security vulnerabilities: Attackers can exploit the weaknesses of centralization by attacking or manipulating centralized components or permissions to invade the contract or system.
Configuration vulnerability refers to the presence of vulnerabilities or insecure issues in the configuration settings of a contract, including custom options, environment variables, and external dependencies. This vulnerability can lead to unexpected behavior or malicious operations by attackers during the runtime of the contract. Here are some common examples of Configuration vulnerabilities in smart contracts:
- Insecure default configuration settings: The contract may use default configuration settings during deployment, which may pose security risks. Attackers can exploit these default settings to perform unauthorized operations or bypass the contract's security mechanisms.
- Incompatible compiler versions: Certain code or features may require specific versions or higher of the compiler to compile correctly. If an incompatible compiler version is used, it can result in compilation errors or the inability to generate executable files.
- Sensitive data leakage: The contract may contain sensitive information such as private keys, passwords, etc. If these sensitive data are stored in insecure locations or in plain text format, attackers may be able to access and manipulate this data for malicious operations.
- Improper management of external dependencies: The contract may rely on external contracts or services. If these dependencies are not properly managed, attackers can modify or exploit these dependencies to attack the contract.
Variable Shadowing is a common security vulnerability in smart contracts because smart contracts allow the use of variables with the same name across different functions or inherited contracts. This can lead to conflicts and variable hiding when using variables with the same name, resulting in execution behavior that differs from the developer's expectations. Here are some common examples of Variable Shadowing vulnerabilities:
- Overriding parent contract variables in child contracts: When a contract is inherited, if the child contract redefines a variable with the same name as the parent contract, the reference to that variable in the child contract will actually use the content of the variable in the child contract, rather than the parent contract.
- Declaration of the same variable in different scopes within the same contract: If a variable is declared in an outer scope and then redeclared within a function, it can cause confusion when used in practice.
Different compiler versions may have different features, optimizations, and security levels. If a vulnerable or mismatched compiler version is used, it can result in incorrect compilation results or make the contract more susceptible to attacks. Here are some common examples of Compiler vulnerabilities in smart contracts:
- Compiler vulnerabilities: Certain compiler versions may have known vulnerabilities or errors that attackers can exploit to perform unauthorized operations or modify the behavior of the contract.
- Incompatibility issues: Different versions of the compiler may have differences in language specifications or optimizations. Using an incompatible compiler version can lead to compilation failures or the generation of incorrect bytecode.
Logging is an important security practice used to record the operations, events, and errors of a contract. However, if the logging system has vulnerabilities, attackers may exploit these vulnerabilities to modify, delete, or forge log data, thereby disrupting the normal operation of the system or hiding their malicious activities. Here are some common issues related to Logging in smart contracts:
- Lack of logging for critical functions: Functions that involve important data updates or permission changes may lack proper logging implementation, which can compromise traceability and monitoring of information. This makes it difficult for users to track and monitor state updates.
- Missing parameters in log records: In the logging of important events, the absence of records for the parameters involved in the events can result in incomplete or difficult-to-trace data.
- Unclear or missing error message descriptions: Error messages reflect the problems encountered during the execution of the contract. If these messages are missing or poorly described, it can cause trouble for developers or users in understanding and using the contract.
Gas Optimization refers to reducing the gas consumption required for contract execution by organizing and writing code in a rational manner, using more efficient data structures and algorithms, among other techniques. Here are some common examples of optimizing gas consumption in smart contracts:
- Excessive looping: Using excessive loops in a contract, or performing complex operations within loops, can increase gas costs.
- Complex data structures and algorithms: Using complex data structures and algorithms can increase the execution time and gas costs of a contract.
- Initializing variables with default values: Initializing variables with default values increases the gas cost due to assignment operations.
- Reading state variables within loops: When using state variables within loops, reading data from storage for each iteration consumes more gas compared to reading from memory.
- Using the "memory" modifier for function parameters: When using the "memory" modifier, the function parameters are copied to memory before execution. For read-only parameters of external functions, the "calldata" modifier can be used to reduce overhead.
- Unnecessary storage read and write operations: Both storing and reading data incur gas costs, so minimizing unnecessary operations can optimize gas consumption.
- Excessive use of events and logs: Events and log records have associated costs, and excessive use can increase gas costs.
Code Quality refers to the issues related to the quality of code, including but not limited to readability, maintainability, and efficiency. Here are some common examples that can impact code quality:
- Readability issues: These problems involve the readability and comprehensibility of the code. For example, non-descriptive naming, lack of comments and documentation, excessively long lines of code, etc. These issues make the code difficult to understand and maintain, increasing the likelihood of errors.
- Redundancy: Unnecessary or redundant parts in contracts or code can introduce potential attack vectors, increase the cost of contract execution, make code maintenance more difficult, or reduce code readability. For example, redundant checks, unused variables or functions in contracts, commented-out code blocks, etc.
- Unhandled exceptions: Failure to properly handle exceptions in code can lead to potential vulnerabilities.