🔒
CULTIVA IA Servicio de Seguridad Blockchain
⚠ Confidencial Emitido: 16 de junio de 2026

Informe de Auditoría de Smart Contracts

Cliente: AlgoYield Finance · Plataforma DeFi sobre Algorand Mainnet · TVL auditado: ~4.2M ALGO

Archivos escaneados 3 contratos
Vulnerabilidades 7 detectadas
Herramienta Tealer + Análisis Manual
Metodología Trail of Bits — 11 Patrones Algorand
Versión de contratos v2.0-pre-release
🚨
LANZAMIENTO BLOQUEADO: Se detectaron 2 vulnerabilidades CRÍTICAS y 3 de ALTA severidad que exponen los ~4.2M ALGO del protocolo a ataques de rekeying y manipulación de transacciones grupales. No se recomienda el despliegue hasta resolver los hallazgos marcados como críticos.
7
Total hallazgos
2
Críticos
3
Altos
2
Medios
0
Bajos
Nivel de Riesgo Global
Bajo Alto Crítico
CRÍTICO Fondos de usuarios en riesgo inmediato
Archivos Auditados
🐍
approval_program.py
PyTeal — Contrato principal staking
2C 1H
liquidity_pool.teal
TEAL puro — Smart signature pools
2H 1M
🐍
rewards_distributor.py
PyTeal — Inner txns distribución
1M
Resultados Tealer (Trail of Bits)
⚙ Análisis Estático Automatizado
$ tealer approval_program.teal --detect all --json && tealer liquidity_pool.teal --detect all --json
→ 6 detectores activos · 3 archivos procesados · Tiempo: 4.2s
unprotected-rekey
approval_program.py:45
CRITICAL
group-size-check
liquidity_pool.teal:12
CRITICAL
update-application-check
approval_program.py:23
HIGH
unprotected-closeout
liquidity_pool.teal:87
HIGH
fee-check
liquidity_pool.teal:34
HIGH
inner-txn-fees
rewards_distributor.py:91
MEDIUM
Hallazgos Detallados
Critical

AY-01 · Ataque de Rekeying — Sin validación de RekeyTo

approval_program.py · línea 45 · función: handle_stake()
Patrón #1 — CWE-284
El contrato aprueba transacciones de pago sin validar el campo RekeyTo. Un atacante puede incluir una dirección arbitraria en ese campo para reasignar la autorización de la cuenta del protocolo, obteniendo control total sobre los fondos depositados (~4.2M ALGO).
# approval_program.py:45 — handle_stake()
If(Txn.type_enum() == TxnType.Payment,
Seq([
# ❌ FALTA: Assert(Txn.rekey_to() == Global.zero_address())
App.globalPut(
Bytes("balance"),
balance + Txn.amount()
),
Approve()
])
)
1 El atacante construye una transacción de stake legítima con RekeyTo = attacker_addr.
2 El contrato valida el monto y tipo, pero no comprueba el campo RekeyTo.
3 Algorand procesa la transacción y reautoriza la cuenta del protocolo al atacante.
4 El atacante drena el pool completo (~4.2M ALGO) con autorización legítima.
# Añadir validación explícita de RekeyTo:
If(And(
Txn.type_enum() == TxnType.Payment,
Txn.rekey_to() == Global.zero_address(),
Txn.close_remainder_to() == Global.zero_address()
),
Seq([
App.globalPut(Bytes("balance"), balance + Txn.amount()),
Approve()
]),
Reject()
)
Critical

AY-02 · Manipulación de Grupo Atómico — Sin verificación de GroupSize

