Back to Blog

Informe de Auditoría de Seguridad para los Contratos de Cakepie

Code Auditing
November 30, 2023
11 min read

Manifiesto del Informe

Elemento Descripción
Cliente Magpie XYZ
Objetivo CakePie Contracts

Historial de Versiones

Versión Fecha Descripción
1.0 30 de noviembre de 2023 Primera versión

1. Introducción

1.1 Acerca de los Contratos Objetivo

Información Descripción
Tipo Contrato Inteligente
Lenguaje Solidity
Enfoque Verificación semi-automática y manual

El objetivo de esta auditoría es el repositorio de código de CakePie Contracts^1 de Magpie XYZ. Los CakePie Contracts ejecutan una campaña CakeRush en la que los usuarios pueden convertir su token CAKE o posición de CAKE bloqueado de PancakeSwap en CakePie. Tenga en cuenta que solo CakeRush.sol y PancakeStakingBNBChain.sol están incluidos en el alcance de la auditoría, mientras que otros archivos quedan fuera del alcance de esta auditoría.

El proceso de auditoría es iterativo. Específicamente, auditaríamos los commits que corrigen los problemas descubiertos. Si hay nuevos problemas, continuaremos este proceso. Los valores SHA de los commits durante la auditoría se muestran en la siguiente tabla. Nuestro informe de auditoría es responsable del código en la versión inicial (Versión 1), así como del nuevo código (en las versiones siguientes) para corregir los problemas del informe de auditoría.

1.2 Modelo de Seguridad

Para evaluar el riesgo, seguimos los estándares o sugerencias ampliamente adoptados tanto por la industria como por la academia, incluyendo la Metodología de Evaluación de Riesgos de OWASP ^2 y la Enumeración de Debilidades Comunes ^3. La gravedad general del riesgo está determinada por la probabilidad y el impacto. Específicamente, la probabilidad se utiliza para estimar qué tan probable es que una vulnerabilidad particular pueda ser descubierta y explotada por un atacante, mientras que el impacto se utiliza para medir las consecuencias de una explotación exitosa.

En este informe, tanto la probabilidad como el impacto se clasifican en dos niveles, es decir, alto y bajo respectivamente, y sus combinaciones se muestran en la Tabla 1.1.

En consecuencia, la gravedad medida en este informe se clasifica en tres categorías: Alta, Media, Baja. En aras de la exhaustividad, Indeterminado también se utiliza para cubrir circunstancias en las que el riesgo no puede determinarse correctamente.

Además, el estado de un elemento descubierto se encontrará en una de las siguientes cuatro categorías:

  • Indeterminado Aún sin respuesta.

  • Reconocido El cliente ha recibido el elemento, pero aún no lo ha confirmado.

  • Confirmado El cliente ha reconocido el elemento, pero aún no lo ha corregido.

  • Corregido El cliente ha confirmado y corregido el elemento.

2. Hallazgos

En total, encontramos dos problemas potenciales. Además, también tenemos tres recomendaciones y una nota.

  • Riesgo Alto: 1

  • Riesgo Bajo: 1

  • Recomendación: 3

  • Nota: 1

ID Gravedad Descripción Categoría Estado
1 Baja Estado potencialmente inconsistente tras el restablecimiento de parámetros Seguridad de Software Corregido
2 Alta Reclamación repetida de recompensas mCake Seguridad de Software Corregido
3 - Verificar los parámetros en las funciones de inicialización Recomendación Reconocido
4 - Verificar los parámetros en los contratos CakeRush Recomendación Corregido
5 - Condiciones adicionales en los modificadores Recomendación Reconocido
6 - Riesgo potencial de centralización Nota -

Los detalles se proporcionan en las siguientes secciones.

2.1 Seguridad de Software

2.1.1 Estado potencialmente inconsistente tras el restablecimiento de parámetros

Elemento Descripción
Gravedad Baja
Estado Corregido en la Versión 2
Introducido por Versión 1

Descripción El contrato CakeRush distribuye recompensas según varios parámetros. Las siguientes funciones permiten al mantenedor del proyecto restablecer algunos de los parámetros:

function resetMultiplier() external onlyOwner {
        uint256 len = rewardMultiplier.length;
        for (uint8 i = 0; i < len; ++i) {
            rewardMultiplier.pop();
            rewardTier.pop();
        }

        tierLength = 0;
    }

    function resetTimeWeighting() external onlyOwner {
        uint256 len = weightedTime.length;
        for (uint8 i = 0; i < len; ++i) {
            weightedTime.pop();
            weighting.pop();
        }

        weightLength = 0;
    }

Listado 2.1: CakeRush.sol

Sin embargo, estas funciones solo restablecen los parámetros, pero no la información del usuario almacenada en la variable de estado userInfos. Como resultado, los cálculos en el contrato CakeRush pueden fallar debido al estado inconsistente. Por ejemplo, si los parámetros se restablecen y se configuran con valores incorrectos, la sustracción en la Línea 155 puede fallar debido a un desbordamiento de entero por defecto.

