Puntuación de Riesgo
Se detectaron 4 vulnerabilidades críticas que pueden resultar en pérdida de fondos, crash del nodo o acceso no autorizado al tesoro. El lanzamiento debe postponerse hasta corrección completa.
Alcance del Escaneo
| ID | Vulnerabilidad | Pallet | Patrón | Severidad | Estado |
|---|---|---|---|---|---|
| CMT-001 | Overflow aritmético en distribución de rewards | staking_rewards | Arithmetic Overflow | Crítica | Pendiente |
| CMT-002 | Panic en retirada con unwrap() sin guard | staking_rewards | Don't Panic · DoS | Crítica | Pendiente |
| CMT-003 | Escritura en storage antes de validación de origen | treasury_governance | Verify First, Write Last | Crítica | Pendiente |
| CMT-004 | ensure_signed en función de ejecución del tesoro | treasury_governance | Bad Origin | Crítica | Pendiente |
| CMT-005 | Pesos fijos para operación O(n) de distribución | staking_rewards | Weights and Fees | Alta | Pendiente |
| CMT-006 | Validación de transacción unsigned insuficiente | treasury_governance | Unsigned Validation | Alta | Pendiente |
| CMT-007 | RandomnessCollectiveFlip para sorteo de validadores | staking_rewards | Bad Randomness | Media | Pendiente |
La función distribute_rewards() utiliza operadores aritméticos nativos de Rust (+, *) que en modo release hacen wrapping, no panican. Con suficientes stakers y una época de alta recompensa, el acumulador puede desbordarse y distribuir cantidades incorrectas, acuñando tokens de la nada.
La función withdraw_stake() llama a .unwrap() sobre el lookup en storage. Si un atacante elimina la entrada del staker entre bloques (condición de carrera en edge case de migración), el nodo hace panic y deja de procesar bloques — DoS completo.
En Substrate v0.9.20 (pre-transaccional), las escrituras a storage persisten aunque la transacción falle después. La función submit_proposal() escribe el estado antes de validar el depósito del proponente, dejando propuestas "fantasma" que pueden ser ejecutadas sin fondos reales.
La función execute_spending() que transfiere fondos del tesoro solo verifica ensure_signed — cualquier cuenta puede llamarla con cualquier propuesta aprobada. No existe verificación de quórum de votos ni origen privilegiado.
La función distribute_rewards() itera sobre todos los stakers (O(n)) pero declara un peso fijo de 10_000. Con miles de stakers, el bloque puede superar su tiempo límite y el peso no cubre el coste real, permitiendo spam gratuito de distribuciones.