Secureum Book
  • 🛡️Secureum Bootcamp
    • 🛡️Secureum Bootcamp
    • 🙌Participate
    • 📜History
  • 📚LEARN
    • Introduction
      • 🔷1. Ethereum Basics
        • 1.1 Ethereum: Concept, Infrastructure & Purpose
        • 1.2 Properties of the Ethereum Infrastructure
        • 1.3 Ethereum vs. Bitcoin
        • 1.4 Ethereum Core Components
        • 1.5 Gas Metering: Solving the Halting Problem
        • 1.6 web2 vs. web3: The Paradigm Shift
        • 1.7 Decentralization
        • 1.8 Cryptography, Digital Signature & Keys
        • 1.9 Ethereum State & Account Types
        • 1.10 Transactions: Properties & Components
        • 1.11 Contract Creation
        • 1.12 Transactions, Messages & Blockchain
        • 1.13 EVM (Ethereum Virtual Machine) in Depth
        • 1.14 Transaction Reverts & Data
        • 1.15 Block Explorer
        • 1.16 Mainnet & Testnets
        • 1.17 ERCs & EIPs
        • 1.18 Legal Aspects in web3: Pseudonymity & DAOs
        • 1.19 Security in web3
        • 1.20 web2 Timescales vs. web3 Timescales
        • 1.21 Test-in-Prod. SSLDC vs. Audits
        • Summary: 101 Keypoints
      • 🌀2. Solidity
        • 2.1 Solidity: Influence, Features & Layout
        • 2.2 SPDX & Pragmas
        • 2.3 Imports
        • 2.4 Comments & NatSpec
        • 2.5 Smart Contracts
        • 2.6 State Variables: Definition, Visibility & Mutability
        • 2.7 Data Location
        • 2.8 Functions
        • 2.9 Events
        • 2.10 Solidity Typing
        • 2.11 Solidity Variables
        • 2.12 Address Type
        • 2.13 Conversions
        • 2.14 Keywords & Shorthand Operators
        • 2.15 Solidity Units
        • 2.16 Block & Transaction Properties
        • 2.17 ABI Encoding & Decoding
        • 2.18 Error Handling
        • 2.19 Mathematical & Cryptographic Functions
        • 2.20 Control Structures
        • 2.21 Style & Conventions
        • 2.22 Inheritance
        • 2.23 EVM Storage
        • 2.24 EVM Memory
        • 2.25 Inline Assembly
        • 2.26 Solidity Version Changes
        • 2.27 Security Checks
        • 2.28 OpenZeppelin Libraries
        • 2.29 DAppSys Libraries
        • 2.30 Important Protocols
        • Summary: 201 Keypoints
      • 🔏3. Security Pitfalls & Best Practices
        • 3.1 Solidity Versions
        • 3.2 Access Control
        • 3.3 Modifiers
        • 3.4 Constructor
        • 3.5 Delegatecall
        • 3.6 Reentrancy
        • 3.7 Private Data
        • 3.8 PRNG & Time
        • 3.9 Math & Logic
        • 3.10 Transaction Order Dependence
        • 3.11 ecrecover
        • 3.12 Unexpected Returns
        • 3.13 Ether Accounting
        • 3.14 Transaction Checks
        • 3.15 Delete Mappings
        • 3.16 State Modification
        • 3.17 Shadowing & Pre-declaration
        • 3.18 Gas & Costs
        • 3.19 Events
        • 3.20 Unary Expressions
        • 3.21 Addresses
        • 3.22 Assertions
        • 3.23 Keywords
        • 3.24 Visibility
        • 3.25 Inheritance
        • 3.26 Reference Parameters
        • 3.27 Arbitrary Jumps
        • 3.28 Hash Collisions & Byte Level Issues
        • 3.29 Unicode RTLO
        • 3.30 Variables
        • 3.31 Pointers
        • 3.32 Out-of-range Enum
        • 3.33 Dead Code & Redundant Statements
        • 3.34 Compiler Bugs
        • 3.35 Proxy Pitfalls
        • 3.36 Token Pitfalls
        • 3.37 Special Token Pitfalls
        • 3.38 Guarded Launch Pitfalls
        • 3.39 System Pitfalls
        • 3.40 Access Control Pitfalls
        • 3.41 Testing, Unused & Redundand Code
        • 3.42 Handling Ether
        • 3.43 Application Logic Pitfalls
        • 3.44 Saltzer & Schroeder's Design Principles
        • Summary: 201 Keypoints
      • 🗜️4. Audit Techniques & Tools
        • 4.1 Audit
        • 4.2 Analysis Techniques
        • 4.3 Specification, Documentation & Testing
        • 4.4 False Positives & Negatives
        • 4.5 Security Tools
        • 4.6 Audit Process
        • Summary: 101 Keypoints
      • ☝️5. Audit Findings
        • 5.1 Criticals
        • 5.2 Highs
        • 5.3 Mediums
        • 5.4 Lows
        • 5.5 Informationals
        • Summary: 201 Keypoints
  • 🌱CARE
    • CARE
      • CARE Reports
  • 🚩CTFs
    • A-MAZE-X CTFs
      • Secureum A-MAZE-X
      • Secureum A-MAZE-X Stanford
      • Secureum A-MAZE-X Maison de la Chimie Paris
