Aztec Connect Diretas Rp$2,19 Juta akibat Celah ZKRollup

Pada 14 Juni 2026, kontrak RollupProcessor Aztec Connect yang sudah dihentikan (deprecated) — 0xff1f2b4adb9df6fc8eafecdcbf96a2b351680455 — dieksploitasi. Penyerang menguras sekitar US$2,19 juta aset dari pool L1 dalam satu transaksi atomik dengan memanfaatkan "boundary gap" antara numRealTxs dan decoded_slots. Meski Aztec Connect sudah deprecated sejak Maret 2024, kontrak immutable ini tetap menjadi titik paparan karena masih menyimpan sisa aset pengguna. Uraian berikut merangkum rekonstruksi teknis serangan berdasarkan kode kontrak dan calldata on-chain. Gambaran kerentanan Akar masalahnya adalah ketidakselarasan batas pemrosesan: rentang siklus settlement L1 yang dilalui RollupProcessorV3 tidak sejalan dengan rentang slot yang dikomit melalui hash public input ZK. Celah ini dimanfaatkan untuk membuat 31 dari 32 slot public input ikut terkunci (committed) ke state root L2 lewat ZK proof, tanpa melewati validasi settlement di lapisan kontrak L1. Pada Decoder.sol, nilai numRealTxs sepenuhnya dapat dikendalikan penyerang karena dibaca dari calldata offset 4516 tanpa pembatasan on-chain. decoded_slots kemudian dibulatkan ke kelipatan terdekat dari numTxsPerRollup demi memenuhi tata letak data precompile SHA256. Proses pembulatan ini menciptakan area "gap" antara numRealTxs dan decoded_slots yang dapat diisi bebas. Di RollupProcessorV3.sol, loop settlement hanya mencakup numRealTxs slot. Dampaknya, asumsi keamanan normal—bahwa setiap public input slot divalidasi di L1 (misalnya lewat pengurangan pendingDepositBalance saat deposit) atau dibatasi oleh sirkuit ZK agar publicValue == 0—gagal dalam kondisi ini: - Precompile SHA256 mencakup seluruh 32 slot (teruji dengan input 8192 byte = 32 × 256 byte), dan konten slot "gap" ikut dikomit lewat ZK proof. - Settlement L1 hanya memproses slot pertama; slot gap [2..32] tidak tersentuh validasi L1. - Pembatasan sirkuit ZK pada publicValue di slot gap (yang seharusnya 0) dibypass atau tidak ditegakkan. Model "dual-path divergence" Calldata yang sama dikonsumsi oleh dua jalur dengan batas atas berbeda: ZK memperlakukan 32 slot sebagai bagian dari komitmen, sementara L1 hanya menganggap 1 slot. Perbedaan definisi "slot yang dihitung" ini menjadi pemicu terciptanya saldo seolah-olah "minting dari nol". Alur serangan Transaksi serangan 0x074ec931…aee1 berisi 14 pemanggilan processRollup() yang disusun dua fase: "7 kali minting" lalu "7 kali penarikan", seluruhnya dalam satu transaksi atomik. Fase 1: Minting — membentuk saldo L2 tanpa dukungan aset di L1 (Rollup #13277–13283, 7 kali) 1) EOA penyerang 0x0f18d8b44a740272f0be4d08338d2b165b7edd17 memanggil kontrak entry master control 0x06f585f74e0da633ae813a0f23fb9900b61d0fcd dengan selector 0x6f3ce701. 2) Kontrak master memanggil berurutan tiga kontrak relay, masing-masing menyimpan calldata rollup berbahaya yang sudah di-hardcode. Parameter kunci tiap calldata: - numRealTxs = 1, rollupSize = 1024, numInnerRollups = 32 - Slot 1 (terlihat di L1): proofId = 0 (noop), publicValue = 0 - Slot 2–32 (31 slot gap, tidak terlihat di L1): proofId = 1 (deposit), publicValue = N, publicOwner = alamat L2 penyerang - Disertai ZK proof yang relevan (sirkuit tidak membatasi publicValue slot gap menjadi 0) 3) Relay Contract A memanggil RollupProcessor.processRollup() beruntun (Rollup #13277–13281, 5 kali): verifikator menyatakan ZK proof valid dan komitmen SHA256 mencakup 32 slot, tetapi siklus settlement L1 berhenti di 1 × TX_PUBLIC_INPUT_LENGTH = 1 slot sehingga hanya memproses noop. "Deposit" palsu di slot gap [2..32] masuk ke komitmen ZK dan menghasilkan Merkle root baru, menaikkan saldo L2 penyerang sebesar 5 × 31N. 4) Relay Contract B memproses Rollup #13282–13283 dengan pola serupa (2 kali), menambah 2 × 31N. Total, akun L2 penyerang mengumpulkan 7 × 31N "deposit" tanpa dukungan, sementara vault L1 tetap tidak berubah. Fase 2: Withdrawal — mengonversi saldo L2 yang menggelembung menjadi aset L1 (Rollup #13284–13290, 7 kali) Penyerang menukarkan seluruh saldo L2 hasil fase minting menjadi aset L1 melalui tujuh rollup penarikan: - Rollup #13284 (DAI): withdraw() → RollupProcessor mentransfer 270.513,054 DAI ke 0x0f18…edd17 - Rollup #13285 (wstETH): 167,890 wstETH → penyerang - Rollup #13286 (yvDAI): 4.873,857 yvDAI → penyerang - Rollup #13287 (yvWETH, relay contract C mengambil alih): 16,570 yvWETH → penyerang - Rollup #13288 (LUSD): 9.273,734 LUSD → penyerang - Rollup #13289 (yvLUSD): 359,047 yvLUSD → penyerang - Rollup #13290 (ETH, transaksi terakhir): RollupProcessor mentransfer 908,987 ETH melalui internal CALL → penyerang Seluruh rangkaian berhasil dieksekusi dalam satu transaksi atomik (gasUsed = 4.513.539), sehingga rollback parsial di level kontrak tidak memungkinkan. Estimasi keuntungan penyerang sekitar US$2,19 juta, seluruhnya berasal dari pool aset pengguna yang sah di RollupProcessor. Pelacakan dana Berdasarkan forensik on-chain (per 15 Juni 2026, sekitar sehari setelah insiden): - Semua aset dipindahkan dalam satu transaksi dari RollupProcessor melalui kontrak perantara 0x06f585…d0fcD langsung ke EOA penyerang 0x0F18D8b44a740272f0be4d08338d2b165b7EdD17. - Kontrak perantara tidak menyisakan dana. - Dana curian masih 100% utuh dan belum dipindahkan lebih lanjut; belum terlihat aktivitas pencucian dana. Pelajaran utama dan rekomendasi Inti pelajaran dari insiden ini: batas atas loop settlement pada kontrak ZKRollup harus selaras ketat dengan rentang slot public input yang dikomit oleh ZK proof. Jika ada gap antara boundary numRealTxs di lapisan kontrak L1 dan decoded_slots pada komitmen SHA256, asumsi keamanan yang menggantungkan penegakan constraint di slot gap pada sirkuit ZK dapat ditembus. L1 perlu memverifikasi secara independen setiap public input slot yang sudah dikomit oleh ZK proof dan tidak dapat menyerahkan beban verifikasi tersebut ke lapisan sirkuit. SlowMist Security Team merekomendasikan audit eksternal menyeluruh sebelum peluncuran sistem Rollup, dengan fokus pada konsistensi logika di batas state L1/L2, batas kepercayaan pada decoding calldata, serta verifikasi sekunder on-chain atas public input ZK. Untuk kontrak yang sudah deprecated tetapi masih menyimpan aset legacy, disarankan melakukan migrasi aset yang tertib atau memusnahkan mekanisme penyimpanan agar risiko paparan tidak berlarut. Artikel ini disusun oleh Threat Intelligence Team SlowMist dengan dukungan MistEye Threat Intelligence System, MistTrack Tracking Platform, serta analisis berbasis AI SlowMist Agent. Pertanyaan dan masukan dapat disampaikan kepada tim.