Apa yang terjadi
Berdasarkan tulisan SafeState tentang analisis para peneliti, serangannya kira-kira berjalan seperti ini:
- Situs Polymarket memuat script real-user monitoring dari CDN DebugBear. Itu setup yang wajar. Ribuan situs melakukan hal yang sama dengan puluhan vendor.
- Penyerang mengganti file itu dengan JavaScript berbahaya. Karena browser selalu mengambilnya langsung dari vendor, setiap pengunjung seketika mendapat versi baru tersebut.
- Script itu mengecek apakah ada sesi Polymarket yang aktif, membaca data akun, detail wallet dan kredensial API trading dari storage browser, lalu memakai alur penandatanganan milik Polymarket sendiri untuk memindahkan posisi atau menjual aset ke wallet penyerang.
Detail yang patut direnungkan: para peneliti mencatat bahwa hardware wallet dan password yang kuat tidak membantu, karena script itu sama sekali tidak butuh private key. Ia bertindak sebagai pengguna yang sedang login, dari dalam sesi browser pengguna itu sendiri.
Perbaikan Polymarket, menurut laporan yang sama, adalah sebuah commit ke production yang menghapus script vendor tersebut. Trading dibuka lagi sore itu juga. SafeState juga mencatat bahwa ini bukan insiden script vendor pertama yang menimpa platform itu tahun ini.
Kenapa ini penting untuk aplikasimu
Tag script yang mengarah ke cdn.some-vendor.com berjalan dengan kekuasaan yang sama seperti kodemu sendiri. Ia bisa membaca DOM, membaca localStorage dan sessionStorage, memanggil API-mu dengan kredensial pengguna, dan mengubah apa yang ditampilkan halaman. Tidak ada sandbox antara "kodemu" dan "snippet analytics yang kamu tempel saat minggu peluncuran".
Ini sangat relevan untuk aplikasi yang di-ship cepat dan aplikasi buatan AI, karena:
- Script menumpuk. Setiap prompt "tambahkan analytics", "tambahkan chat bubble", "tambahkan error tracking" cenderung menambah satu tag lagi. Jarang ada yang menghapusnya belakangan.
- Token disimpan di storage browser. Banyak template awal menyimpan token sesi atau API di localStorage, tempat script mana pun di halaman bisa membacanya.
- Biasanya tidak ada Content-Security-Policy. Tanpanya, script apa pun yang disisipkan atau ditukar bisa memuat kode tambahan dari mana saja dan mengirim data ke mana saja.
Kamu tidak bisa mengaudit pipeline build vendor-mu. Tapi kamu bisa membatasi seberapa besar kerusakan yang bisa dibuat script jahat.
Cara mengecek aplikasimu
1. Daftar semua script yang dimuat halamanmu. Buka aplikasimu, lalu DevTools, tab Network, filter JS, dan reload. Atau jalankan ini di console pada setiap halaman penting:
[...document.scripts].map(s => s.src || '(inline)').filter(Boolean)Catat setiap domain yang bukan milikmu. Lakukan juga di halaman setelah login, bukan hanya di situs marketing. Tag manager bisa memuat script tambahan yang tidak muncul di source HTML-mu.
2. Cek tag mana saja yang punya atribut integrity. Di console:
[...document.querySelectorAll('script[src]')]
.filter(s => !s.src.startsWith(location.origin))
.map(s => ({ src: s.src, sri: !!s.integrity }))3. Lihat response header-mu. Jalankan curl -sI https://yourapp.com dan cari Content-Security-Policy. Kalau tidak ada, atau isinya script-src * atau 'unsafe-inline' tanpa nonce, header itu tidak banyak membatasi.
4. Cek di mana sesimu disimpan. Di DevTools, buka Application lalu lihat Local Storage dan Session Storage. Kalau kamu melihat access token, refresh token atau API key di sana, script mana pun di halaman bisa membacanya, dan itulah persis yang dilakukan payload Polymarket.
Cara memperbaikinya
Hapus yang tidak kamu perlukan. Ini langkah yang paling berharga. Rekomendasi SafeState untuk operator dimulai dengan menyimpan inventaris script pihak ketiga dan membuang tag yang tidak esensial dari halaman akun, checkout dan transaksi. Halaman login, billing dan pengaturanmu jarang butuh tool heatmap.
Kunci versi dan verifikasi script yang kamu pertahankan dengan Subresource Integrity (SRI). Kalau vendor menyediakan file berversi, rujuk versi tertentu dan tambahkan hash. Kalau file itu berubah, browser menolak menjalankannya:
<script
src="https://cdn.example-vendor.com/sdk/4.2.1/sdk.min.js"
integrity="sha384-REPLACE_WITH_REAL_HASH"
crossorigin="anonymous"></script>Buat hash-nya sendiri dari file persis yang sudah kamu periksa:
curl -s https://cdn.example-vendor.com/sdk/4.2.1/sdk.min.js \
| openssl dgst -sha384 -binary | openssl base64 -APerhatikan trade-off-nya: SRI merusak script yang diperbarui vendor di tempat pada URL tanpa versi, hal yang umum untuk snippet monitoring dan analytics. Untuk script seperti itu, host sendiri salinan yang dikunci dan kamu perbarui dengan sengaja, atau terima bahwa kamu memercayai file live milik vendor dan jauhkan dari halaman sensitif.
Tambahkan Content-Security-Policy. CSP memberi tahu browser origin mana yang boleh menyajikan script dan ke origin mana halaman boleh mengirim data. Titik awal untuk aplikasi Next.js atau Express bisa terlihat seperti ini:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.example-vendor.com;
connect-src 'self' https://api.yourapp.com;
frame-ancestors 'none';
base-uri 'self';
object-src 'none'Bersikaplah realistis soal apa yang diberikan CSP di sini: kalau domain vendor itu sendiri diizinkan, CSP tidak akan menghentikan file berbahaya yang disajikan dari sana. Yang dilakukan CSP adalah mencegah script itu menarik kode dari domain baru atau mengirim data curian ke endpoint sembarangan yang tidak ada di connect-src. Terapkan dulu dengan Content-Security-Policy-Report-Only supaya kamu bisa melihat apa yang rusak. Panduan kami tentang menambahkan Content-Security-Policy menjelaskannya langkah demi langkah.
Jauhkan token sesi dari jangkauan JavaScript. Pindahkan token sesi ke cookie bertanda HttpOnly, Secure dan SameSite, supaya script di halaman tidak bisa membacanya. Ini tidak akan menghentikan script jahat mengirim request atas nama pengguna selama halaman terbuka, tapi mencegah token dicuri dan dipakai ulang di tempat lain. Lihat flag cookie Secure, HttpOnly dan SameSite.
Jaga key frontend-mu tetap bersih. Kalau sebuah script bisa membaca bundle-mu, ia bisa membaca rahasia apa pun yang ikut kamu kirim di dalamnya, dan bot sudah memburu key yang bocor dan file .env. Cek panduan kami tentang API key yang terekspos di JavaScript sisi klien, pastikan kamu tidak mengirim source map di production, dan kalau kamu sudah sempat kecolongan, artikel kami tentang merotasi rahasia aplikasimu tanpa downtime membahas cara membereskannya.
Checklist penutup
Sebelum menutup DevTools, pastikan kamu:
- Mendata setiap script pihak ketiga di halaman publik dan halaman setelah login.
- Menghapus script yang tidak lagi dipakai, terutama dari halaman login, billing dan akun.
- Mengunci versi dan menambahkan hash integrity jika vendor mendukungnya.
- Meng-host sendiri script yang tidak bisa dikunci, atau menjauhkannya dari halaman sensitif.
- Memasang Content-Security-Policy dengan script-src dan connect-src yang ketat.
- Menyimpan token sesi di cookie HttpOnly, bukan di localStorage.
- Mengulang audit ini setiap kali seseorang (atau agen AI) menambahkan tag baru.
Cari tahu posisimu
Kalau kamu ingin gambaran awal yang cepat, AppSafe mengecek security header-mu, termasuk apakah Content-Security-Policy sudah dipasang, dan pemindaian penuh terverifikasinya memeriksa masalah frontend seperti Subresource Integrity dan library JavaScript yang rentan. Kamu bisa melihat seperti apa laporannya di contoh laporan, atau padukan ini dengan checklist pra-peluncuran untuk aplikasi buatan AI kami.
Polymarket menemukan penyebabnya sekitar satu jam setelah menghentikan trading. Banyak tim kecil butuh waktu jauh lebih lama untuk menyadari script yang berubah. Jalankan pemindaian AppSafe gratis di aplikasimu hari ini dan cari tahu posisimu.