Powered by GitBook
On this page
  • Actors and Privileged Roles
  • Actors
  • Privileged Roles
  • Critical Parameters
  • Explicitness vs. Implicitness
  • Configuration
  • Initialization
  • Cleanup
  • Data Pitfalls
  • Data Validation
  • Numerical Issues
  • Accounting Issues
  • Audit Logging
  • Cryptographic Issues
  • Error Reporting
  • DoS Attacks
  • Timing
  • Freshness
  • Ordering
  • Undefined Behavior
  • Trust
  • Interactions
  • Dependencies
  • Clarity
  • Privacy
  • Cloning
  • Gas
  • Constants
  • Scarcity
  • Incentives
  • Clarity
  • Privacy
  • Cloning Contracts
  1. LEARN
  2. Introduction
  3. 3. Security Pitfalls & Best Practices

3.43 Application Logic Pitfalls

The following concepts we're about to discuss are generalizations and higher level concepts related to application logic level issues that can't be specifically codified in tools or generalized because they differ across applications. These are perhaps much harder to reason and detect because it requires deep understanding of the application logic and hence there's mostly manual effort in security reviews. Such business logic which is application specific should have been translated from requirements to the specification, then implementation with all of it validated and documented accurately especially the security relevant aspects.

Without that security reviewers have to infer assumptions constraints program and variants trust and threat models which is not very effective or efficient. Application logic related vulnerabilities are perhaps the hardest to detect and have resulted in serious exploits. This is therefore of utmost importance to security.

Actors and Privileged Roles

Actors

The aspirational goal in web3 is for it to be a completely permissionless system where, ideally, there are no centralized trusted actors, such as admins, responsible for any aspect of smart contracts related to either development or management.

Remember that web3 aspires to be a zero trust system where no one needs to be trusted to use and not abuse the system, because everything is and should be verified. However, in guarded launch scenarios, the goal is to start with trusted actors/assets/actions and then progressively decentralize towards automated governance by the community.

For the trusted phase, all the trusted actors (their roles and capabilities) should be clearly specified in the trust and threat models, implemented accordingly and documented for user information and any evaluation. This is a critical consideration in web3's Byzantine Threat Model.

Privileged Roles

Let's now talk about privileged roles. Trusted actors who have privileged roles in the context of the smart contact application with capabilities to deploy contracts modify critical parameters, pause and pause the system, trigger emergency shutdown, withdraw, transfer, drain funds and allow deny other actors, should ideally be addresses controlled by multiple independent and mutually distrusting entities.

They should not be controlled by private keys of externally owned accounts, but we are multiSig with the high pressure, say 5-7 or 9-11 depending on the criticality of the application, the value address, and eventually they should be governed by a community or a DAO (decentralized autonomous organization) of token holders. This is because an EOA is a single point of failure, if its key is compromised or the order is malicious multiSig on the other hand brings in the security design principle of privileged separation, which is tolerant to a few of the holders being malicious or compromised.

