Cointime

Download App
iOS & Android

Runtime Environment and Smart Contract Security Modeling

Validated Project

The design and runtime of different blockchains alter the security of smart contracts built on top of them. There are a number of reasons for this: developers must use a new domain-specific language; transaction executions may involve asynchronous function finality; and tooling is not always equal for different blockchain environments.

In this blog post, we will explore how security changes based on different runtime models. In particular we will compare the runtime assumptions for EVM smart contracts and a similar set of assumptions for NEAR smart contracts. We will then look into how this alters the design of a secure smart contract.

We will also highlight an attack vector found while auditing NEAR contracts which we will name an insolvency attack. While this attack is known to the some in the NEAR community, it is still not a well known attack. Further, it can effect any blockchain that requires additional fees for creating new storage.

Abstract Liquid Staking Contracts

We will begin by defining an abstract liquid staking contract. We will use this contract to understand how the runtime of a blockchain effects the security of a smart contract.

Our staking contract will have some common functionalities found in an ERC20-type contract. The common functionalities will be to track the token balance of a given user and allow for transfers of tokens between users. There are three functions that change state: transfer; transferFrom; and approve. Between two user’s Bob and Alice they are able to generally change the state as follows:

  • transfer

a. Call - Bob calls transfer with input amount x and to address Alice.

b. Effect - The contract updates Alice’s balance with x tokens and removes x tokens from Bob’s balance.

  • approve

a. Call - Bob calls approve with input allowance x and to address Alice.

b. Effect - The contract updates Alice’s allowance x with respective to Bob’s balance to allow Alice to call transferfrom on Bob's tokens.

  • transferFrom

Call - Alice calls transferFrom with input amount x input, from address Bobs account, and to address an Sally's address

Effect - The contract updates Sallys’s balance with x tokens and removes x tokens from Bob’s balance and removes Alice’s allowance x with respective to Bob’s balance.

The remaining functions of our liquid staking will be the following.

  • depositAndStake

a. Call - Alice calls depositAndStake with x input amount

b. Effect - The contract checks whether there is sufficient attached GAS as input x. If there is then the contract mints Alice stGAS tokens and deposits the GAS into a node. It then calls depositandStakeCallback

  • depositAndStakeCallback

a. Call - The contract can only call this function internally with no inputs.

b. Effect - It checks whether the Gas deposit is successful. If successful it returns true and otherwise it reverts the state updates and sends the user their GAS tokens back.

  • withdraw

a. Call - Alice calls withdraw with input amount x

b. Effect - The contract unstakes Alice’s GAS tokens from the node and calls transferFrom on an equivalent amount of stGAS tokens that Alice owns. If Alice does not hold a sufficent amount of stGAS then the transaction reverts.

EVM Runtime Model and Asynchronous Function Calls

The runtime model for the EVM is well known. A general set of axioms assumed by Solidity developers are seen below:

  • If there is sufficient amount of gas then transactions may contain numerous and complex function calls;
  • If a transaction is executed then function calls are synchronous;
  • There is no difference in gas cost of a transaction if a function call increases the storage usage of an existing contract.

This model lead to an interesting family of attack surfaces called reentrancy attacks. While solutions for reentrancy attacks are now well known, there are still many different examples of reentrancy that are more difficult to detect such as multifunction reentrancy and read only reentrancy.

Using our liquid staking contract, let us review how a simple reentrancy attack would work on a EVM-style smart contract using our psuedo-code below.

    function withdraw(uint amount) {
        require(balances[msg.sender] >= amount);
        msg.sender.transfer(amount);       
        balances[msg.sender] -= amount;   
        ...
        ...
    }

Reentrancy attack flow for synchronous function calls:

  • Suppose Bob is a smart contract and our liquid staking contract controls 100 GAS tokens.
  • If Bob holds at least 1 stGAS token then Bob can call withdraw and re-enter via the fallback.
  • The final withdraw will then complete the function call.

The check-effect-interact pattern is one solution to this type of reentrancy. In the example this is done by switching the line responsible for transferring with the line that updates balances. However, is this solution still secure if function calls are no longer synchronous? No! A concrete example can be found in Near smart contracts.

