• YouTube Channel
  • System Status
  • VS Code Extension
  • Array Length Assignment

    Overview

    What is the Array Length Assignment vulnerability?

    In Ethereum, storage (state) variables associated with a smart contract are indexed by a 256-bit integer key. For dynamically sized arrays, the array values are stored sequentially starting from the hash of the key for the array. In earlier versions of Solidity, the length propery of a dynamic array could be specified by the programmer, modifying which storage slots were available to be indexed through that array.

    If a smart contract exposed functionality to set the length and index the array, an attacker could potentially access any storage slot of the smart contract. If write access were provided, an attacker could subsequently write over sensitive storage variables, such as the owner of the smart contract or other critical data.

    Further reading: Maliciously Manipulate Storage Variables in Solidity

    Technical example of vulnerable code

      // SPDX-License-Identifier: Unlicense
      pragma solidity 0.4.0;
        
      contract VulnerableArray {
          address[] public users; // A dynamically sized array
          address public owner; // This value should not be able to be updated by any user
    
          constructor() public {
              users.push(msg.sender); // Initializing the array with some data
              owner = msg.sender;
          }
    
          function register() public payable {
              users.push(msg.sender);
          }
    
          function setUsersLength(uint256 _length) public {
              // Problematic: Allowing arbitrary changes to array length
              users.length = _length;
          }
    
          function setUser(uint256 _index, address _value) public {
              // Problematic: Accessing elements beyond the intended bounds
              data[_index] = _value;
          }
    
          function withdrawContractFunds() public {
              require(msg.sender == owner);
              msg.sender.transfer(address(this).balance);
          }
    
          // additional smart contract functionality
    
      }
    
    

    In the example above, the users array is dynamic, with the function setUsersLength allowing the length of the array to be set arbitrarily. The setUser function allows anyone to set the value of any element in the array. This allows the user to access any storage slot in the smart contract, including the owner variable, if they can determine the appropriate index to overwrite it. An attacker able to exploit this vulnerability could set themselves as the owner and subsequently call withdrawContractFunds to drain the contract of its funds.

    Technical example of how to fix the vulnerability

      // SPDX-License-Identifier: Unlicense
        pragma solidity 0.5.0;
          
        contract VulnerableArray {
            address[100] public users; // A dynamically sized array
            address public owner; // This value should not be able to be updated by any user
      
            constructor() public {
                users.push(msg.sender); // Initializing the array with some data
                owner = msg.sender;
            }
      
            function register() public payable {
                users.push(msg.sender);
            }
      
            function setUser(uint256 _index, address _value) public {
                data[_index] = _value;
            }
      
            function withdrawContractFunds() public {
                require(msg.sender == owner);
                msg.sender.transfer(address(this).balance);
            }
      
            // additional smart contract functionality
      
        }
    
    

    In the updated code example, the compiler version is specified as 0.5.0, which no longer allows for assignment of the length property of arrays. In addition, the users array itself has been set to a fixed length to limit the bounds of its access.