When such privileged roles within smart contracts are being changed it is recommended not to use a single step change because it is error-prone. For example in a single step change, if the current admin accidentally changes the new admin to the zero address, or an incorrect address that's where the private key is not available, the system is left without an operational and the contract will have to be redeployed which is not easy or even entirely feasible in some scenarios.

Instead one should follow a two-step approach that we have discussed earlier, the current privileged role proposes a new address for the change and in the second step the newly proposed address, then claims the privileged role in a separate transaction. This two-step change mitigates risk by allowing accidental proposals to be corrected instead of leaving the system unoperational with no or malicious privileged.

Critical Parameters

When critical parameters of systems need to be changed it is recommended to enforce the changes after a time delay that is coupled and locked with that logic. This is to allow systems users to be aware of such critical changes and give them an opportunity to exit from that system, if they do not like the upcoming changes, or adjust their engagement in any other way with the system accordingly.

For example reducing rewards increasing fees or changing trust models in a system might not be acceptable to some users who may wish to withdraw their funds before the change and exit. Such a time locked execution of delayed change enforcement needs to be combined with event emission to notify users of upcoming changes via off-chain interfaces or monitoring tools. So the best practice is a time delay change for critical parameters that is broadcasted using events to users monitoring via off-chain interfaces the goal is to surprise less be more transparent and fair.

Explicitness vs. Implicitness

As a general principle everything in security is about being explicit. Instead of being implicit (implicit assumptions, implicit trust or threat models, implicit acceptance of assets, actors, actions) which leads to security vulnerabilities whereas, if they are explicitly specified implemented and documented they can be reasoned about and evaluated from a security perspective.

Even with the Solidity language it has progressively adopted explicit declarations of intent over the versions such as with function visibility and variable storage. So it's recommended to do the same at the application level where all requirements should be explicitly specified, so they're accurately implemented and lend themselves to validation. Implicit requirements specification and implementation assumptions should be explicitly documented and validated for correctness. Any latent implicit requirements and assumptions should be flagged as being dangerous.

Configuration

Security issues arise not only from implementation errors, but also from this configuration of system components, such as contracts, parameters, addresses and permissions all of which may lead to security issues. Such configuration aspects should be documented and validated test configurations should be clearly marked as such and separated appropriately from production configurations.

This is critical because testing is typically done with lower thresholds of different values to allow for faster or easier testing, they may also use more acceptable trust models or lower levels of thread than what is encountered in a production setting. So the best practice is to check configuration settings and make sure that they are correct relevant and validated for a production deployment.

Initialization

Lack of initialization. Initializing with incorrect values or allowing untrusted actors to initialize system parameters may lead to security issues this is especially true for critical parameters, addresses, permissions and rules within the system because the default or incorrect values may be used to exploit the system. Either technically or economically. The best practice therefore to avoid security pitfalls from initialization is to check that it is done and done correctly using the right values and done, so by only the authorized users.

Cleanup

Missing the cleaning up of old state or cleaning up incorrectly or insufficiently will lead to reuse of stale state which may lead to security issues. Cleaning could be in the context of using Solidity's delayed primitive or even simply re-initializing variables to default values in the context of the application's logic.

For example this is applicable to contract state maintained in state variables within storage or even local variables within contact functions, where old scale values may lead to incorrect reads or rights in the context of the contract's logic. Cleaning up storage state using delete primitive provides Gas refunds with an EVM some of which has changed in recent upgrades, London upgrade for example reduced Gas refunds of s stores. Nevertheless, there are benefits besides security to this aspect of cleaning up.

Data Pitfalls

At a very high and perhaps abstract level data, processing issues may lead to security issues in the application logic's context this could arise from several reasons such as while processing critical data or from processing of painted input data.

Processing could be missing or incorrectly implemented this could either resolve from a faulty specification or implementation without being caught during validation therefore all aspects of data processing should be reviewed for potential security impact

Data Validation

