Prompt Injection pada Coding Agent: Risiko dan Pertahanan
Pahami bagaimana teks berbahaya dari file, pull request, web, dan tool menyusup ke coding agent di server, lalu pilih pertahanan yang benar-benar mengurangi dampaknya.
Apa yang dimaksud dengan prompt injection terhadap coding agent
Prompt injection terhadap coding agent mudah dijelaskan: teks yang dibaca agent diperlakukan sebagai instruksi yang harus diikuti agent. Agent membuka file, komentar pull request, halaman web, atau hasil pemanggilan tool. Semua itu diterima sebagai jenis teks yang sama seperti permintaan Anda. Jika penyerang mengendalikan salah satu teks tersebut, penyerang dapat menulis ke dalam sesi Anda.
Setiap produk agent saat ini memiliki sifat tersebut. Model menerima satu rangkaian token. Permintaan Anda, system prompt, isi file, dan hasil tool digabungkan, lalu model memprediksi teks berikutnya. Tidak ada bit hak akses pada token. Tidak ada penanda dalam format yang menunjukkan bagian mana yang Anda otorisasi dan bagian mana yang berasal dari file README milik orang yang tidak dikenal.
Halaman ini menjelaskan model ancamannya: bagaimana teks yang dikendalikan penyerang mencapai agent yang berjalan pada server, apa yang dapat diperoleh penyerang pada setiap titik, dan pertahanan mana yang sepadan dengan upayanya. Panduan containment dalam panduan kami yang lain hanya dapat dipahami setelah Anda mengetahui apa yang harus dilindungi dari agent.
Mengapa model tidak dapat memisahkan konten dari instruksi
Pelatihan membantu, tetapi tidak menyelesaikan masalah ini. Model saat ini dilatih untuk memperlakukan teks yang diambil dengan kecurigaan, dan model menolak banyak upaya sederhana. Penolakan adalah probabilitas, bukan aturan. Penyerang dapat mengubah susunan kata, mencoba lagi, dan menyembunyikan teks dalam format yang tidak pernah diperkirakan siapa pun. Tidak ada batasan mengenai berapa banyak susunan kata yang dapat mereka coba.
Proyek OWASP GenAI mencatat masalah ini sebagai LLM01:2025 Prompt Injection dan membaginya menjadi dua jenis. Injeksi langsung adalah prompt pengguna sendiri yang mengubah perilaku model. Injeksi tidak langsung adalah konten eksternal, seperti situs web atau file, yang mengubah perilaku model saat konten tersebut diproses. Injeksi tidak langsung adalah jenis yang penting pada server karena agent membaca jauh lebih banyak teks daripada yang Anda ketikkan.
Studi sistematis pertama adalah karya Greshake dan rekan-rekannya, Not what you've signed up for (2023). Kesimpulan mereka adalah kalimat yang perlu diingat: ketika aplikasi memasukkan teks yang diambil ke dalam model yang dapat memanggil tool, pemrosesan teks tersebut mendekati eksekusi kode arbitrer.
Kondisi yang mengubah pembacaan menjadi kebocoran
Membaca teks berbahaya tidak dengan sendirinya menyebabkan kerusakan. Kerusakan memerlukan jalur untuk keluar dari mesin.
Simon Willison menamai kombinasi tersebut the lethal trifecta pada Juni 2025. Agen yang menyimpan data privat, terpapar konten yang tidak tepercaya, dan dapat mengirim data ke luar dapat dibujuk untuk mengeluarkan data pertama melalui jalur ketiga.
Coding agent pada VPS Anda memiliki semua kondisi tersebut sejak awal. Data privatnya adalah source code, file .env, kunci SSH, dan shell history Anda. Konten yang tidak tepercaya mencakup setiap repository, halaman, dan hasil tool yang dibacanya. Jalur keluarnya adalah git push, curl, npm publish, isi pull request, atau tautan yang ditampilkan di terminal dan Anda klik.
Anda tidak dapat menghilangkan kondisi kedua, karena membaca teks yang tidak tepercaya adalah tugas yang Anda berikan kepada agent. Jadi, setiap pertahanan praktis berfokus pada dua kondisi lainnya.
Tempat teks yang tidak tepercaya menjangkau coding agent pada server
Repositori yang digunakan agent
Setiap file dalam checkout adalah input. Komentar sumber, README.md, changelog, fixture pengujian, kode vendored, dan file instruksi agent itu sendiri: CLAUDE.md, AGENTS.md, serta padanannya. Agent yang diminta memahami codebase akan membacanya, karena itulah yang Anda minta.
Dalam situasi ini, penyerang memperoleh akses ke semua orang yang melakukan clone repositori lalu mengarahkan agent ke repositori tersebut. File instruksi adalah jalur paling langsung karena file itu memang dibuat untuk dibaca sebagai instruksi. Pull request yang menambahkan empat baris berguna ke CLAUDE.md dan satu baris yang mengalihkan agent dapat terlewat oleh reviewer manusia yang hanya memindainya sekilas.
Issue, pull request, dan komentar code review
Apa pun yang dapat diketik orang asing ke tracker Anda akan menjangkau agent segera setelah Anda memintanya melakukan triase. Pada May 2025, Invariant Labs menerbitkan temuan GitHub MCP dengan pola yang persis seperti ini. Agent milik seorang developer memiliki akses ke satu repositori publik dan beberapa repositori privat. Penyerang membuat issue di repositori publik tersebut. Ketika developer meminta agent memeriksa issue yang terbuka, agent membaca isi repositori privat lalu menuliskannya ke pull request di sisi publik.
Laporan tersebut menjelaskan masalah arsitektur, bukan cacat kode pada MCP server. Agent memiliki satu access token dengan cakupan luas, membaca dari inbox publik, dan memiliki izin untuk menulis. Tidak ada konfigurasi yang salah dalam pengertian umum. Karena itu, solusinya adalah membatasi cakupan akses, bukan melakukan patch.
Halaman web yang diambil agent
Dokumentasi, jawaban forum, halaman vendor, dan hasil pencarian. Semua itu dapat memuat teks yang ditulis untuk agent, bukan untuk Anda. HTML yang dikonversi menjadi teks memberi penyerang ruang tambahan karena konten yang tidak pernah ditampilkan browser tetap dapat menjangkau model.
Penyerang memperoleh kendali saat agent paling sedikit diawasi. Tidak ada yang membaca seluruh teks halaman yang diambil agent ketika mencari informasi.
Output tool MCP
MCP (model context protocol) adalah cara umum bagi agent untuk terhubung ke tool eksternal. Hasilnya dikembalikan sebagai teks dan langsung masuk ke context window. Ada dua permukaan di sini, bukan satu. Data yang dikembalikan tool adalah permukaan yang jelas. Nama dan deskripsi tool itu sendiri, yang dibaca model untuk menentukan kapan tool tersebut harus dipanggil, adalah permukaan lainnya. Server yang tidak Anda kendalikan dapat mengubah salah satunya di antara pemanggilan.
Penyerang yang memasukkan teks ke output satu tool dapat menjangkau semua tool lain yang dimiliki agent. Dengan cara ini, injection pada sesuatu yang bernilai rendah dapat berakhir dengan mengendalikan sesuatu yang bernilai tinggi.
Log CI, output build, dan metadata dependency
npm install mencetak teks dari package yang tidak Anda tulis. Kegagalan pengujian mencetak pesan assertion dari library. Log continuous integration (CI) berisi ribuan baris output pihak ketiga. Jika Anda meminta agent memperbaiki build yang gagal, agent akan membaca seluruh output tersebut.
Dalam situasi ini, penyerang memperoleh akses ke mesin build. Mesin ini biasanya menyimpan kredensial deployment dan token registry, tetapi lebih jarang diperhatikan dibandingkan laptop.
Hal yang benar-benar diperoleh penyerang
Ada empat hasil yang perlu direncanakan.
Pencurian kredensial. Apa pun yang dapat dibaca oleh proses agent termasuk dalam cakupan: variabel lingkungan, ~/.aws/credentials, ~/.ssh, token gh, atau file konfigurasi Docker. Pengiriman data tersebut tidak memerlukan curl. Commit ke branch, deskripsi pull request, package yang dipublikasikan ke registry, atau pencarian DNS untuk nama yang dikendalikan penyerang semuanya dapat memindahkan data keluar dari server.
Perubahan kode yang Anda setujui. Menulis kode adalah tugas agent. Karena itu, membuat agent menulis satu baris yang secara halus salah merupakan hasil yang paling mudah dicapai. Contohnya, menambahkan dependency atau pemanggilan logging yang membawa token ke dalam log yang Anda kirim ke tempat lain.
Persistensi. File yang ditulis sekali dapat terus berjalan tanpa melibatkan model: hook di .git/hooks, script postinstall di package.json, baris yang ditambahkan ke file startup shell, atau baris tambahan di CLAUDE.md. Perintah berikutnya akan menjalankannya.
Pergerakan di dalam jaringan Anda. Agent berjalan di tempat Anda menjalankannya. Jika server tersebut dapat mengakses database melalui loopback, service administrasi internal, metadata service milik cloud provider Anda, atau host lain di jaringan privat, maka apa pun yang mengendalikan agent juga dapat mengaksesnya.
Mode persetujuan otomatis menghapus pemeriksaan terakhir
Dalam mode default, Claude Code meminta persetujuan sebelum menjalankan perintah atau mengedit file. Permintaan tersebut merupakan pemeriksaan oleh manusia yang berada di antara setiap permukaan risiko di atas dan tindakan nyata. Mode yang menghapus permintaan tersebut juga menghapus pemeriksaannya.
Dokumentasi menyatakan dengan jelas tentang bypassPermissions: gunakan hanya di lingkungan terisolasi seperti container atau VM, tempat Claude Code tidak dapat menimbulkan kerusakan. Auto mode lebih longgar dan menyetujui panggilan tool secara otomatis, dengan pemeriksaan keselamatan di latar belakang yang memverifikasi bahwa tindakan sesuai dengan permintaan Anda. Pemeriksaan tersebut mendeteksi banyak masalah. Namun, pemeriksaan itu tetap merupakan penilaian model terhadap output model. Karena itu, perlakukan sebagai filter, bukan sebagai batasan.
Administrator dapat menghapus keduanya. Atur permissions.disableBypassPermissionsMode atau permissions.disableAutoMode ke "disable" dalam file settings, lalu tempatkan file tersebut di managed settings agar project yang di-check out tidak dapat menimpanya. Panduan kami tentang auto mode dan aturan izin Claude Code menjelaskan kapan setiap aturan berlaku.
Pertahanan, diurutkan berdasarkan manfaatnya
Tidak satu pun dari langkah ini merupakan perbaikan menyeluruh. Masing-masing hanya membatasi apa yang dapat diakses agen atau tindakan yang dapat dilakukannya.
- Mesin yang dapat Anda hancurkan dan bangun ulang, sehingga insiden keamanan hanya menghabiskan waktu satu jam, bukan menimbulkan insiden besar.
- Kredensial yang terpisah dari kredensial Anda, dibatasi untuk satu repositori, dan berumur pendek.
- Tidak ada secret berumur panjang di environment yang diwarisi oleh perintah agen.
- Penegakan sistem operasi pada egress jaringan dan akses file, yang berlaku untuk setiap proses yang dimulai agen.
- Prompt persetujuan tetap diaktifkan untuk operasi tulis dan pemanggilan jaringan.
- Hook sebagai lapisan cadangan deterministik untuk tindakan tertentu yang dapat Anda tentukan.
- Membaca diff sebelum menggabungkannya.
Urutan ini penting. Item 1 sampai 4 tetap berlaku meskipun model sepenuhnya berada di bawah kendali penyerang. Item 5 sampai 7 bergantung pada perhatian manusia, yang justru biasanya berhenti dilakukan saat agen berjalan lama.
Tempatkan agen pada mesin yang dapat dibuang
VPS yang hanya menyimpan checkout dan satu token terbatas merupakan target yang jauh lebih kecil daripada laptop yang menyimpan key Anda. Jalankan agen sebagai user tidak berprivilege khusus, bukan sebagai akun login Anda dan bukan sebagai root. Panduan kami tentang VM sekali pakai untuk coding agent dan user dengan hak akses minimal pada VPS membahas penyiapannya, sedangkan menjalankan Claude Code dengan aman pada VPS membahas penggunaannya sehari-hari.
Keluarkan secret dari environment
Environment variable dapat dibaca oleh setiap proses turunan, yang berarti dapat dibaca oleh setiap perintah yang dijalankan agen. Sandbox Claude Code dapat menghapus variable tertentu sebelum setiap perintah yang dijalankan dalam sandbox. Di Linux, sandbox memerlukan dua package terlebih dahulu:
sudo apt-get install bubblewrap socatKemudian di ~/.claude/settings.json:
{
"sandbox": {
"enabled": true,
"network": {
"allowedDomains": ["github.com", "*.npmjs.org"]
},
"credentials": {
"envVars": [
{ "name": "GITHUB_TOKEN", "mode": "deny" },
{ "name": "NPM_TOKEN", "mode": "deny" }
]
}
}
}Entri deny menghapus variable tersebut sebelum setiap perintah dalam sandbox dijalankan, dan allowedDomains membatasi perintah dalam sandbox ke host yang Anda cantumkan. Blok credentials memerlukan Claude Code v2.1.187 atau yang lebih baru, berdasarkan pemeriksaan pada August 2026. Jalankan /sandbox dalam sebuah session untuk melihat layer yang aktif dan dependency yang masih hilang. Menentukan secret mana yang memang perlu tersedia di mesin tersebut merupakan bagian yang lebih besar dari pekerjaan ini, dan menjauhkan secret dari jangkauan AI agent membahasnya secara mendalam.
Batasi egress jaringan pada sistem operasi
Aturan firewall tidak memedulikan keputusan model. Jalankan agen sebagai user agent khusus, lalu blokir data yang dikirim user tersebut:
table inet agentcage {
chain output {
type filter hook output priority filter; policy accept;
meta skuid "agent" ct state established,related accept
meta skuid "agent" oif lo accept
meta skuid "agent" counter drop
}
}Dengan demikian, user agent hanya memiliki akses loopback. Trafiknya harus melewati proxy yang Anda jalankan pada mesin yang sama, dan proxy tersebut menyimpan allowlist hostname. Dengan https_proxy diarahkan ke proxy itu, client mengirim request CONNECT dan proxy melakukan name lookup. Dengan demikian, agen tidak memerlukan DNS outbound (domain name system) sendiri. Periksa hasilnya dengan sudo nft list ruleset dan pantau counter pada aturan drop meningkat saat agen mencoba mengakses sesuatu yang baru.
Biarkan session SSH kedua tetap terbuka saat menerapkan perubahan firewall. Periksa juga cara container runtime Anda memperlakukan aturan ini: Docker menulis chain-nya sendiri, dan port Docker yang dipublikasikan melewati ufw menjelaskan kejutan yang ditimbulkannya.
Hook: pemeriksaan yang tidak dapat dibantah oleh model
Aturan permission dan hook ditegakkan oleh Claude Code, bukan oleh model. Dokumentasi menjelaskannya secara tegas: instruksi dalam prompt atau CLAUDE.md memengaruhi tindakan yang coba dilakukan Claude, tetapi tidak mengubah tindakan yang diizinkan Claude Code. Perbedaan ini merupakan nilai utamanya. Baris dalam CLAUDE.md yang berisi "jangan pernah menjalankan curl" hanyalah saran yang dapat dibantah oleh paragraf hasil injection. Hook adalah proses yang mengembalikan exit code.
Daftarkan hook PreToolUse di .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/no-egress.sh"
}
]
}
]
}
}Hook menerima tool call dalam format JSON melalui standard input. Exit code 2 memblokir call dan menampilkan alasan dari standard error kepada Claude. Exit code 0 memungkinkan call berlanjut melalui alur permission normal.
#!/usr/bin/env bash
# PreToolUse: stdin holds the tool call, exit 2 blocks it.
cmd=$(jq -r '.tool_input.command // ""')
if printf '%s' "$cmd" | grep -qE '(^|[;&|]|\s)(curl|wget|nc|ncat)(\s|$)'; then
echo "Blocked: this repository does not allow outbound network commands." >&2
exit 2
fi
exit 0Sekarang bagian yang perlu dipahami. Ini adalah denylist untuk string shell, dan denylist semacam itu memiliki celah. python3 -c dapat membuka socket tanpa menggunakan kata curl. Target make deploy dapat menyembunyikan call yang sama satu tingkat lebih dalam. Tulis hook untuk kesalahan yang dapat Anda tentukan, lalu tempatkan batasan yang benar-benar Anda andalkan di kernel atau pada jaringan.
Aturan permission deny memiliki batasan pencocokan yang perlu diketahui. Aturan deny Read dan Edit mencakup file tool milik Claude sendiri serta perintah file yang dikenali di Bash, seperti cat, head, tail, dan sed. Aturan tersebut tidak mencakup script Python atau Node yang membuka file secara langsung. Aturan dievaluasi dengan urutan deny terlebih dahulu, lalu ask, kemudian allow. Karena itu, aturan deny tidak dapat memiliki pengecualian allowlist.
{
"permissions": {
"deny": [
"Read(.env)",
"Read(./secrets/**)",
"Bash(git push *)"
]
}
}Pantau data yang keluar dan baca diff
Eksekusi agen menghasilkan diff dan serangkaian pemanggilan jaringan. Keduanya perlu diperiksa sebelum sesuatu digabungkan atau di-deploy. Pemeriksaan keamanan mandiri pada diff mendeteksi jenis perubahan yang berbeda dari pemeriksaan singkat oleh manusia, sedangkan mengetahui data yang dikirim coding agent dari mesin membantu Anda memahami bentuk trafik normal sehingga request yang tidak biasa dapat segera terlihat.
Hal yang masih belum terselesaikan
Saat ini belum ada pemisahan yang andal antara konten dan instruksi. Setiap pertahanan yang dirilis berupa filter dengan tingkat kegagalan tertentu atau pembatasan dampak. Tidak ada bagian dalam tumpukan yang menandai rentang teks sebagai data yang tidak boleh dipatuhi dalam keadaan apa pun.
Filter memang membantu, tetapi juga dapat gagal. Classifier yang mendeteksi sebagian besar upaya prompt injection tetap harus selalu benar, sedangkan penyerang hanya perlu benar satu kali. Asimetri ini membuat tingkat keberhasilan pertahanan yang dipublikasikan menjadi titik awal untuk upaya berikutnya, bukan jaminan.
Pekerjaan yang paling menjanjikan berada pada tingkat desain, bukan tingkat model. CaMeL, dari Defeating Prompt Injections by Design (Debenedetti dan rekan-rekan, 2025), terlebih dahulu mengekstrak alur kontrol dan alur data dari request tepercaya. Dengan demikian, data tidak tepercaya tidak dapat mengubah perilaku program. CaMeL kemudian menerapkan pemeriksaan capability saat tool dipanggil. Angka dari paper tersebut pada benchmark AgentDojo menunjukkan biaya pendekatan ini.
The data behind this chart
[
{
"label": "Undefended agent",
"tasks_solved_pct": 84
},
{
"label": "CaMeL",
"tasks_solved_pct": 77
}
]Agent tanpa perlindungan menyelesaikan 84 persen tugas. CaMeL menyelesaikan 77 persen tugas dengan jaminan keamanan. Angka tersebut adalah angka yang dipublikasikan dalam paper untuk satu benchmark, bukan pengukuran terhadap workload Anda. Selisih antara keduanya secara kasar menunjukkan biaya jaminan yang benar-benar berlaku saat ini.
Sebelum desain seperti itu tersedia dalam tools yang Anda gunakan setiap hari, anggap agent dapat mengalami compromise pada suatu waktu dan buat peristiwa itu tidak menimbulkan dampak berarti. Itulah alasan utama menggunakan mesin disposable, kredensial dengan cakupan terbatas, egress yang dikendalikan, serta kebiasaan membaca diff.
FAQ
Dapatkah saya menghentikan prompt injection dengan meminta agent mengabaikan instruksi dalam file?
Tidak. Kalimat tersebut berada dalam context window yang sama dengan serangan, sehingga bersaing dengan teks penyerang dalam posisi yang setara. Dokumentasi Claude Code menjelaskan batasnya dengan jelas: instruksi dalam prompt atau CLAUDE.md menentukan tindakan yang ingin dilakukan agent, tetapi tidak mengubah hal yang diizinkan oleh tool. Perlakukan file instruksi sebagai pernyataan maksud, lalu masukkan hal yang Anda andalkan ke dalam permission rules, hook PreToolUse, atau aturan firewall.
Apakah prompt injection benar-benar berisiko jika agent hanya mengakses repository saya sendiri?
Ya, karena repository Anda dipenuhi teks yang tidak Anda tulis. File README dependensi, URL dalam lockfile, test fixture, kode vendored, dan output npm install semuanya dapat masuk selama tugas biasa. Apa pun yang diambil dari issue tracker atau situs dokumentasi juga masuk dengan cara yang sama. Risikonya meningkat seiring banyaknya hal yang dibaca agent, dan agent yang berguna biasanya membaca banyak hal.
Apakah menjalankan agent dalam container dapat mengatasi masalah ini?
Tindakan tersebut membatasi dampak, dan hanya jika Anda juga mencabut kredensialnya. Container dengan SSH agent yang diteruskan, kredensial cloud dalam environment, dan akses jaringan tanpa pembatasan akan memberikan penyerang hampir semua hal yang dapat diakses oleh host. Manfaat utama container adalah filesystem yang dapat Anda hapus dan tempat yang bersih untuk menerapkan aturan egress. Padukan dengan token yang cakupannya dibatasi ke satu repository.
Perubahan tunggal apa yang paling mengurangi risiko?
Hapus kredensial berumur panjang dari environment yang diwarisi oleh command agent, lalu terapkan kebijakan egress default-deny pada mesin tersebut. Keduanya memutus kondisi ketiga dalam lethal trifecta: teks tetap dapat membajak agent, tetapi data yang dapat dijangkaunya tidak memiliki tujuan yang berguna. Approval prompt dan peninjauan diff juga membantu, tetapi keduanya bergantung pada manusia yang tetap waspada selama proses panjang. Karena itu, peringkatnya berada di bawah dua perubahan tersebut.