Tips & Tricks

7 Kasus Keamanan Gagal Claude Code | Insiden Nyata dan Pencegahan

Tujuh insiden keamanan nyata dengan Claude Code: kebocoran .env, penghapusan DB produksi, ledakan tagihan dan lainnya — dengan analisis penyebab dan kode pencegahan.

“Claude Code memang praktis, tapi rasanya agak menakutkan” — perasaan itu benar adanya. Alat yang powerful menimbulkan kecelakaan yang powerful juga.

Artikel ini membahas tujuh insiden keamanan nyata yang dapat terjadi saat mengembangkan dengan Claude Code, menjelaskan mengapa hal itu terjadi dan bagaimana mencegahnya dengan kode dan konfigurasi konkret. Belajarlah dari kesalahan orang lain sebelum menjadi kesalahan Anda sendiri.

Kasus 1: File .env Ter-push ke GitHub

Apa yang Terjadi

Seorang developer memberi instruksi kepada Claude Code: “Saya ingin meneruskan variabel lingkungan ke CI, tolong commit juga file .env-nya.” Claude Code dengan patuh menjalankan git add .env && git commit. Beberapa menit setelah push ke GitHub, sebuah crawler mendeteksi API key. Notifikasi Slack masuk: “Your API key has been exposed.”

Penyebab

  • .env tidak ada di .gitignore
  • Claude Code menjalankan instruksi “commit ini” secara literal
  • Pengguna menyetujui dialog konfirmasi tanpa berpikir

Kode Pencegahan

1. Otomatiskan setup keamanan saat membuat proyek

# scripts/init-security.sh — jalankan setiap kali membuat proyek
#!/bin/bash
cat >> .gitignore << 'EOF'

# === Keamanan: Jangan pernah commit ini ===
.env
.env.*
.env.local
!.env.example
*.pem
*.key
*-service-account.json
credentials.json
EOF

echo "✓ Pola pengecualian keamanan ditambahkan ke .gitignore"
git add .gitignore && git commit -m "security: add .gitignore patterns"

2. Scan sebelum commit dengan Hook

.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash(git add*)",
        "hooks": [{
          "type": "command",
          "command": "git diff --cached --name-only | grep -E '^\\.env' && echo '🚨 Anda akan meng-stage file .env! Batalkan!' && exit 1 || exit 0"
        }]
      }
    ]
  }
}

3. Pemulihan jika sudah ter-push

# Langkah 1: Rotasi API key segera (prioritas utama)

# Langkah 2: Hapus sepenuhnya dari riwayat git
git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch .env" \
  --prune-empty --tag-name-filter cat -- --all

# Langkah 3: Force push ke remote
git push origin --force --all

# Langkah 4: Bersihkan cache GitHub (hubungi juga GitHub Support)

Kasus 2: DROP TABLE Dijalankan di DB Produksi

Apa yang Terjadi

“Tabel ini sudah tidak dipakai, tolong hapus.” Claude Code menghasilkan dan menjalankan DROP TABLE old_users;. Masalahnya: itu terhubung ke DATABASE_URL produksi. Backup terbaru sudah tiga hari yang lalu. Data tiga hari lenyap.

Penyebab

  • .env yang sama digunakan bersama antara development dan production
  • Claude Code tidak dapat membedakan antara lingkungan
  • Pengguna dalam mode ask tetapi mengklik “OK” secara refleks

Kode Pencegahan

1. Pisahkan file .env sepenuhnya per lingkungan

.env.development   # ← pengembangan lokal, DB dummy
.env.staging       # ← staging, salinan produksi
.env.production    # ← produksi, dikelola manual, jangan pernah dibagikan

2. Sematkan pemeriksaan lingkungan dalam skrip

// scripts/db-migrate.mjs
const env = process.env.APP_ENV ?? "development";
const dbUrl = process.env.DATABASE_URL ?? "";

if (env === "production") {
  const readline = require("readline").createInterface({
    input: process.stdin, output: process.stdout
  });
  await new Promise((resolve) => {
    readline.question(
      `⚠️  Menghubungkan ke DB produksi (${dbUrl.split("@")[1]}).\nApakah Anda yakin ingin melanjutkan? (ketik yes): `,
      (answer) => {
        readline.close();
        if (answer !== "yes") { console.log("Dibatalkan."); process.exit(0); }
        resolve(undefined);
      }
    );
  });
}

3. Larang operasi produksi di CLAUDE.md

## 🚨 Pembatasan Lingkungan Produksi

Jika DATABASE_URL mengandung `prod`, `production`, atau `live`:
- Jangan pernah menjalankan DROP / TRUNCATE / DELETE (tanpa klausa WHERE)
- Selalu dapatkan konfirmasi pengguna sebelum migrasi
- Tampilkan perintah backup sebelum operasi destruktif apa pun

Kasus 3: File Penting Terhapus dengan rm -rf

Apa yang Terjadi