A specific aspect of data processing that we just discussed is data validation where contract functions check, if they receive data from external users or other contracts is valid, based on aspects of variable types, lower high thresholds or any other application logic specific context.

Validation issues very frequently lead to security issues. Missing validation of data or incorrectly insufficiently validating data especially tainted data from untrusted users will cause untrustworthy system behavior which may lead to security issues. Sanity and threshold checks are therefore critical aspects of data validation.

Numerical Issues

Another specific type of data processing is numerical processing, where the logic operates on numerical values incorrect numerical computation will almost always cause unexpected behavior some of which may lead to serious security issues. If not accounting miscalculations these may be related to overflow/underflow, precision handling, type casting, parameter return values, decimals, ordering of operations with multiplication/division and loop indices among other things.

The recommended best practice is to adopt widely used libraries for special mathematical support such as Fixed-point or floating point numbers and combine this with extensive testing using fuzzing and other tools meant to specifically test constraints and invariants for numerical issues.

Accounting Issues

A specific type of data numerical processing is that related to accounting incorrect or insufficient tracking or accounting of business logic related aspects. Such as states phases permissions, rules, deposits, withdrawals of funds, mints. births, transfers of tokens or rewards penalties, fees within DeFi applications all these may lead to serious security issues. We have seen numerous vulnerabilities specifically related to this aspect.

Therefore accounting aspects related to application logic states or transitions or numerical aspects as outlined earlier should be carefully reviewed to make sure they are correct and complete.

Audit Logging

Recording or accessing snapshots or logs of important events within a system is known as audit logging. The recorded events are called audit logs. Note that this auditing from a logging perspective is different from the concept of external reviews, which is also called auditing. Auditing and logging are important for monitoring the security of an application.

In the context of smart contracts this applies to event emissions, the ability to query values of public state variables, exposed getter functions, and recording appropriate error strengths from requires, asserts and rewards. Incorrect or insufficient implementation of these aspects will impact off-chain monitoring and instant response capabilities which may lead to security issues. Correct and sufficient audit and logging is therefore something that also needs to be paid attention to for reasons of monitoring detecting and recovery aspects of security.

Cryptographic Issues

Incorrect or insufficient cryptography, especially related to on-chain signature verification, or off-chain key management, will impact access control and may lead to security issues. So, aspects of keys, accounts, hashes signatures, and randomness need to be paid attention to along with the fundamental concepts of ECDSA signatures and keccak-256 hashes.

There are also other deeper and dual cryptographic aspects one will encounter in Ethereum applications or protocol upgrades with abbreviations such as BLS, RANDAO, and VRF. Also zero knowledge (ZK) aspects. At a high level, cryptography is fundamental and critical to security and even a tiny mistake here can be disastrous surely leading to security vulnerabilities.

Error Reporting

Incorrect or insufficient detecting reporting and handling of error conditions will cause exceptional behavior to go unnoticed which may lead to security issues. At a high level security exploits almost always focus on exceptional behavior that is normally not encountered or validated or noticed.

Such exceptional behavior is what is anticipated caught and reported by error conditions. Any deviations from the specification are errors that should be detected reported and handled appropriately by the implementation.

DoS Attacks

Denial of service (DoS) Attacks are also a security concern. Traditionally security has been considered as a triad referred to as the CIA triad which stands for confidentiality, integrity and availability. DoS affects availability, and in this case that of the smart contract application. Preventing other users from successfully accessing system services by either modifying system parameters or shared state causes denial of service issues which affects the availability of the system.

The effects of this could cause users to have their funds locked reduce profits prevent from having their transactions included and therefore interactions with the contracts denied. Attackers may cause DoS without any apparent or immediate economic benefits to themselves and do so by spending Ether on the Gas or any other tokens required for such duress causing interactions, which is typically referred to as griefing. So the best practices here are to recognize and minimize any such attributes in the smart contracts or application logic that could enable dos.

Timing

Timing issues can have a security impact. Incorrect assumptions on timing of user actions which can't be controlled. Triggering of system state transitions or dependencies on blockchain state blocks transactions may all lead to security issues depending on the application logic context. Therefore any timing attributes or logic within smart contact applications should be analyzed to check for such issues.