Lets look at the following psuedocode for a liquid staking contract. This example, we will assume that all external function calls are assumed to be finalized in the next block. Further note that the follow is based off the documentation from NEAR and is only meant to model a re-entrancy attack.

   fn depositAndStake(){
     let user = msg.sender();
     let amount = msg.value();
     balance[user]= balance[user] + amount;

     #External contract call  - Takes 1 block to finalize

     validator.deposit_NEAR_and_stake()
     .attachNEAR(amount).thenCallback(depositAndStakeCallback)

   }

   fn withdraw(amount: u32){
     if user has sufficent balance:
       balance[user] = balance[user] - amount
       msg.sender.transfer(amount); 
       ...
       ...
   }

   function depositAndStakeCallback{
   if deposit Failed:
       # Also assume not reverts on underflows 
       balance[user] = balance[user] - amount
       msg.sender.transfer(amount);
   }
   ...
   ...

} 

Notice that in the above contract, the withdraw function follows check-effect-interact pattern. However it is still vulnerable to reentrancy as follows:

  • Suppose Bob is a smart contract on Near and suppose our liquid staking contract controls 100 Near tokens.
  • Bob calls depositAndStake with 49 Near attached at block zero.

Bob calls the withdraw function at block zero then Bob will receive 49 Near.

However, the callback function depositAndStakeCallback is executed at block one and Bob will receive another 49 Near.

Note that Bob is able to call depositAndStake and withdraw within the same transaction. This is because the NEAR blockchain allows for batched function calls. The key here is that the withdraw function is finalized before the depositAndStake has completed the external function call.

Reentrancy attacks are still permissible when function calls are asynchronous however in a slightly different form. One solution to protect against such an attack one is to follow a Check-Interact-Effect in combination with a local Mutex for certain situations. See below for how the Check-Interact-Effect would work here. Further to see the full example, please check the excellent explanation found in the NEAR documentation.

    fn depositAndStake(){
      let user = msg.sender();
      let amount = msg.value();

      #External contract call  - Takes 1 block to finalize

      validator.deposit_NEAR_and_stake()
      .attachNEAR(amount).thenCallback(depositAndStakeCallback)

    }

    fn withdraw(amount: u32){
      if user has sufficent balance:
        balance[user] = balance[user] - amount
        msg.sender.transfer(amount); 
        ...
        ...
    }

    function depositAndStakeCallback{

    if deposit Successful:
    balance[user]= balance[user] + amount;

    if deposit Failed:
        # Also assume not reverts on underflows 
        msg.sender.transfer(amount);
    }
    ...
    ...

} 

Near Runtime Model and Storage Staking

In the previous section, we saw how the security model of our smart contract can change if function calls are no longer synchronous. In this section, lets see how security will change if gas increases when the state of a smart contract increases.

On the NEAR blockchain, the storage of on-chain data requires the deposit of NEAR tokens into the account that contains such data. This mechanism is called Storage Staking. Any piece of data is subject to the deposit including: account metadata; smart contract bytecode; data generated by function calls on smart contracts. The amount of Near needed for Storage Staking is defined to be the stored data length multiplied by the cost in byte.

As such we can update the general axioms for Near developers as follows:

  • If there is sufficient amount of gas then transactions may contain numerous and complex function calls;
  • If a transaction is executed then external function calls are asynchronous;
  • The gas cost of a transaction is defined to be the sum of the gas cost of the function call and a storage staking fee. If there is not enough storage staking fee then all function calls will revert and all other funds deposited in the contract are locked.

The introduces a new problem not found when writing EVM smart contracts. If a generic user can call a function that stores new on-chain data then the smart contract logic must verify there is sufficient funds for the Storage Staking. Otherwise a generic user can cause a denial of service attack on the smart contract. This attack is referred to as the Million Small Deposits attack.

Evgeny Kuzyakov from the Near Social team has provided a solution for storage staking found in NEP-145. However, even with this solution if storage staking is not properly calculated between contracts this opens up a new attack vector which we will call an insolvency attack.

