Hardening Editor AI bukan soal menambah satu lapis proteksi, tetapi memisahkan jalur kepercayaan di aplikasi yang menggabungkan UI editor, webview, model AI, plugin, shell, file system, dan jaringan. Jika satu komponen bisa dipicu oleh prompt, file workspace, atau extension yang tidak tepercaya, maka token, sesi login, dan host developer ikut menjadi target.

Dalam konteks disclosure RCE di Cursor, pelajaran utamanya bukan detail beritanya, melainkan pola risikonya: editor AI modern sering berjalan sebagai aplikasi hybrid desktop-web dengan permission yang luas, akses ke secret developer, dan kemampuan mengeksekusi tool. Karena itu, hardening harus dimulai dari trust boundary, bukan hanya validasi input di permukaan.

Artikel ini fokus pada implementasi praktis untuk editor AI, IDE berbasis desktop-web, atau tool coding assistant yang dapat membaca file, memanggil model, menjalankan plugin, dan mengeksekusi command lokal.

Model ancaman: di mana permukaan serangannya?

Arsitektur editor AI biasanya memiliki beberapa jalur data yang mudah bercampur:

  • Prompt dan chat context: input dari user, file workspace, clipboard, terminal output, atau hasil tool.
  • Webview/UI: komponen frontend yang kadang menampilkan konten tidak tepercaya.
  • Plugin/extension: kode pihak ketiga dengan event hook, akses file, dan kadang akses shell.
  • Bridge desktop: lapisan IPC antara renderer/webview dan proses host.
  • Tool execution: shell command, git, package manager, formatter, linter, test runner.
  • Credential store: token AI provider, GitHub/GitLab token, SSH key, API key cloud, cookie sesi.
  • Network egress: koneksi ke API model, marketplace plugin, telemetry, dan endpoint lain.

Masalah utamanya adalah confused deputy: komponen yang dipercaya penuh mengeksekusi aksi atas nama input yang tidak tepercaya. Contohnya, prompt hasil baca file workspace memicu plugin untuk menjalankan shell, lalu shell membaca file sensitif atau mengekspor token ke jaringan.

Prinsip dasarnya: prompt, file project, extension, dan konten webview harus dianggap tidak tepercaya sampai dibuktikan sebaliknya. Jangan langsung mewariskan privilege host ke komponen tersebut.

Pemisahan trust boundary yang benar

1. Pisahkan domain UI, orkestrator, dan executor

Desain yang lebih aman membagi aplikasi menjadi tiga peran:

  • UI/Renderer: menampilkan editor, chat, dan hasil. Tidak boleh punya akses langsung ke shell, token mentah, atau file sensitif di luar workspace yang diizinkan.
  • Orchestrator: memutuskan tool mana yang boleh dipanggil, menerapkan policy, audit, rate limit, dan approval.
  • Executor sandbox: proses terpisah dengan permission minimal untuk menjalankan command, membaca file tertentu, atau melakukan network request yang diizinkan.

Dengan pemisahan ini, eksploitasi di layer UI atau prompt injection tidak otomatis berujung pada RCE penuh di host.

2. Jangan anggap IPC sebagai jalur internal yang aman

Pada aplikasi desktop-web hybrid, IPC sering menjadi titik lemah. Jangan menyediakan endpoint seperti runCommand(cmd) atau readFile(path) yang menerima input arbitrer dari renderer. Lebih aman memakai command object yang tervalidasi dan dibatasi policy.

// Anti-pattern: renderer dapat mengirim command arbitrer
ipc.handle('runCommand', async (_event, cmd) => {
  return exec(cmd)
})

// Lebih aman: gunakan action yang terstruktur dan divalidasi
ipc.handle('tool.invoke', async (_event, request) => {
  validateToolRequest(request)
  return toolGateway.invoke(request)
})

Validasi bukan hanya tipe data. Pastikan request cocok dengan capability yang telah diberikan, path berada di area yang diizinkan, dan argumen command tidak membuka escape ke shell.

3. Terapkan capability-based access

Jangan memberi plugin atau sesi AI hak akses global. Berikan capability token spesifik untuk satu aksi, satu ruang kerja, satu durasi, dan satu kelas resource.