Freshness

Freshness of an object is a concept related with timing and indicates if it is the latest one in some relevant timeline or, if it is stale indicating that there is an updated value or version in that corresponding timeline. Using stale values and not the most recent values leads to freshness issues that could manifest into security issues.

Concrete examples are the use of nonsense in transactions to prevent replay attacks by repeating older transactions or the asset prices obtained from Oracles which, if stale can cause significant accounting issues leading to price manipulations and resulting vulnerabilities. Therefore increased assumptions about the status of or data from system actors being fresh because of lack of updation or availability may lead to security issues, if and when such factors have been updated and result resultant stale values being used instantly.

Ordering

Similar to timing issues incorrect assumptions on ordering of user actions or system state transitions may also lead to security issues. For example a user may accidentally or maliciously call a finalization function or other contract functions even before the initialization function has been called, if the system allows this to happen.

Attackers can front run or back run user interactions to force assumptions or ordering to fail Front-running is when the attackers race to finish their transaction or interaction before the user. Back-running is when they raise to be behind or right after the user's transaction of interaction.

Combining these two aspects can also be exploited in what are known as sandwich attacks where the user's transaction is sandwiched between those from the patent. So the best practice is to pay attention to the related aspects of timing and ordering attributes and evaluate, if they can be abused in any manner.

Undefined Behavior

Undefined behavior that is triggered accidentally or maliciously may lead to security issues. But what is undefined behavior? Any behavior that is not defined in the specification, but is allowed either explicitly or inadvertently in the implementation is undefined behavior.

Such behavior may never be triggered in normal operations but, if they are triggered accidentally in exceptional conditions that may result in rewards. However, if such behavior can also be exploited in some manner that leads to security issues in some cases it may not be clear, if such undefined behavior is a security concern or not, but nevertheless should be treated as such. The best practice is to make sure all acceptable behavior is detailed in the specification implemented accordingly and documented thoroughly.

Trust

Trust is a fundamental concept in security. Thus minimization (or zero trust in the extreme case) is often the aspirational goal because trusted assets actors actions may be compromised or become malicious to subvert security. Trust minimization is a foundational value upon which web3 is being picked, and one of the key tenets of decentralization where the notions of insiders and outsiders are blurred, and users may misuse the system under assumptions of the Byzantine Threat model.

So incorrect or insufficient trust assumptions about or among system actors and external entities may lead to privileged escalation or misuse, which may further lead to security issues the best practice therefore is to never trust, but always verify both the principle as well as in practice.

Interactions

Following up with the trust minimization ideas we commented earlier, it is obvious that external interactions can have a security impact. Such interactions could be with assets actors or actions that are outside the adopted trust and threat models and hence external. Interacting with such external components for example tokens contracts or Oracles forces the system to trust or make assumptions about their correctness or availability which requires validation of their existence before interacting with them and any outputs from such interactions

Therefore such external interactions can have security implications and need to be considered carefully. Increasing dependencies and composability make this a significant challenge.

Dependencies

In a similar way, dependencies on external actors assets actions or software such as contracts, libraries, tokens, Oracles or Relayers will lead to trust correctness and availability assumptions which, if or when broken may lead to security issues. Dependencies therefore should be well documented and evaluated for such trust assumptions and threat models.

Clarity

Lack of clarity in assets actors or actions or system specification, documentation, implementation, user interface or user experience will lead to incorrect assumptions and unanticipated expectations or outcome which may lead to security issues. Therefore increasing the clarity by clearly thoroughly and accurately specifying implementing and documenting all security relevant aspects will help in mitigating risks from lack of clarity.

Privacy

Privacy and security are very closely related. In this context there could be privacy issues related to assets actors and their actions. Remember that data and transactions on the Ethereum blockchain are not private anyone can observe contract state and track transactions both included in the block, those pending in the mempool. So incorrect assumptions about such privacy aspects of data or transactions that manifest in implementation or assumed trust and threat models can be abused leading to security issues.

Cloning