Insolvency Attack on Liquid Staking Contract

To minimize complexity let us suppose that our Liquid staking contract does not enforce a storage staking fee in the function depositAndStake. However the withdraw function refunds a storage staking fee.

    fn depositAndStake(){

      let user = msg.sender();
      let amt = msg.value();
      # increases contract size if user is calling for the first time.
      balance[user]= balance[user] + amt;

      #External contract call   

      validator.deposit_NEAR_and_stake()
      .attachNEAR(amount).thenCallback(depositAndStakeCallback)

    }

    fn withdraw(amount: u32){
      if user has sufficent balance:
        balance[user] = balance[user] - amount
        msg.sender.transfer(amount);
        refund storage fee  
        ...
        ...
    }

Insolvency attack flow:

  • Suppose our liquid staking contract contains 100 Near such that 50 Near is the necessary storage fee for 200 accounts. The remaining 50 is rewards obtained by staking.
  • Further suppose that a new account requires 0.5 Near for storage staking to call depositAndStake.
  • Bob calls depositAndStake with the input amount 0.01.
  • Bob then batch calls the function withdraw with input amount 0.0001.
  • Bob is able to drain 50 NEAR from the Liquid staking and the contract will revert function calls that increase state.

While the above example attack is trivial to see, in practice it is much more difficult to detect for a large system of smart contracts. Further, this scenario does not appear to be logical. Why would a contract refund NEAR when calling withdraw if the balance[user] is not even 0?

This scenario has appeared while auditing NEAR smart contracts. In particular, a bridge can have escrow contracts on either side such that one side of the bridge will collect storage fees and the other side of the bridge will release storage fees. However if both sides do not have the correct storage accounting then a user can abuse the storage fee release. That was an issue with Calimero bridge which we will explore in more detail in the next post. 

Conclusion

Smart contract security is influenced by the underlying blockchain's runtime and the virtual machines that define the programming language. Different models of security are needed for different blockchains.

While there is already a large number of well known security models for different blockchains, the number of models will continue to increase as new blockchains are launched.

Further, we have seen that smart contract security is not composable between different models. In this blog, we provided a number of examples illustrating how NEAR and EVM smart contracts can differ.

One aspect that remains important however not explored in this post is how different smart contract security models interact with each other. These intersections remain critically important as they are found in bridges and other inter-blockchain communication systems. This topic will be explored in another blog post.

Read more: https://www.certik.com/resources/blog/3eSV9gLNNCcIwTt8Qe78Kb-runtime-environment-and-smart-contract-security-modeling

Get the latest news here: Cointime channel — https://t.me/cointime_en

Comments

All Comments

