Failure to Initialize (Falla al Inicializar)

Ocurre cuando un contrato no se inicializa correctamente antes de ser utilizado, lo que puede llevar a que variables críticas, como el propietario del contrato o configuraciones importantes, queden en un estado por defecto. Esto puede permitir que cualquier usuario tome el control del contrato o que el contrato funcione de manera inesperada.

Ejemplo:

Imagina que tienes un contrato inteligente que debería ser inicializado con una dirección de propietario (owner) que tiene privilegios especiales, como la capacidad de pausar o destruir el contrato. Si el contrato no tiene un constructor que asigne la dirección del propietario o si se despliega utilizando un proxy sin una función de inicialización adecuada, la variable owner podría quedar en un estado predeterminado, como la dirección 0x0 o cualquier otra dirección por defecto.

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 el contrato
    }
}

En este ejemplo, si la función initialize no se llama después de desplegar el contrato, la variable owner permanecerá sin establecer, y cualquier usuario podría potencialmente llamar a initialize y establecerse a sí mismo como el propietario, tomando el control del contrato.

Mitigación:

  1. Uso de un constructor: Si el contrato no utiliza un patrón de proxy y se despliega directamente, siempre es recomendable usar un constructor para inicializar variables críticas como owner. El constructor asegura que estas variables se establezcan en el momento del despliegue y no puedan 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 el contrato
        }
    }
  2. Inicialización en proxies: Cuando se utiliza un patrón de proxy para desplegar contratos (un patrón común para facilitar actualizaciones), es crucial incluir una función de inicialización que asegure que el contrato solo puede ser inicializado una vez. Esta función debe estar protegida para que solo pueda ser llamada una vez y no pueda ser reutilizada por un 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 el contrato
        }
    }
  3. Protección contra la re-Inicialización: Además de asegurar que la función de inicialización solo se puede ejecutar una vez, se puede implementar un modificador que verifique que el contrato ya ha sido inicializado antes de permitir la ejecución de funciones críticas.

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

Last updated