Cloning in this context refers to copy pasting code from other libraries contracts different parts of the same contract or from entirely different projects with minimal or no changes. The configurations context assumptions bugs and bug fixes for the original code may be ignored or used incorrectly in the context of the cloned code.

This may result in incorrect code semantics for the context being copied to copy over any vulnerabilities or miss any security fixes applied to the original code all of which may lead to security issues. There have been security vulnerabilities because of cloning incorrectly some of which have led to exploits as well. Cloning therefore is risky and has serious security implications.

Gas

Remember that the notion of Gas and Ethereum stems from the need to bound computation because of the Turing completeness of the underlying EVM. Incorrect assumptions about Gas requirements especially for loops or external calls will lead to Out-of-Gas exceptions which may further lead to security issues such as failed transfers or locked funds. Gas usage must therefore be considered while reviewing smart contracts to evaluate any assumptions leading to security implications of denial of service.

Constants

Issues may arise, if you assume certain aspects to be constant. That is they do not change for the duration of a transaction or even the contract's lifetime, but in fact they are not constant and change for some reason. Hardcoded assumptions could manifest for example in hardcoded contract configuration parameters. Example: Block times, block Gas Limits, opcode Gas prices, addresses, roles or permissions. Any such incorrect assumptions about system actors entities or parameters being constant may lead to security issues, if and when such factors change unexpectedly.

Scarcity

Scarcity refers to the notion that something is available in only few numbers. This may refer to assets or actors in the context of an application where assumptions may be made that, there are only a few assets or actors interacting with the application. Incorrect assumptions about such Scarcity say for example tokens funds available to any system actor will lead to unexpected outcomes, if those assumptions are broken which may further lead to security issues.

For example susceptibility to flash loads or flash mints, related overflows is an example where the vulnerable contract makes a Scarcity related assumption and applies that to the size or type of variables used to maintain token balances. Which, if broken because of flash loans or mints can lead to overflows, if not mitigated appropriately. This is also related to civil attacks where an attacker subverts a system by creating a large number of identities and uses them to gain a disproportionately large influence where the system assumption on fewer unique identities is broken in some sense. Therefore one needs to evaluate if there are any Scarcity or abundance assumptions in an application that could cause security issues.

Incentives

Incentives are another fundamental aspect of blockchains and web3. Mechanism design or crypto economics dictates almost everything in this space including infrastructure provisioning development and governance of systems. What incentives are provided and how much incentives are provided may be used or abused while interacting with smart contract applications.

Incentives could be either rewards or penalties, so for example incentives to liquidate positions in defile lending or applications of incentives to cause denial of service or briefing of a system. Incorrect assumptions about such incentives for system or external actors to either perform or not perform certain actions will lead to expected behavior not being triggered or unexpected behavior being triggered both of which may lead to security issues.

Clarity

Lack of clarity in assets actors or actions or system specification, documentation, implementation, user interface or user experience will lead to incorrect assumptions and unanticipated expectations or outcome which may lead to security issues. Therefore increasing the clarity by clearly thoroughly and accurately specifying implementing and documenting all security relevant aspects will help in mitigating risks from lack of clarity.

Privacy

Privacy and security are very closely related. In this context there could be privacy issues related to assets actors and their actions. Remember that data and transactions on the Ethereum blockchain are not private anyone can observe contract state and track transactions both included in the block, those pending in the mempool. So incorrect assumptions about such privacy aspects of data or transactions that manifest in implementation or assumed trust and threat models can be abused leading to security issues.

Cloning Contracts

Cloning in this context refers to copy pasting code from other libraries contracts different parts of the same contract or from entirely different projects with minimal or no changes. The configurations context assumptions bugs and bug fixes for the original code may be ignored or used incorrectly in the context of the cloned code.

This may result in incorrect code semantics for the context being copied to copy over any vulnerabilities or miss any security fixes applied to the original code all of which may lead to security issues. There have been security vulnerabilities because of cloning incorrectly some of which have led to exploits as well. Cloning therefore is risky and has serious security implications.

Previous3.42 Handling EtherNext3.44 Saltzer & Schroeder's Design Principles

Last updated 1 year ago

📚
🔏