Recommended for you

  • US Spot Ethereum ETF Sees Net Outflow of $4.93 Million

    On June 13, according to monitoring by Trader T, the US spot Ethereum ETF experienced a net outflow of $4.93 million yesterday.

  • US Spot Bitcoin ETF Sees Net Inflow of $85.82 Million Yesterday

    On June 13, according to monitoring by Trader T, the US spot Bitcoin ETF recorded a net inflow of $85.82 million yesterday.

  • U.S. Bans Foreign Access to Fable 5 and Mythos 5; Anthropic Issues Detailed Rebuttal

    On June 13, Anthropic issued a statement announcing that the U.S. government, citing national security powers, has released an export control directive requiring the suspension of all access to the AI models Fable 5 and Mythos 5 by foreign entities, regardless of whether the individuals are within the U.S., including Anthropic employees who are foreign nationals. The practical effect of this order is that we must immediately disable access to Fable 5 and Mythos 5 for all customers to ensure compliance. Access to all other Anthropic models will not be affected. We received the government's directive at 5:21 PM (Eastern Time) today. The letter did not specify the details of its national security concerns. Our understanding is that the government believes it has become aware of a method to bypass or 'jailbreak' Fable 5. So far, the government has only provided us with verbal evidence suggesting the existence of a potential narrow, non-general jailbreak, essentially by requiring the model to read specific code libraries and fix any software defects. We are complying with the government's legitimate directive and are in the process of removing all users' access to Fable 5 and Mythos 5. However, we disagree with the conclusion that 'a narrow potential jailbreak vulnerability should be the reason to recall commercial models deployed to hundreds of millions of users.' (Jinshi)

  • Iranian Foreign Minister: Iran-U.S. Memorandum of Understanding May Be Signed in Days

    On June 13, Iranian media reported that Iranian Foreign Minister Amir-Abdollahian stated that once the final stage of negotiations between Iran and the U.S. is completed, the memorandum of understanding will be signed and announced immediately. The first phase will be signed electronically from a distance, "which may happen in the coming days." (Xinhua News Agency)

  • U.S. Officials: U.S. and Iran Close to Agreement, Signing Expected in Coming Days

    On June 13, Reuters reported that a senior U.S. official stated on Friday local time that the U.S. and Iran have not yet truly reached the finish line, but are very close to finalizing an agreement to resolve their conflicts. Washington expects to sign the agreement in the coming days. 'The negotiating team has put us in a very favorable position, but we still need to see, we haven't really reached the finish line, but we are very close,' the U.S. official said. The official noted that the agreed terms achieve a core goal of Trump. The memorandum of understanding includes the reopening of the Strait of Hormuz and the lifting of U.S. blockades on Iranian ports. Iran's highly enriched uranium will also be destroyed on-site and subsequently removed from the country. 'Iran will not gain anything from signing the memorandum or from the negotiations themselves,' the official said. 'They will receive economic rewards for fulfilling the obligations set forth in the agreement. Therefore, if they commit to handing over nuclear materials, they will gain something. If they dismantle their nuclear program or facilities, they will receive additional benefits.'

  • Iran's Foreign Ministry: Iran is Reviewing Draft Memorandum of Understanding

    On June 13, local time on the 12th, Iranian Foreign Ministry spokesperson Baghaei stated that Iran and the United States have reached an understanding on most issues, and Iran is currently in the final stages of compiling the text of the memorandum of understanding. Therefore, the previous statement by Iranian Foreign Minister Amir-Abdollahian that 'the two sides are very close to reaching an understanding' is accurate and noteworthy. Meetings of relevant decision-making bodies are ongoing, and this is a process that is being continuously advanced. To achieve a final and decisive outcome, consensus must be formed among decision-making bodies and relevant departments. Baghaei also mentioned that various speculations regarding the content of the agreement text have not been confirmed. Although specific details of the diplomatic process cannot be publicly discussed at this time, this does not mean that the public does not have the right to be informed. (CCTV News)

  • SpaceX Opens at $150 on First Day of Trading, IPO Price Set at $135

    On June 12, SpaceX opened at $150 on its first day of trading, with an IPO price set at $135.

  • Iranian Foreign Minister Claims Iran and US 'Have Never Been Closer' to Memorandum of Understanding

    On June 12, Iranian Foreign Minister Amir-Abdollahian stated on social media that Iran and the US 'have never been closer' to reaching a memorandum of understanding. He urged the media to refrain from speculating on its contents before finalization. The Iranian side will disclose all details in due course. (CCTV News)

  • BTC Surpasses $64,000

    Market data shows that BTC has surpassed $64,000, currently priced at $64,107.99, with a 24-hour increase of 2.18%. The market is experiencing significant volatility, so please ensure proper risk management.

  • ARM Soars Nearly 10%, Bank of America Predicts Server CPU Market to Quadruple by 2030

    On June 12, ARM surged nearly 10%, reaching $376.18. According to a recent forecast by Vivek Arya, an analyst at Bank of America Global Research, the total addressable market (TAM) for server CPUs is expected to skyrocket from $35 billion in 2025 to over $170 billion by 2030. This significantly exceeds the bank's previous prediction of a $125 billion market size for server CPUs by 2030. Arya stated in the report, 'We believe the rise of agent-based AI is a powerful demand accelerator that not only expands the market opportunities for CPUs but also benefits Intel, AMD, and challengers based on Arm architecture.'