solidity.security.proxy-storage-collision.proxy-storage-collision

profile photo of semgrepsemgrep
Author
unknown
Download Count*

Proxy declares a state var that may override a storage slot of the implementation

Run Locally

Run in CI

Defintion

rules:
  - id: proxy-storage-collision
    message: Proxy declares a state var that may override a storage slot of the
      implementation
    metadata:
      category: security
      technology:
        - solidity
      cwe: "CWE-787: Out-of-bounds Write"
      confidence: HIGH
      likelihood: MEDIUM
      impact: HIGH
      subcategory:
        - vuln
      references:
        - https://blog.audius.co/article/audius-governance-takeover-post-mortem-7-23-22
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Other
    patterns:
      - pattern-either:
          - pattern: |
              contract $CONTRACT is ..., $PROXY, ... {
                  ...
                  $TYPE $VAR;
                  ...
                  constructor(...) {
                      ...
                  }
                  ...
              }
          - pattern: |
              contract $CONTRACT is ..., $PROXY, ... {
                  ...
                  $TYPE $VAR = ...;
                  ...
                  constructor(...) {
                      ...
                  }
                  ...
              }
      - pattern-not: |
          contract $CONTRACT is ..., $PROXY, ... {
              $TYPE immutable $VAR;
              ...
              constructor(...) {
                  ...
              }
              ...
          }
      - pattern-not: |
          contract $CONTRACT is ..., $PROXY, ... {
              $TYPE immutable $VAR = ...;
              ...
              constructor(...) {
                  ...
              }
              ...
          }
      - pattern-not: |
          contract $CONTRACT is ..., $PROXY, ... {
              $TYPE constant $VAR = ...;
              ...
              constructor(...) {
                  ...
              }
              ...
          }
      - metavariable-regex:
          metavariable: $CONTRACT
          regex: ^(?!AdminUpgradeabilityProxy|OwnedUpgrade*abilityProxy).*$
      - metavariable-regex:
          metavariable: $PROXY
          regex: (UpgradeabilityProxy|AdminUpgradeabilityProxy|OwnedUpgrade*abilityProxy|TransparentUpgradeableProxy|ERC1967Proxy)
      - focus-metavariable: $PROXY
    languages:
      - solidity
    severity: WARNING

Examples

proxy-storage-collision.sol

pragma solidity ^0.5.0;

import "@openzeppelin/upgrades/contracts/upgradeability/UpgradeabilityProxy.sol";


/**
 * @notice Wrapper around OpenZeppelin's UpgradeabilityProxy contract.
 * Permissions proxy upgrade logic to Audius Governance contract.
 * https://github.com/OpenZeppelin/openzeppelin-sdk/blob/release/2.8/packages/lib/contracts/upgradeability/UpgradeabilityProxy.sol
 * @dev Any logic contract that has a signature clash with this proxy contract will be unable to call those functions
 *      Please ensure logic contract functions do not share a signature with any functions defined in this file
 */
// ruleid: proxy-storage-collision
contract AudiusAdminUpgradeabilityProxy is UpgradeabilityProxy {
    address private proxyAdmin;
    string private constant ERROR_ONLY_ADMIN = (
        "AudiusAdminUpgradeabilityProxy: Caller must be current proxy admin"
    );

    /**
     * @notice Sets admin address for future upgrades
     * @param _logic - address of underlying logic contract.
     *      Passed to UpgradeabilityProxy constructor.
     * @param _proxyAdmin - address of proxy admin
     *      Set to governance contract address for all non-governance contracts
     *      Governance is deployed and upgraded to have own address as admin
     * @param _data - data of function to be called on logic contract.
     *      Passed to UpgradeabilityProxy constructor.
     */
    constructor(
      address _logic,
      address _proxyAdmin,
      bytes memory _data
    )
    UpgradeabilityProxy(_logic, _data) public payable
    {
        proxyAdmin = _proxyAdmin;
    }

    /**
     * @notice Upgrade the address of the logic contract for this proxy
     * @dev Recreation of AdminUpgradeabilityProxy._upgradeTo.
     *      Adds a check to ensure msg.sender is the Audius Proxy Admin
     * @param _newImplementation - new address of logic contract that the proxy will point to
     */
    function upgradeTo(address _newImplementation) external {
        require(msg.sender == proxyAdmin, ERROR_ONLY_ADMIN);
        _upgradeTo(_newImplementation);
    }

    /**
     * @return Current proxy admin address
     */
    function getAudiusProxyAdminAddress() external view returns (address) {
        return proxyAdmin;
    }

    /**
     * @return The address of the implementation.
     */
    function implementation() external view returns (address) {
        return _implementation();
    }

    /**
     * @notice Set the Audius Proxy Admin
     * @dev Only callable by current proxy admin address
     * @param _adminAddress - new admin address
     */
    function setAudiusProxyAdminAddress(address _adminAddress) external {
        require(msg.sender == proxyAdmin, ERROR_ONLY_ADMIN);
        proxyAdmin = _adminAddress;
    }
}