liquidity_pool.teal · línea 12 · smart signature de pool
Patrón #2 y #3 — CWE-345
La smart signature del pool de liquidez no valida Global.group_size() ni el índice de la transacción dentro del grupo atómico. Un atacante puede construir grupos con transacciones adicionales no autorizadas que pasen la firma del pool mientras extraen fondos en transacciones paralelas del mismo grupo.
// liquidity_pool.teal:12
txn TypeEnum
int pay
==
// ❌ SIN: global GroupSize / int 2 / == / &&
// ❌ SIN: txn GroupIndex / int 0 / == / &&
txn Receiver
addr ALGOYIELD_POOL_ADDR
==
&&
return
1 Atacante crea grupo atómico de 3 txns: [txn_pool_válida, txn_robo_1, txn_robo_2].
2 La smart signature valida solo la txn[0], aprobando el grupo completo.
3 txn_robo_1 y txn_robo_2 retiran fondos del pool sin restricciones adicionales.
// Validar tamaño y posición del grupo:
global GroupSize
int 2
== // exactamente 2 transacciones en el grupo
txn GroupIndex
int 0
== // esta txn debe ser la primera
&&
txn TypeEnum
int pay
== &&
txn RekeyTo
global ZeroAddress
== && // rekey check
return
High

AY-03 · Fees no verificados en Smart Signature

liquidity_pool.teal · línea 34 · smart signature
Patrón #10 — Fee Manipulation
La smart signature no verifica que el fee de la transacción sea razonable. En TEAL, los fees son pagados por el remitente pero deducidos del saldo de la cuenta si la lógica no los restringe. Un atacante puede configurar fees arbitrariamente altos para agotar el saldo del pool, o establecer fees = 0 para hacer spam masivo gratuito saturando el protocolo.
// Añadir al inicio de la smart signature:
txn Fee
int 1000 // fee mínimo Algorand
>=
txn Fee
int 10000 // fee máximo tolerable
<=
&&
// ... resto de la lógica
High

AY-04 · Control de Acceso en Operaciones Update/Delete

approval_program.py · línea 23 · handle_update()
Patrón #11 — Unauthorized Update
Las operaciones UpdateApplication y DeleteApplication no verifican que el remitente sea el creador del contrato. Cualquier cuenta puede actualizar la lógica del contrato o eliminarlo permanentemente, pudiendo inyectar código malicioso o destruir el protocolo.
# Añadir verificación de creator en updates:
If(
Txn.on_completion() == OnComplete.UpdateApplication,
Assert(Txn.sender() == Global.creator_address()),
Reject()
)
If(
Txn.on_completion() == OnComplete.DeleteApplication,
Assert(Txn.sender() == Global.creator_address()),
Reject()
)
Medium

AY-05 · Inner Transactions sin Fee Explícito

rewards_distributor.py · línea 91 · distribute_rewards()
Patrón #9 — Inner Txn Fee Risk
Las inner transactions del distribuidor de recompensas no especifican el fee explícitamente (deberían ser 0, cubiertos por la transacción outer con fee pooling). El sistema podría deducir fees adicionales del propio pool de recompensas en operaciones de alta frecuencia, erosionando gradualmente los rendimientos del protocolo.
# En cada InnerTxnBuilder, añadir fee=0:
InnerTxnBuilder.Begin(),
InnerTxnBuilder.SetFields({
TxnField.type_enum: TxnType.AssetTransfer,
TxnField.asset_receiver: recipient,
TxnField.asset_amount: reward_amount,
TxnField.fee: Int(0), # ✅ fee cubierto por outer txn
}),
InnerTxnBuilder.Submit()
Checklist de Auditoría — Estado AlgoYield v2

Transacciones de Pago

RekeyTo validado en todas las txns de pago
CloseRemainderTo validado en txns de pago
Fee validado en smart signatures

Transacciones Atómicas

GroupSize validado para grupos atómicos
GroupIndex validado (posición absoluta)
!
Campo Lease para protección de replay (parcial)

Aplicaciones

OnComplete validado (Update/Delete protegidos)
Creator address guardada correctamente
Clear state program definido

Inner Transactions

!
Fee=0 explícito en inner txns (falta en rewards)
RekeyTo no controlado por usuario (TEAL v6+)
Scan Tealer sin hallazgos críticos/altos