“Bersihkan direktori build/” — typo pada path menghasilkan rm -rf ./, menghapus seluruh proyek. File di luar git (konfigurasi lokal, kode eksperimen yang belum di-commit) hilang selamanya.

Penyebab

  • rm -rf adalah salah satu perintah paling berbahaya bagi Claude Code
  • Tidak ada tanda kutip ganda di sekitar path → perilaku buruk dengan path yang mengandung spasi
  • Pengguna menyetujui dengan ceroboh

Kode Pencegahan

// .claude/settings.json
{
  "permissions": {
    "deny": [
      "Bash(rm -rf /)",
      "Bash(rm -rf ~*)",
      "Bash(rm -rf .*)"
    ],
    "ask": [
      "Bash(rm -rf*)"
    ]
  }
}

Hook untuk menampilkan apa yang akan dihapus sebelum dieksekusi:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash(rm*)",
        "hooks": [{
          "type": "command",
          "command": "echo '⚠️ Perintah hapus terdeteksi. Menjalankan dalam 5 detik. Ctrl+C untuk membatalkan.' && sleep 5"
        }]
      }
    ]
  }
}

Kasus 4: API Key Ditulis Langsung di Prompt dan Diteruskan ke Subagent

Apa yang Terjadi

“Tolong posting ke Qiita menggunakan QIITA_TOKEN=abc123def456” — ditulis langsung di prompt dan didelegasikan ke subagent. Subagent dapat menulis konten ke log dan memori, dan token akhirnya tersimpan dalam file log di bawah .claude/.

Penyebab

  • Prompt dipertahankan sebagai riwayat percakapan
  • Prompt subagent juga tercatat dengan cara yang sama
  • Bahkan di lingkungan lokal, proses lain atau backup dapat mengekspos rahasia

Kode Pencegahan

Jangan pernah menulis rahasia di prompt — teruskan melalui variabel lingkungan

# ❌ Berbahaya
claude -p "Gunakan QIITA_TOKEN=abc123 untuk menjalankan qiita-publish.mjs"

# ✅ Aman: skrip membaca dari process.env
# Tulis QIITA_TOKEN=abc123 di .env, lalu
claude -p "Jalankan scripts/qiita-publish.mjs (token dibaca otomatis dari .env)"

Prinsip yang sama untuk instruksi subagent

// ❌ Berbahaya
Agent({ prompt: `Gunakan API key ${process.env.SECRET_KEY} untuk...` });

// ✅ Aman: hanya berikan nama key, skrip membaca nilainya
Agent({ prompt: "Gunakan variabel lingkungan SECRET_KEY untuk..." });

Kasus 5: Loop Retry API Tanpa Henti Meledakkan Tagihan

Apa yang Terjadi

“Coba ulang otomatis jika ada error” — skrip dengan penanganan error dihasilkan. Ketika sebuah error tidak dapat diselesaikan, retry tidak pernah berhenti: 3.000 panggilan API Anthropic dalam satu jam menghasilkan tagihan $200.

Penyebab

  • Tidak ada batas retry yang ditetapkan
  • Tidak ada exponential backoff — loop tanpa henti dengan interval 1 detik
  • Tidak ada alert tagihan yang dikonfigurasi

Kode Pencegahan

// utils/retry.ts — utilitas retry yang aman
export async function withRetry<T>(
  fn: () => Promise<T>,
  options = { maxAttempts: 3, baseDelayMs: 1000, maxDelayMs: 30000 }
): Promise<T> {
  let lastError: Error;

  for (let attempt = 1; attempt <= options.maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (err) {
      lastError = err as Error;
      if (attempt === options.maxAttempts) break;

      // Exponential backoff + jitter
      const delay = Math.min(
        options.baseDelayMs * Math.pow(2, attempt - 1) + Math.random() * 1000,
        options.maxDelayMs
      );
      console.warn(`Attempt ${attempt}/${options.maxAttempts} failed: ${err.message}`);
      console.warn(`Retrying in ${Math.round(delay / 1000)}s...`);
      await new Promise((r) => setTimeout(r, delay));
    }
  }

  throw new Error(`Gagal setelah ${options.maxAttempts} percobaan: ${lastError!.message}`);
}

Tentukan di CLAUDE.md:

## Aturan Wajib untuk Panggilan API
- Maksimal 3 retry
- Selalu implementasikan exponential backoff (1s → 2s → 4s)
- Jangan pernah membuat loop tanpa henti: while(true) + panggilan API dilarang

Kasus 6: git push --force Menghapus Commit Rekan Kerja

Apa yang Terjadi

“Timpa remote dengan kondisi lokal” — git push --force dijalankan. Tiga commit yang baru saja di-push oleh anggota tim hilang. Anggota tersebut juga tidak memiliki salinan lokal dari perubahan itu — kode hilang selamanya.

Penyebab

  • --force cenderung dijalankan tanpa memahami bahayanya
  • Claude Code dengan patuh menjalankan instruksi “timpa remote”
  • Developer tidak mengetahui alternatif yang lebih aman git push --force-with-lease