/**
 * @notice This contract implements a proxy that is upgradeable by an admin.
 */
// ok: proxy-storage-collision
contract VaultTransparentUpgradeableProxy is TransparentUpgradeableProxy, IVaultImmutable {
    /// @notice Vault underlying asset
    IERC20 public override immutable underlying;

    /// @notice Vault risk provider address
    address public override immutable riskProvider;

    /// @notice A number from -10 to 10 indicating the risk tolerance of the vault
    int8 public override immutable riskTolerance;

    /**
     * @notice Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`.
     */
    constructor(
        address _logic,
        address admin_,
        VaultImmutables memory vaultImmutables
    ) TransparentUpgradeableProxy(_logic, admin_, "") payable {
        underlying = vaultImmutables.underlying;
        riskProvider = vaultImmutables.riskProvider;
        riskTolerance = vaultImmutables.riskTolerance;
    }
}

/**
 * @notice This contract implements a proxy that is upgradeable by an admin.
 */
// ruleid: proxy-storage-collision
contract VaultTransparentUpgradeableProxy is TransparentUpgradeableProxy, IVaultImmutable {
    /// @notice Vault underlying asset
    address private proxyAdmin = address(0);
    IERC20 public override immutable underlying;

    /// @notice Vault risk provider address
    address public override immutable riskProvider;

    /// @notice A number from -10 to 10 indicating the risk tolerance of the vault
    int8 public override immutable riskTolerance;

    /**
     * @notice Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`.
     */
    constructor(
        address _logic,
        address admin_,
        VaultImmutables memory vaultImmutables
    ) TransparentUpgradeableProxy(_logic, admin_, "") payable {
        underlying = vaultImmutables.underlying;
        riskProvider = vaultImmutables.riskProvider;
        riskTolerance = vaultImmutables.riskTolerance;
    }
}

/**
 * @notice This contract implements a proxy that is upgradeable by an admin.
 */
// ok: proxy-storage-collision
contract VaultTransparentUpgradeableProxy is TransparentUpgradeableProxy, IVaultImmutable {
    /// @notice Vault underlying asset
    address constant proxyAdmin = address(0);
    IERC20 public override immutable underlying;

    /// @notice Vault risk provider address
    address public override immutable riskProvider;

    /// @notice A number from -10 to 10 indicating the risk tolerance of the vault
    int8 public override immutable riskTolerance;

    /**
     * @notice Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`.
     */
    constructor(
        address _logic,
        address admin_,
        VaultImmutables memory vaultImmutables
    ) TransparentUpgradeableProxy(_logic, admin_, "") payable {
        underlying = vaultImmutables.underlying;
        riskProvider = vaultImmutables.riskProvider;
        riskTolerance = vaultImmutables.riskTolerance;
    }
}

/**
 * @notice This contract implements a proxy that is upgradeable by an admin.
 */
// ok: proxy-storage-collision
contract VaultTransparentUpgradeableProxy is TransparentUpgradeableProxy, IVaultImmutable {
    /// @notice Vault underlying asset
    address immutable proxyAdmin = address(0);
    IERC20 public override immutable underlying;

    /// @notice Vault risk provider address
    address public override immutable riskProvider;

    /// @notice A number from -10 to 10 indicating the risk tolerance of the vault
    int8 public override immutable riskTolerance;

    /**
     * @notice Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`.
     */
    constructor(
        address _logic,
        address admin_,
        VaultImmutables memory vaultImmutables
    ) TransparentUpgradeableProxy(_logic, admin_, "") payable {
        underlying = vaultImmutables.underlying;
        riskProvider = vaultImmutables.riskProvider;
        riskTolerance = vaultImmutables.riskTolerance;
    }
}