Contoh capability yang baik:

  • fs.read:/workspace/project-a/src/**
  • fs.write:/workspace/project-a/tmp/**
  • net.connect:api.openai.com:443
  • tool.exec:git-status

Contoh capability yang buruk:

  • shell.exec:*
  • fs.read:/
  • net.connect:*

Penyimpanan secret dan token yang tidak mudah bocor

1. Pisahkan token pengguna, token aplikasi, dan token tool

Kesalahan umum adalah memakai satu token jangka panjang untuk semua kebutuhan: login, API AI, plugin marketplace, dan akses tool. Ini memperbesar dampak kompromi.

Minimal bedakan:

  • Session token user: untuk autentikasi UI/backend aplikasi.
  • Provider token: untuk memanggil model atau layanan eksternal tertentu.
  • Tool token: untuk integrasi seperti Git hosting, issue tracker, atau cloud API.
  • Ephemeral execution token: untuk satu aksi sensitif dengan TTL pendek.

Jika satu token bocor, penyerang tidak otomatis mendapat semua privilege.

2. Gunakan secure storage OS, bukan file plaintext

Untuk aplikasi desktop, simpan secret di mekanisme secure storage OS jika tersedia, bukan di file konfigurasi biasa, localStorage, atau cache yang mudah dibaca proses lain. Bila butuh cache lokal, simpan hanya referensi atau token terenkripsi dengan kunci yang tidak ditaruh berdampingan dalam bentuk mentah.

Hal yang sebaiknya dihindari:

  • Menulis API key ke file log.
  • Menyimpan refresh token di renderer/webview storage.
  • Mewariskan environment variable sensitif ke semua child process.
  • Mengirim token penuh ke plugin hanya untuk membaca identitas user.

3. Scoping sesi dan token

Session scoping berarti token hanya valid untuk konteks tertentu. Terapkan batas berikut:

  • Scope resource: hanya repo/workspace tertentu.
  • Scope aksi: read-only, write terbatas, atau execute subset tool.
  • Scope waktu: TTL pendek, terutama untuk aksi sensitif.
  • Scope asal: hanya bisa dipakai oleh proses tertentu atau channel IPC tertentu.

Jika editor memanggil backend internal untuk memperoleh token eksekusi, backend harus mengikat token pada policy yang eksplisit, bukan memberi bearer token generik yang bisa dipakai ulang di mana saja.

{
  "sub": "user-123",
  "workspace": "project-a",
  "capabilities": [
    "fs.read:src/**",
    "tool.exec:git-status",
    "tool.exec:git-diff"
  ],
  "ttl_seconds": 120,
  "aud": "local-executor"
}

Format di atas hanya ilustrasi. Intinya adalah token harus menyatakan batas akses yang sempit dan mudah diverifikasi.

Izin plugin/extension: default deny, bukan default trust

1. Desain permission model yang jelas

Plugin AI, extension editor, dan integrasi tool sering menjadi jalur tercepat ke privilege escalation. Terapkan model izin yang eksplisit dan bisa diaudit:

  • Akses file: read-only, write, path terbatas.
  • Akses jaringan: domain allowlist, blok localhost/internal network bila tidak perlu.
  • Eksekusi command: daftar tool yang diizinkan, tanpa shell arbitrer.
  • Akses credential: per-secret, bukan akses ke seluruh vault.
  • Hook event: batasi event sensitif seperti startup, file open, save, atau terminal output.

Permission harus tampil saat instalasi atau saat pertama kali dipakai, dan perubahan scope harus memerlukan persetujuan baru.

2. Hindari plugin berjalan di proses utama

Menjalankan extension di proses utama aplikasi membuat setiap bug parser, XSS di webview, atau bug extension memiliki dampak yang besar. Lebih aman menjalankan plugin di proses terpisah atau sandbox dengan IPC yang ketat.

3. Review permission transitive

Plugin yang tampak hanya butuh akses file bisa menjadi berbahaya jika ia juga dapat memanggil plugin lain atau memanfaatkan executor umum. Pastikan permission tidak menjadi transitive tanpa kontrol. Jika plugin A hanya boleh membaca file, plugin A tidak boleh memicu plugin B yang dapat menjalankan shell atas nama A.

Validasi input prompt, file, dan hasil tool

1. Anggap prompt injection sebagai masalah kontrol alur

Prompt injection bukan hanya masalah kualitas jawaban model. Dalam editor AI, prompt injection dapat menjadi pemicu aksi sistem. Instruksi berbahaya dapat datang dari:

  • README, komentar kode, atau file konfigurasi di repository.
  • Issue, pull request, atau commit message.
  • Terminal output atau stack trace.
  • Dokumen yang diunduh atau hasil browsing.

Karena itu, jangan pernah mengikat aksi sensitif langsung ke keluaran model tanpa lapisan policy dan approval.

2. Pisahkan data dan instruksi

Jika file workspace dimasukkan ke konteks model, tandai sebagai untrusted content. Sistem sebaiknya memisahkan:

  • Instruksi sistem: policy internal yang tidak bisa diubah oleh konten luar.
  • Data kerja: file, issue, output tool, yang boleh dianalisis tetapi tidak boleh otomatis menjadi otoritas.
  • Rencana aksi: representasi terstruktur yang wajib diverifikasi policy engine.

Pola yang lebih aman adalah model menghasilkan tool plan terstruktur, lalu orchestrator memeriksa setiap langkah sebelum eksekusi.

{
  "action": "tool.exec",
  "tool": "git-status",
  "args": [],
  "reason": "Memeriksa perubahan workspace sebelum menyarankan patch"
}

Bandingkan dengan pendekatan berbahaya: model menghasilkan string shell lengkap yang langsung dieksekusi.

3. Validasi path dan konten file

Setiap permintaan akses file harus lolos pemeriksaan:

  • Normalisasi path dan cegah traversal seperti ../.
  • Tolak symlink yang keluar dari root workspace jika tidak diizinkan.
  • Bedakan file teks biasa dari binary, device file, socket, atau named pipe.
  • Batasi ukuran file, jumlah file, dan kedalaman scanning.

Bug umum terjadi saat aplikasi merasa aman karena path diawali root workspace, padahal setelah resolusi symlink target-nya keluar dari batas tersebut.

Sandbox proses, allowlist command, dan pembatasan shell/fs/network

1. Jangan beri akses shell umum jika yang dibutuhkan hanya beberapa tool

Banyak editor AI sebenarnya hanya perlu command tertentu seperti git status, git diff, formatter, atau test runner. Jika kebutuhan sempit, gunakan allowlist command alih-alih shell generik.

const ALLOWED_TOOLS = {
  'git-status': { bin: '/usr/bin/git', args: ['status', '--short'] },
  'git-diff':   { bin: '/usr/bin/git', args: ['diff', '--'] },
  'npm-test':   { bin: '/usr/bin/npm', args: ['test', '--', '--runInBand'] }
}

function invokeAllowedTool(name, extraArgs = []) {
  const spec = ALLOWED_TOOLS[name]
  if (!spec) throw new Error('tool not allowed')
  validateExtraArgs(name, extraArgs)
  return spawn(spec.bin, [...spec.args, ...extraArgs], {
    shell: false,
    stdio: ['ignore', 'pipe', 'pipe'],
    env: minimalEnv()
  })
}

Intinya bukan bahas bahasa pemrograman tertentu, melainkan pola berikut:

  • shell: false untuk menghindari ekspansi shell.
  • Gunakan path binary eksplisit bila mungkin.
  • Whitelist argumen tambahan per-tool, bukan regex longgar.
  • Kurangi environment variable yang diwariskan.

2. Jalankan executor dalam sandbox terpisah

Untuk aksi tool, gunakan proses terisolasi dengan pembatasan berikut sesuai platform dan kebutuhan:

  • User atau container terpisah dengan privilege minimal.
  • Root filesystem read-only bila memungkinkan.
  • Mount workspace secara terbatas, bukan seluruh home directory.
  • Network off secara default, lalu buka hanya domain tertentu.
  • Batas CPU, memori, waktu eksekusi, dan jumlah proses.

Pada praktiknya, tingkat isolasi dipilih berdasarkan kebutuhan produk. Sandbox berat memberi proteksi lebih baik, tetapi menambah biaya integrasi, kompatibilitas tool, dan kompleksitas debugging. Untuk editor desktop, kompromi yang umum adalah executor proses terpisah + policy ketat + network/file restrictions.

3. Blok akses ke lokasi sensitif

Walau tool perlu membaca workspace, hampir tidak pernah ada alasan untuk mengakses lokasi berikut tanpa persetujuan eksplisit:

  • Direktori home penuh pengguna.
  • Folder SSH dan GPG.
  • Credential store, file cloud config, token cache, dan browser profile.
  • Socket Docker daemon atau service lokal sensitif.
  • Metadata service cloud dan endpoint internal perusahaan.

Selain blok path, pertimbangkan juga blok hostname/IP privat untuk mencegah pivot ke resource internal.

Rate limit aksi sensitif, logging audit, dan kill switch fitur

1. Rate limit bukan hanya untuk API publik

Di editor AI, rate limit juga berguna untuk menahan penyalahgunaan lokal atau chain exploit. Batasi frekuensi:

  • Permintaan token baru.
  • Eksekusi tool sensitif.
  • Upaya akses file di luar scope.
  • Perubahan permission plugin.
  • Network egress ke domain yang jarang dipakai.

Rate limit memberi waktu untuk deteksi dan mengurangi dampak saat satu komponen mulai berperilaku abnormal.

2. Audit log harus cukup detail untuk forensik

Log yang berguna bukan hanya error stack. Simpan jejak berikut dengan sanitasi yang tepat:

  • Siapa atau komponen apa yang meminta aksi.
  • Capability apa yang dipakai.
  • Tool apa yang dieksekusi dan argumen ter-normalisasi.
  • Path file yang diakses setelah resolusi path.
  • Keputusan policy: allow, deny, require-approval.
  • Hash atau identifier sesi/token, bukan token mentah.

Jangan log secret mentah, isi file sensitif, atau prompt lengkap jika mengandung data rahasia. Pilih redaction yang konsisten agar log tetap berguna.

3. Sediakan kill switch

Jika ada temuan serius, tim perlu bisa mematikan fitur berisiko tanpa menunggu rilis penuh. Kill switch idealnya dapat:

  • Menonaktifkan auto-run tool.
  • Memblok plugin tertentu berdasarkan ID atau signature.
  • Mematikan network egress ke endpoint tertentu.
  • Menonaktifkan bridging API tertentu di renderer.
  • Memaksa mode read-only untuk AI assistant.

Kill switch harus dirancang agar gagal dengan aman. Jika config remote tidak bisa diambil, jangan default ke mode permisif.

Contoh arsitektur aman untuk editor AI

Komponen utama

  • Renderer/UI: menampilkan editor dan chat; tidak memegang secret mentah atau API shell umum.
  • Policy Engine: memutuskan izin berdasarkan user, workspace, plugin, dan capability.
  • Credential Broker: mengambil token dari secure storage dan mengeluarkan token sempit berumur pendek.
  • Tool Orchestrator: menerima rencana aksi terstruktur dari model, bukan command bebas.
  • Sandbox Executor: proses terisolasi untuk tool/file/network dengan batas resource.
  • Audit Logger: mencatat keputusan dan eksekusi penting.

Alur yang direkomendasikan

  1. User meminta AI menganalisis perubahan kode.
  2. Renderer mengirim permintaan ke orchestrator tanpa akses langsung ke shell.
  3. Model menghasilkan rencana aksi terstruktur, misalnya membaca file tertentu dan menjalankan git-status.
  4. Policy engine memeriksa apakah aksi sesuai capability sesi dan apakah perlu approval user.
  5. Credential broker, bila perlu, mengeluarkan token sempit berumur pendek untuk executor.
  6. Executor menjalankan tool dalam sandbox, dengan path, network, dan env yang dibatasi.
  7. Hasil tool dikembalikan ke orchestrator, ditandai sebagai data tidak tepercaya, lalu diringkas untuk UI.
  8. Audit log mencatat keputusan penting dan sumber permintaan.

Arsitektur ini bekerja karena setiap langkah punya otoritas sempit dan bisa diaudit. Tidak ada satu komponen tunggal yang menerima input tidak tepercaya sekaligus punya akses penuh ke host, token, shell, dan network.

Anti-pattern yang sering muncul

  • Renderer dapat memanggil shell langsung melalui IPC generik.
  • Satu token untuk semua fungsi dan berlaku lama.
  • Plugin dipercaya penuh setelah instalasi tanpa permission granular.
  • Auto-run tool berdasarkan keluaran model tanpa policy gate.
  • Path check berbasis string prefix tanpa resolusi symlink/canonical path.
  • Executor mewarisi seluruh environment host, termasuk secret CI/cloud.
  • Logging terlalu minim sehingga insiden sulit ditelusuri, atau terlalu berlebihan sampai membocorkan secret.
  • Kill switch tidak ada atau hanya bisa dipakai lewat update aplikasi penuh.

Checklist implementasi hardening editor AI

Trust boundary dan arsitektur

  • Renderer/webview tidak punya API shell atau FS arbitrer.
  • IPC memakai action terstruktur, bukan command string bebas.
  • Plugin berjalan di proses terpisah atau sandbox.
  • Model hanya mengusulkan rencana aksi, bukan mengeksekusi langsung.

Token dan session

  • Secret disimpan di secure storage OS atau mekanisme setara.
  • Token dipisah per fungsi: session, provider, tool, execution.
  • Token eksekusi berumur pendek, resource-scoped, action-scoped.
  • Child process tidak mewarisi environment sensitif secara default.

Plugin dan izin

  • Permission granular untuk file, network, command, dan secret.
  • Permission escalation memerlukan approval baru.
  • Plugin tidak dapat memanggil plugin lain untuk melewati policy.
  • Plugin ID, signature, dan provenance diverifikasi sesuai model distribusi yang dipakai.

Validasi input dan eksekusi

  • Semua path dinormalisasi dan dicek setelah resolusi symlink.
  • Command memakai allowlist dan shell: false bila relevan.
  • Network default deny, lalu allowlist domain yang perlu.
  • Workspace mount terbatas; home, SSH, credential store diblok.
  • Batas ukuran file, durasi proses, CPU, memori, dan jumlah proses diterapkan.

Operasional

  • Rate limit aksi sensitif dan issuance token diterapkan.
  • Audit log mencatat keputusan policy dan eksekusi penting.
  • Kill switch siap mematikan fitur berisiko.
  • Prosedur respons insiden untuk kebocoran token dan kompromi host sudah diuji.

Debugging dan verifikasi hardening

Uji skenario yang realistis

Jangan hanya menguji happy path. Simulasikan skenario seperti:

  • Repository berisi prompt injection di README atau komentar kode.
  • Plugin mencoba membaca file di luar workspace lewat symlink.
  • Tool mencoba melakukan network egress ke domain tak dikenal.
  • Renderer mengirim request IPC yang dimodifikasi secara manual.
  • Executor crash lalu restart dengan state yang salah atau permission melebar.

Tambahkan negative test

Untuk fitur keamanan, test yang paling penting sering justru memastikan operasi gagal sesuai harapan. Contoh:

  • Permintaan fs.read ke ~/.ssh harus ditolak.
  • Tool yang tidak ada di allowlist harus gagal dieksekusi.
  • Token kadaluarsa tidak boleh diterima executor.
  • Plugin tanpa permission network tidak boleh membuka koneksi keluar.

Langkah respons insiden bila token atau host developer terpapar

Jika ada indikasi kebocoran token, penyalahgunaan plugin, atau kompromi host developer, bertindak cepat lebih penting daripada investigasi yang sempurna di menit pertama.

1. Kontainmen segera

  • Aktifkan kill switch untuk mematikan auto-exec, plugin tertentu, atau bridge IPC berisiko.
  • Cabut atau suspend token yang mungkin terpapar.
  • Blok domain egress mencurigakan jika ada indikator exfiltration.
  • Isolasi host developer dari jaringan internal bila kompromi host dicurigai.

2. Rotasi credential

  • Rotasi API key model, token Git hosting, cloud credential, dan secret lain yang dapat diakses editor.
  • Rotasi refresh token atau sesi login yang tersimpan lokal.
  • Periksa apakah child process atau log pernah menerima secret yang sama.

3. Forensik minimum yang berguna

  • Ambil audit log keputusan policy dan eksekusi tool.
  • Identifikasi plugin aktif, perubahan permission terakhir, dan command yang dijalankan.
  • Periksa akses file ke lokasi sensitif dan network egress yang tidak biasa.
  • Bandingkan hash build, extension, dan konfigurasi terhadap baseline yang dipercaya.

4. Pemulihan

  • Patch jalur eksploitasi atau nonaktifkan fitur terkait sampai perbaikan siap.
  • Verifikasi ulang trust boundary dan permission model, bukan hanya bug spesifik.
  • Komunikasikan scope dampak ke pengguna internal dengan daftar tindakan rotasi yang jelas.

5. Post-incident review

Setelah insiden terkontrol, cari akar desainnya. Jika akar masalahnya adalah renderer memegang privilege host atau plugin mendapat akses shell umum, maka patch kecil tidak cukup. Ulangi desain capability, session scoping, dan sandboxing.

Penutup

Hardening Editor AI yang efektif berangkat dari satu asumsi: konten yang dibaca model, plugin yang dipasang, dan jalur UI ke host bisa menjadi sumber eksekusi berbahaya. Karena itu, perlindungan paling bernilai adalah pemisahan trust boundary, token yang sempit dan singkat, plugin berizin minimal, executor tersandbox, command allowlist, pembatasan file/network, audit log yang berguna, dan kill switch yang siap dipakai.

Jika editor AI Anda saat ini masih mengandalkan shell generik, token jangka panjang, dan plugin yang berjalan hampir tanpa batas, mulailah dari tiga perubahan besar: putuskan akses langsung renderer ke host, ubah semua aksi sensitif menjadi capability terstruktur, dan jalankan eksekusi tool di sandbox dengan default deny. Itu memberi pengurangan risiko yang nyata, bahkan sebelum semua lapisan hardening lain selesai dibangun.