Kode Pencegahan

// .claude/settings.json
{
  "permissions": {
    "deny": [
      "Bash(git push --force *master*)",
      "Bash(git push --force *main*)",
      "Bash(git push -f *master*)",
      "Bash(git push -f *main*)"
    ]
  }
}

Tentukan alternatif aman di CLAUDE.md:

## Aturan Git yang Aman
- `git push --force` **dilarang**
- Gunakan `git push --force-with-lease` sebagai gantinya
  (ditolak otomatis jika orang lain telah push perubahan)
- Selalu dapatkan konfirmasi pengguna sebelum push langsung ke main/master

Kasus 7: Service Account dengan Hak Berlebihan Mengakses Semua Sumber Daya

Apa yang Terjadi

“Gunakan kunci service account GCP ini untuk mengoperasikan Cloud Storage.” Service account memiliki izin Owner. Claude Code terhubung tidak hanya ke Cloud Storage tetapi juga ke BigQuery, Cloud SQL, dan cluster GKE “untuk menginvestigasi” — menghasilkan biaya yang tidak terduga.

Penyebab

  • Service account memiliki izin berlebihan (pelanggaran prinsip hak minimum)
  • Claude Code memiliki kecenderungan agresif untuk menggunakan alat yang tersedia
  • Bahkan “untuk menginvestigasi” terdengar seperti alasan yang sah untuk akses luas

Kode Pencegahan

Buat service account dengan hak minimum:

# ❌ Hindari: izin Owner
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member="serviceAccount:[email protected]" \
  --role="roles/owner"

# ✅ Hanya izin minimum yang diperlukan
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member="serviceAccount:[email protected]" \
  --role="roles/storage.objectAdmin"
  # ← Hanya baca/tulis ke Cloud Storage

Definisikan cakupan akses secara eksplisit di CLAUDE.md:

## Pembatasan Akses GCP
Izin untuk service account yang digunakan dalam proyek ini:
- Cloud Storage: Baca/Tulis OK (bucket: my-project-assets saja)
- BigQuery: Dilarang
- Cloud SQL: Dilarang
- Sumber daya GCP lainnya: Dilarang

Tolak instruksi apa pun yang mencoba mengakses sumber daya di luar izin ini.

Daftar Periksa Komprehensif untuk Mencegah Insiden

Daftar periksa akhir yang disuling dari pola umum di ketujuh kasus.

### Pengaturan yang Harus Diterapkan Hari Ini (30 menit)
- [ ] Tambahkan pola .env ke .gitignore
- [ ] Tambahkan daftar deny ke .claude/settings.json (rm -rf, git push --force, DROP TABLE)
- [ ] Dokumentasikan pembatasan di CLAUDE.md

### Pemeriksaan Mingguan
- [ ] Tinjau git log untuk commit file yang tidak disengaja
- [ ] Verifikasi .env dikecualikan oleh .gitignore: `git check-ignore -v .env`
- [ ] Periksa tenggat waktu rotasi API key

### Respons Pertama terhadap Insiden
1. Segera cabut dan rotasi API key yang terpengaruh
2. Hapus dari riwayat git (filter-branch atau BFG)
3. Tinjau log akses untuk menentukan cakupan pelanggaran
4. Laporkan situasi kepada pemangku kepentingan

Ringkasan

Insiden Claude Code jarang disebabkan oleh “AI yang mengamuk” — hampir semua muncul dari manusia yang menunda konfigurasi keamanan.

KasusPenyebab UtamaPencegahan
Kebocoran .envTidak ada gitignoreScript init + Hook
Penghapusan DB produksiTidak ada pemisahan lingkungan.env terpisah + alur konfirmasi
Kecelakaan rm -rfTidak ada daftar denyKonfigurasi settings.json
Kebocoran keyDitulis di promptStandarkan ke env vars
Ledakan tagihanTidak ada batas retryUtilitas withRetry
Force pushTidak ada pengaturan larangandeny + force-with-lease
Akses hak berlebihanPelanggaran hak minimumBatasi peran IAM

Langkah pertama Anda hari ini: Menambahkan "deny": ["Bash(rm -rf*)"] ke .claude/settings.json saja sudah dapat mencegah salah satu kecelakaan paling destruktif yang mungkin terjadi.

Artikel Terkait

Referensi

#claude-code #security #incident #best-practices #devops

Tingkatkan alur kerja Claude Code kamu

50 template prompt yang sudah teruji, siap copy-paste ke Claude Code sekarang juga.

Gratis

PDF Gratis: Cheatsheet Claude Code dalam 5 Menit

Cukup masukkan emailmu dan kami akan langsung mengirim cheatsheet PDF A4 satu halaman.

Kami menjaga data pribadimu dengan aman dan tidak pernah mengirim spam.

Masa

Tentang Penulis

Masa

Engineer yang aktif menggunakan Claude Code. Mengelola claudecode-lab.com, media teknologi 10 bahasa dengan lebih dari 2.000 halaman.