// docs / baas security / supabase service role exposure
Supabase service role key terekspos di JavaScript: apa artinya dan cara menemukannya
Service role key Supabase adalah kunci master ke database Anda. Siapa saja yang memegangnya mem-bypass Row-Level Security, dapat membaca setiap kolom dari setiap tabel, dan dapat menulis atau menghapus apa pun yang mereka pilih. Ia dirancang untuk hidup secara eksklusif di kode sisi server โ tidak pernah di browser. Ketika AI coding tool mengirimkannya ke bundle JavaScript, database Anda, secara efektif, bersifat publik. Artikel ini menjelaskan bentuk JWT yang mengidentifikasi key yang bocor, tiga pola AI tool yang menghasilkan kebocoran, apa yang harus dilakukan pada jam pertama setelah deteksi, dan cara men-scan secara otomatis sebelum pengguna melakukannya.
Apa itu service role key
Supabase menerbitkan dua key berbeda untuk setiap proyek: key anon (juga disebut publishable key di proyek yang lebih baru) dan key service_role. Keduanya adalah JSON Web Token yang ditandatangani oleh JWT secret proyek Anda. Perbedaannya adalah claim role yang dipanggang ke dalam payload JWT โ anon untuk key publik, service_role untuk kunci master. PostgREST, Supabase Storage, dan Supabase Auth semuanya beralih ke mode bypass-segalanya ketika mereka melihat claim service_role.
Decode key Supabase apa pun di jwt.io dan lihat payload-nya. Bentuk JWT service-role tidak salah lagi:
Payload yang ter-decode dari JWT service-role (ditampilkan sebagai blok dengan syntax highlight di bawah).
{
"iss": "supabase",
"ref": "[project-ref]",
"role": "service_role",
"iat": 1700000000,
"exp": 2000000000
}Proyek Supabase yang lebih baru menerbitkan key bergaya rahasia dengan prefix sb_secret_ alih-alih JWT. Perilakunya identik โ apa pun yang membawa sb_secret_ di bundle publik sama-sama katastrofis.
Bagaimana AI coding tools membocorkan service role key
Kami telah melihat tiga pola yang sama di ribuan aplikasi vibe-coded. Masing-masing dimulai dengan pengembang meminta bantuan AI tool dan berakhir dengan service key ter-inline ke dalam bundle.
Pola 1: File .env tunggal dengan prefix NEXT_PUBLIC_
Pengembang meminta AI tool untuk "menyiapkan Supabase" dan menerima satu .env dengan kedua key. AI tool โ dilatih pada korpus di mana sebagian besar environment variable diekspos via NEXT_PUBLIC_* โ memberi prefix NEXT_PUBLIC_ pada keduanya. Next.js meng-inline apa pun yang cocok dengan prefix itu ke dalam bundle klien pada build time. Kirim ke Vercel, dan service key ada di main.[hash].js.
Pola 2: Key salah dalam panggilan createClient
Pengembang menempelkan kedua key ke file config.ts yang dihasilkan AI, dan AI mengisi panggilan createClient() sisi browser dengan process.env.SUPABASE_SERVICE_ROLE_KEY karena keliru. Build menarik variabel itu, dan JWT mendarat di bundle.
Pola 3: Service role key di-hardcode di skrip seed
Pengembang meminta AI tool untuk menulis skrip yang men-seed database. AI meng-hardcode service role key langsung ke dalam file (alih-alih membaca dari environment), commit file ke repositori, dan repo GitHub publik atau route /scripts/seed.js aplikasi yang ter-deploy sekarang menyajikan key.
Cara scan bundle FixVibe mendeteksi kebocoran
Check bundle-secrets FixVibe mengunduh setiap file JavaScript yang direferensikan oleh aplikasi yang ter-deploy โ entry chunk, lazy-loaded chunk, web worker, service worker โ dan menjalankannya melalui detektor yang men-decode apa pun yang cocok dengan bentuk JWT (eyJ[base64-header].eyJ[base64-payload].[signature]). Jika payload yang ter-decode berisi "role": "service_role", scan melaporkannya sebagai temuan kritis dengan path file dan baris persis di mana key muncul. Check yang sama juga mencocokkan pola sb_secret_* yang lebih baru berdasarkan prefix.
Scan tidak pernah berautentikasi dengan key yang ditemukan. Ia mengidentifikasi bentuk dan melaporkan kebocoran โ menggunakan key untuk membuktikan eksploitabilitas akan menjadi akses tidak sah ke database Anda. Buktinya ada di payload JWT itu sendiri.
Terdeteksi โ apa yang harus dilakukan di jam pertama
Service role key yang bocor adalah keadaan darurat runtime. Asumsikan key telah di-scrape โ penyerang memantau bundle publik secara real time. Perlakukan database sebagai terkompromi sampai Anda telah merotasi key dan mengaudit aktivitas terkini.
- Rotasi key segera. Di Dashboard Supabase, masuk ke Project Settings โ API โ Service role key โ Reset. Key lama diinvalidasi dalam hitungan detik. Setiap kode sisi server yang menggunakan key harus diperbarui dan di-deploy ulang sebelum rotasi mendarat.
- Audit aktivitas database terkini. Buka Database โ Logs di dashboard. Filter pada 7 hari terakhir. Cari query
SELECT *tidak biasa terhadap tabel dengan PII, statementUPDATEatauDELETEbesar, dan request dari IP di luar infrastruktur yang Anda kenal. Supabase mencatat headerx-real-ippada setiap request. - Periksa objek storage. Kunjungi Storage โ Logs dan tinjau unduhan file terkini. Service role key yang bocor memberikan akses bypass-segalanya ke bucket privat juga.
- Hapus key dari source control. Bahkan setelah rotasi, meninggalkan JWT di history git Anda berarti ia dapat ditemukan di repo publik. Gunakan
git filter-repoatau BFG Repo-Cleaner untuk membersihkannya dari history, kemudian force-push (peringatkan kolaborator terlebih dahulu). - Scan ulang setelah perbaikan. Jalankan scan FixVibe baru terhadap aplikasi yang di-deploy ulang. Temuan bundle-secrets seharusnya hilang. Konfirmasi tidak ada JWT
service_roledan tidak ada stringsb_secret_*yang tersisa di chunk mana pun.
Mencegah kebocoran sejak awal
Perbaikan struktural adalah disiplin penamaan ditambah pengaman di tingkat tool:
- Jangan pernah memberi prefix service key dengan
NEXT_PUBLIC_*,VITE_*, atau prefix bundle-inlining lainnya. Konvensi penamaan adalah batasnya โ setiap framework menghormatinya. - Jauhkan service key sepenuhnya dari
.envdi mesin pengembang. Baca dari secret manager (Doppler, Infisical, env vars terenkripsi Vercel) saat deploy, jangan pernah commit secara lokal. - <strong>Mark every Supabase client construction with explicit context.</strong> Files named <code>supabase/browser.ts</code> use the anon key; files named <code>supabase/server.ts</code> use the service-role key with <code>import 'server-only'</code> at the top. The <code>server-only</code> import causes a build error if a client component tries to consume the module.
- <strong>Add a pre-commit hook that greps for JWT-shaped strings.</strong> <code>git diff --staged | grep -E 'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+'</code> catches both anon and service tokens before they leave your machine.
- Tambahkan gate CI yang men-scan output build. Setelah
next build, grep output.next/static/chunks/untuk stringservice_role. Gagalkan build jika ada yang cocok.
# Pre-commit hook: refuse any staged JWT-shaped string.
git diff --staged \
| grep -E 'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+' \
&& echo "JWT detected in staged changes โ refusing commit" \
&& exit 1
# CI gate: fail the build if "service_role" shipped to the static bundle.
grep -RE 'service_role|sb_secret_' .next/static/chunks/ \
&& echo "Service-role credential leaked into bundle" \
&& exit 1Pertanyaan yang sering diajukan
Seberapa cepat penyerang benar-benar menemukan service-role key Supabase yang bocor?
Scanner bundle publik menjelajahi deployment baru dalam hitungan menit. Peneliti telah mendokumentasikan eksploit yang berfungsi terhadap proyek Supabase baru dalam waktu kurang dari satu jam sejak deploy pertama. Perlakukan setiap eksposur service-role sebagai jendela 60 menit, bukan 60 hari.
Apakah merotasi key cukup, atau saya harus mengasumsikan eksfiltrasi data?
Rotasi menginvalidasi key yang bocor tetapi tidak membatalkan data yang sudah ditarik. Jika tabel Anda berisi PII, data pembayaran, atau data yang diatur, Anda mungkin memiliki kewajiban pemberitahuan di bawah GDPR (72 jam), CCPA, atau HIPAA. Audit log dan konsultasikan dengan penasihat hukum jika audit menunjukkan akses mencurigakan.
Dapatkah RLS melindungi saya jika service-role key bocor?
Tidak. Row-Level Security sepenuhnya di-bypass oleh claim service_role. Itu disengaja โ key ada justru untuk membiarkan kode backend melewati RLS untuk operasi admin. Mitigasinya adalah memastikan key tidak pernah mencapai konteks di mana penyerang dapat membacanya.
Apakah ini berlaku untuk model publishable / secret key Supabase yang baru (<code>sb_publishable_</code> / <code>sb_secret_</code>)?
Ya โ kelas risiko yang identik. Key sb_secret_* adalah format secret-key baru yang menggantikan JWT service-role untuk proyek yang lebih baru. Apa pun yang membawa sb_secret_* di bundle sama katastrofisnya dengan JWT service-role yang bocor. Detektor bundle-secrets FixVibe mencocokkan kedua bentuk.
Bagaimana dengan key anon / publishable โ apakah aman di bundle?
Ya, secara desain. Anon key dimaksudkan untuk hidup di browser dan adalah yang digunakan setiap klien web Supabase. Keamanannya sepenuhnya bergantung pada RLS yang dikonfigurasi dengan benar pada setiap tabel publik. Lihat artikel Scanner RLS Supabase untuk apa yang harus diperiksa.
Langkah berikutnya
Jalankan scan FixVibe terhadap URL produksi Anda โ check bundle-secrets gratis, tanpa pendaftaran, dan melaporkan eksposur service_role dalam waktu kurang dari semenit. Pasangkan ini dengan artikel Scanner RLS Supabase untuk memverifikasi lapisan RLS bekerja dengan baik, dan Checklist keamanan bucket storage Supabase untuk mengunci akses file. Untuk latar belakang mengapa AI tools menghasilkan kelas kebocoran ini dengan begitu andal, baca Mengapa AI coding tools meninggalkan celah keamanan.