function quoteConvert(
        uint256 _amountToConvert,
        address _account
    )
        external
        view
        returns (
            uint256 newUserFactor,
            uint256 newTotalFactor,
            uint256 newUserWeightedFactor,
            uint256 newWeightedTotalFactor
        )
    {
        if (_amountToConvert == 0 || rewardMultiplier.length == 0 || weighting.length == 0)
            return (0, 0, 0, 0);

        UserInfo storage userInfo = userInfos[_account];
        uint256 accumulated = _amountToConvert + userInfo.converted;

        uint256 factorAccuNoWeighting = 0;
        uint256 i = 1;
        while (i < rewardTier.length && accumulated > rewardTier[i]) {
            factorAccuNoWeighting += (rewardTier[i] - rewardTier[i - 1]) * rewardMultiplier[i - 1];
            i++;
        }
        factorAccuNoWeighting += (accumulated - rewardTier[i - 1]) * rewardMultiplier[i - 1];

        uint256 factorToEarnNoWeighting = (factorAccuNoWeighting / DENOMINATOR) - userInfo.factor;

Listado 2.2: CakeRush.sol

Lo que es peor, si los usuarios llaman a convert o convertWithCakePool inmediatamente después de restablecer los parámetros (antes de que se establezcan los nuevos parámetros, por ejemplo mediante back-running), puede provocar el restablecimiento de los factores totales y ponderados registrados dentro del contrato, debido a la lógica en las Líneas 141-142.

Impacto El restablecimiento de parámetros puede provocar un estado inconsistente e incorrecto.

Sugerencia Establecer los nuevos parámetros después de borrar los anteriores.

Respuesta del Proyecto Los multiplicadores no se restablecerán una vez que la campaña cake rush haya comenzado.

2.1.2 Reclamación repetida de recompensas mCake

Elemento Descripción
Gravedad Alta
Estado Corregido en la Versión 3
Introducido por Versión 2

Descripción Después de bloquear tokens CAKE en el contrato, los usuarios pueden reclamar tokens mCake como recompensas a través de la función. Sin embargo, la función contiene un problema que permite a los usuarios reclamar las recompensas varias veces. En el siguiente segmento de código, si la cantidad es mayor que la del usuario, se transferiría o depositaría una cantidad total de al usuario. La implementación correcta debería devolver solo, por lo que la implementación actual efectivamente permite a un usuario reclamar repetidamente las recompensas de mCake.

function claim(bool _isStake) external nonReentrant {
        UserInfo storage userInfo = userInfos[msg.sender];
        if (claimedMCake[msg.sender] >= userInfo.converted) revert AlreadyClaimed();
        if (_isStake && userInfo.converted > 0) {
            if (masterCakepie == address(0)) revert MasterCakepieNotSet();
            IERC20(mCakeOFT).safeApprove(address(masterCakepie), userInfo.converted);
            IMasterCakepie(masterCakepie).depositFor(
                address(mCakeOFT),
                address(msg.sender),
                userInfo.converted
            );
        } else if (userInfo.converted > 0) {
            IERC20(mCakeOFT).transfer(msg.sender, userInfo.converted);
            emit Claim(msg.sender, userInfo.converted);
        }

        claimedMCake[msg.sender] = userInfo.converted;
    }

Listado 2.3: CakeRush.sol

Impacto Los usuarios pueden reclamar recompensas mCake de forma repetida.

Sugerencia Revisar la lógica de reclamación de recompensas.

2.2 Recomendación Adicional

2.2.1 Verificar los parámetros en las funciones de inicialización

Elemento Descripción
Estado Reconocido
Introducido por Versión 1

Descripción En las funciones de inicialización de los contratos CakeRush y PancakeStakingBNBChain, existen parámetros que no pueden modificarse después de la inicialización. Se recomienda que estos parámetros sean verificados en las funciones de inicialización.

function __CakeRush_init(
        address _cake,
        address _mCakeOFT,
        address _masterCakepie
    ) public initializer {
        __Ownable_init();
        __ReentrancyGuard_init();
        __Pausable_init();
        cake = _cake;
        mCakeOFT = _mCakeOFT;
        masterCakepie = _masterCakepie;
    }

Listado 2.4: CakeRush.sol

Impacto N/A

Sugerencia Verificar los parámetros en las funciones de inicialización.

2.2.2 Verificar los parámetros en los contratos CakeRush

Elemento Descripción
Estado Corregido en la Versión 2
Introducido por Versión 1

Descripción En el contrato CakeRush, se pueden agregar varios parámetros relacionados con la distribución de recompensas. Sin embargo, no existe ninguna verificación de que estos parámetros estén configurados correctamente según los supuestos del contrato. Específicamente, en las funciones setMultipler y setTimeWeighting, deben verificarse condiciones adicionales (es decir, la propiedad de incremento monótono de los arrays rewardTier y weightedTime).

function setMultiplier(
        uint256[] calldata _multiplier,
        uint256[] calldata _tier
    ) external onlyOwner {
        if (_multiplier.length == 0 || (_multiplier.length != _tier.length)) revert LengthInvalid();

        for (uint8 i = 0; i < _multiplier.length; ++i) {
            if (_multiplier[i] == 0) revert InvalidAmount();
            rewardMultiplier.push(_multiplier[i]);
            rewardTier.push(_tier[i]);
            tierLength += 1;
        }
    }

Listado 2.5: CakeRush.sol

Impacto N/A

Sugerencia Verificar los parámetros en las funciones que los establecen.

2.2.3 Condiciones adicionales en los modificadores

Elemento Descripción
Estado Reconocido
Introducido por Versión 1

Descripción En el contrato CakeRush, el modificador _onlyPancakeStaking tiene una condición superflua. Según la semántica de este modificador, con verificar msg.sender != pancakeStaking sería suficiente.

modifier _onlyPancakeStaking() {
        if (pancakeStaking == address(0) || msg.sender != pancakeStaking)
            revert OnlyPancakeStaking();
        _;
    }

Listado 2.6: CakeRush.sol

Impacto N/A

Sugerencia Eliminar las condiciones superfluas del modificador.

2.3 Nota

2.3.1 Riesgo potencial de centralización

Descripción El propietario de CakeRush tiene privilegios significativos para modificar configuraciones críticas. Esto crea un único punto de fallo. Si un atacante comprometiera al propietario, podría potencialmente incapacitar todo el sistema.

Además, los tokens CAKE en el contrato no se gestionan explícitamente para bloquearlos en el contrato VECake. En cambio, CakeRush permite al propietario retirar todos esos CAKEs, lo que significa que el propietario debe bloquear los tokens CAKE después de retirarlos. Sin embargo, esta lógica no está garantizada a nivel de código, lo que también genera preocupaciones de centralización.

Respuesta del Proyecto El equipo convierte al propietario en un multisig para mitigar el riesgo.

3. Avisos y Observaciones

3.1 Descargo de Responsabilidad

Este informe de auditoría no constituye asesoramiento de inversión ni una recomendación personal. No considera, y no debe interpretarse como consideración o influencia sobre, la economía potencial de un token, venta de tokens o cualquier otro producto, servicio u otro activo. Ninguna entidad debe basarse en este informe de ninguna manera, incluso con el fin de tomar decisiones de compra o venta de tokens, productos, servicios u otros activos.

Este informe de auditoría no es un respaldo de ningún proyecto o equipo en particular, y el informe no garantiza la seguridad de ningún proyecto en particular. Esta auditoría no ofrece ninguna garantía sobre el descubrimiento de todos los problemas de seguridad de los contratos inteligentes, es decir, el resultado de la evaluación no garantiza la inexistencia de más hallazgos de problemas de seguridad. Dado que una sola auditoría no puede considerarse exhaustiva, siempre recomendamos proceder con auditorías independientes y un programa público de recompensas por errores para garantizar la seguridad de los contratos inteligentes.

El alcance de esta auditoría se limita al código mencionado en la Sección 1.1. A menos que se especifique explícitamente, la seguridad del lenguaje en sí (por ejemplo, el lenguaje Solidity), la cadena de herramientas de compilación subyacente y la infraestructura informática quedan fuera del alcance.

3.2 Procedimiento de Auditoría

Realizamos la auditoría siguiendo el siguiente procedimiento.

  • Detección de Vulnerabilidades Primero analizamos los contratos inteligentes con analizadores de código automáticos, y luego verificamos manualmente (rechazamos o confirmamos) los problemas reportados por ellos.

  • Análisis Semántico Estudiamos la lógica de negocio de los contratos inteligentes y realizamos una investigación adicional sobre las posibles vulnerabilidades utilizando una herramienta automática de fuzzing (desarrollada por nuestro equipo de investigación). También analizamos manualmente posibles escenarios de ataque con auditores independientes para verificar de forma cruzada el resultado.

  • Recomendación Proporcionamos algunos consejos útiles a los desarrolladores desde la perspectiva de buenas prácticas de programación, incluyendo optimización de gas, estilo de código, entre otros.

Mostramos los principales puntos de verificación concretos a continuación.

3.2.1 Seguridad de Software

  • Reentrada

  • DoS

  • Control de acceso

  • Manejo de datos y flujo de datos

  • Manejo de excepciones

  • Llamadas externas no confiables y flujo de control

  • Consistencia de inicialización

  • Operaciones con eventos

  • Aleatoriedad propensa a errores

  • Uso inadecuado del sistema proxy

3.2.2 Seguridad DeFi

  • Consistencia semántica

  • Consistencia funcional

  • Gestión de permisos

  • Lógica de negocio

  • Operaciones con tokens

  • Mecanismo de emergencia

  • Seguridad del oráculo

  • Lista blanca y lista negra

  • Impacto económico

  • Transferencia por lotes

3.2.3 Seguridad NFT

  • Elemento duplicado

  • Verificación del receptor del token

  • Seguridad de metadatos fuera de la cadena

3.2.4 Recomendación Adicional

  • Optimización de gas

  • Calidad y estilo del código

Nota Los puntos de verificación anteriores son los principales. Podemos utilizar más puntos de verificación durante el proceso de auditoría según la funcionalidad del proyecto.

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit