Failure to Initialize (Falha ao Inicializar)

Ocorre quando um contrato não é inicializado corretamente antes de ser utilizado, o que pode fazer com que variáveis críticas — como o proprietário do contrato ou configurações importantes — permaneçam em um estado padrão. Isso pode permitir que qualquer usuário assuma o controle do contrato ou que o contrato funcione de maneira inesperada. Exemplo: Imagine que você possui um contrato inteligente que deve ser inicializado com um endereço de proprietário (owner) que possui privilégios especiais, como a capacidade de pausar ou destruir o contrato. Se o contrato não tiver um construtor que atribua a direção do proprietário, ou se for implantado utilizando um proxy sem uma função de inicialização adequada, a variável owner pode permanecer em um estado padrão — como o endereço 0x0 ou qualquer outro valor padrão.

contract VulnerableContract {
    address public owner;

    function initialize(address _owner) external {
        owner = _owner;
    }

    function pauseContract() external {
        require(msg.sender == owner, "Not the contract owner");
        // Lógica para pausar o contrato
    }
}

Neste exemplo, se a função initialize não for chamada após o contrato ser implantado, a variável owner permanecerá sem ser definida, e qualquer usuário poderá potencialmente chamar initialize e se definir como proprietário, assumindo o controle do contrato.

Mitigação:

  1. Uso de um construtor: Se o contrato não utilizar um padrão de proxy e for implantado diretamente, é sempre recomendável usar um constructor para inicializar variáveis críticas como owner. O construtor garante que essas variáveis sejam definidas no momento da implantação e não possam ser modificadas posteriormente.

    contract SecureContract {
        address public owner;
    
        constructor(address _owner) {
            owner = _owner;
        }
    
        function pauseContract() external {
            require(msg.sender == owner, "Not the contract owner");
            // Lógica para pausar o contrato
        }
    }
  2. Inicialização em proxies: Quando se utiliza um padrão de proxy para implantar contratos (um padrão comum para facilitar atualizações), é fundamental incluir uma função de inicialização que assegure que o contrato só possa ser inicializado uma única vez. Essa função deve estar protegida para que possa ser chamada apenas uma vez e não possa ser reutilizada por um atacante.

    contract SecureContract {
        address public owner;
        bool private initialized;
    
        function initialize(address _owner) external {
            require(!initialized, "Already initialized");
            owner = _owner;
            initialized = true;
        }
    
        function pauseContract() external {
            require(msg.sender == owner, "Not the contract owner");
            // Lógica para pausar o contrato
        }
    }
  3. Proteção contra re-inicialização: Além de garantir que a função de inicialização só possa ser executada uma vez, é possível implementar um modificador que verifique se o contrato já foi inicializado antes de permitir a execução de funções críticas. Isso impede que um atacante tente inicializar o contrato novamente ou redefinir variáveis sensíveis após a implantação.

    modifier onlyInitialized() {
        require(initialized, "Contract not initialized");
        _;
    }
    
    function pauseContract() external onlyInitialized {
        require(msg.sender == owner, "Not the contract owner");
        // Lógica para pausar o contrato
    }

Last updated