Ringkasan Utama
CVE-2026-22708 membuat Cursor versi sebelum 2.3 menjalankan built-in shell seperti export, typeset dan declare tanpa pengecekan allowlist atau persetujuan, sehingga agent hasil prompt injection bisa meracuni variabel seperti PAGER dan mengubah perintah git yang disetujui menjadi eksekusi kode. Allowlist hanya mencocokkan nama perintah, bukan state shell, jadi sandbox harus menjadi batas sebenarnya.
Bagian dari bug ini yang paling membekas adalah betapa biasa perintah yang disetujui itu. Entri allowlist untuk git branch persis yang ditulis tim yang hati-hati, dan para peneliti menunjukkan entri itu bisa cukup, bahkan dengan allowlist yang kosong, karena langkah berbahaya terjadi satu perintah sebelumnya dan tidak ada yang ditanyai.
Saya membaca GitHub advisory, catatan NVD, tulisan Pillar Security, entri database SentinelOne, dokumentasi run modes dan sandbox Cursor, serta manual git-var. Saya tidak mereproduksi bug ini dan post ini tidak berisi exploit payload. Semua di bawah ini dirujuk ke salah satu halaman itu, dan kalau mereka berbeda pendapat, saya sebutkan.
Isi catatan CVE, dan di mana sumber-sumbernya berbeda
Deskripsi NVD menyebut bahwa sebelum Cursor 2.3, dengan agent dalam Auto-Run Mode dan mode Allowlist aktif, beberapa built-in shell tetap bisa berjalan tanpa muncul di allowlist dan tanpa persetujuan pengguna. Lewat prompt injection langsung maupun tidak langsung, penyerang bisa mengatur, mengubah atau menghapus environment variable yang memengaruhi perintah tepercaya. GitHub advisory GHSA-82wg-qcm4-fp2w menambahkan bahwa konfigurasi non-default diperlukan dan mengkredit Dan Lisichkin dari Pillar Security.
| Field | NVD (nvd@nist.gov) | GitHub sebagai CNA (security-advisories@github.com) |
|---|---|---|
| Skor | CVSS 3.1 base 9.8 Critical, network, low complexity, tanpa privilege, tanpa interaksi | CVSS 4.0 base 7.2 High, attack complexity High, attack requirements Present |
| Kelemahan | CWE-77, command injection | CWE-15, 74, 77, 78, 94 dan 269 |
| Terdampak | Sebelum 2.3 | Teks advisory: 2.2 dan sebelumnya |
| Diperbaiki | 2.3 | 2.3, dijelaskan sebagai perbaikan parsing perintah terminal untuk edge case |
| Dipublikasikan | 2026-01-14 | 14 Januari 2026 |
Kedua skor itu bukan kontradiksi yang harus diselesaikan, melainkan dua sistem penilaian oleh dua pihak. Kalau scanner atau kebijakan Anda berbunyi patch semua yang 9.0 ke atas, 9.8 dari NVD akan memicunya sementara 7.2 dari GitHub tidak. Baca prasyaratnya sebelum angkanya: ini hanya berdampak pada pengguna yang mengaktifkan workflow allowlist, dan butuh prompt injection yang sampai ke agent lebih dulu.
Mengapa allowlist tidak pernah melihat langkah berbahayanya
Allowlist menjawab satu pertanyaan: apakah perintah ini ada di daftar. Temuan Pillar adalah evaluator server-side Cursor memperlakukan built-in shell sebagai tepercaya secara implisit. Built-in yang disebut adalah export, readonly, unset, typeset, declare dan local, dan semuanya berjalan di shell saat ini, jadi bukan program terpisah yang akan ditandai pengecekan nama perintah. Mereka hanya mengubah state.
State itu dibaca oleh perintah berikutnya. Manual git sendiri menjelaskan urutan yang dipakai untuk memilih pager: GIT_PAGER, lalu setting core.pager, lalu PAGER, lalu default saat compile, biasanya less. Manual itu juga menyebut nilainya memang dimaksudkan untuk diinterpretasikan oleh shell. Jadi variabel yang tampak seperti konfigurasi tampilan yang tidak berbahaya adalah, by design, string yang diserahkan ke shell. Contoh Pillar persis itu: set PAGER diam-diam lewat built-in, lalu tunggu perintah biasa seperti git branch berjalan.
# Git picks its pager in this order (git-var manual):
# $GIT_PAGER, then core.pager, then $PAGER, then the compiled default (usually less)
# and the manual says the value is "meant to be interpreted by the shell".
# So each of these is a string a shell will run, not a harmless display setting.
git var GIT_PAGER # what git would launch right now
git config --show-origin --get-all core.pager # is it pinned, and in which file?
echo "PAGER=$PAGER" # the last fallback in the chainPillar menyebut kelas yang sama menjangkau variabel lain, dengan menamai LD_PRELOAD dan GIT_ASKPASS, tetapi mencatat keduanya butuh lebih banyak interaksi pengguna. Pager adalah kasus yang paling bersih karena menyetujui git branch terasa seperti menyetujui daftar read-only. Persetujuan itu tidak pernah tentang hal yang benar-benar dijalankan.
Dari satu klik ke nol klik: varian yang dijelaskan Pillar
Pillar menjelaskan empat bentuk dari kelemahan yang sama. Saya mendaftarkannya pada tingkat detail yang dijelaskan, karena yang penting bagi defender adalah kelasnya, bukan resepnya.
- PAGER hijacking, satu klik: sebuah built-in mengatur PAGER, lalu perintah git di allowlist memicu kode yang dikontrol penyerang alih-alih menampilkan output.
- Rantai warning handler Python, satu klik: Pillar mengkredit Luke Jahnke dari elttam untuk rantai environment variable yang membuat eksekusi Python berikutnya mengarah ke Perl lalu ke eksekusi kode.
- Penulisan file arbitrer lewat export, nol klik: Pillar menyebut sanitizer tidak mengenali here-string yang digabung dengan output redirection sebagai penulisan file, sehingga konten bisa ditambahkan ke file startup shell untuk persistensi di setiap shell baru.
- Eksekusi langsung lewat typeset atau declare, nol klik: Pillar menyebut keduanya menyalahgunakan flag parameter expansion zsh sehingga command substitution yang tertanam dievaluasi, dan filter tidak mendeteksi command substitution yang eksplisit.
Varian persistensi adalah yang paling saya khawatirkan, karena kerusakannya bertahan melewati sesi. Penulisan ke file startup seperti ~/.zshrc tidak hilang hanya dengan memperbarui Cursor, jadi patching dan audit adalah dua pekerjaan terpisah, dan auditnya ada di bagian Senin.
Timeline dan fix: awalnya belum lengkap, lalu aturan parser
Timeline Pillar: dilaporkan ke Cursor pada 11 Agustus 2025; Cursor mengakui masalahnya pada Agustus; pada September mengakui isu sistemik dengan dua inisiatif besar yang berjalan; dan pada Januari 2026 merilis fix. Advisory dan catatan NVD sama-sama bertanggal 14 Januari 2026, dan versi yang diperbaiki adalah 2.3.
Pillar juga menyebut mitigasi sandbox awal Cursor tampak belum lengkap, hanya menutup jalur pemicu tertentu sementara kelas kerentanannya masih bisa dieksploitasi. Fix yang dijelaskan berupa aturan, bukan patch untuk satu payload: persetujuan eksplisit pengguna untuk setiap perintah yang tidak bisa diklasifikasikan parser server-side. Itu bentuk yang tepat, karena mengubah hal yang tidak diketahui menjadi prompt, bukan allow, tetapi itu pernyataan dari peneliti, dan saya tidak menemukan fix dijelaskan lebih rinci di advisory selain perbaikan parsing untuk edge case.
Apa yang tidak pernah bisa dijamin allowlist
Allowlist adalah filter pada satu layer, dan tiap layer melihat hal yang berbeda. Tabel ini memuat apa yang dikatakan dokumentasi Cursor sendiri tentang tiap layer, di samping apa yang tidak bisa dilihat layer itu.
| Layer | Dasar keputusannya | Yang tidak bisa dilihatnya |
|---|---|---|
| Allowlist | Apakah aksi ada di daftar Anda; aksi yang terdaftar berjalan tanpa persetujuan | Environment yang diwarisi perintah, dan apa pun yang gagal diklasifikasikan parser |
| Classifier Auto-review | Model di backend Cursor meninjau panggilan yang tidak memakai sandbox | Dokumen Cursor menyebutnya bukan batas keamanan dan bisa salah ke dua arah |
| Sandbox | Di mana perintah berjalan: akses file dan jaringan, apa pun perintahnya | Perintah yang butuh akses penuh melewatinya dan masuk ke persetujuan |
| Run Everything | Tidak ada; setiap tool call berjalan otomatis | Semuanya |
Alasan struktural mengapa allowlist tidak bisa menjadi jaminan adalah ia bertumpu pada perintah sementara serangannya ada di konteks. Bahkan setelah fix, dokumentasi lifecycle Auto-review Cursor menyebut panggilan shell, Fetch dan MCP di allowlist berjalan di luar sandbox. Jadi allowlist tetap menjadi satu jalur di mana perintah dieksekusi dengan privilege penuh Anda, dan karena itu daftarnya harus pendek dan membosankan. Pillar mengutip Cursor yang menyebut allowlist bukan jaminan keamanan, dan halaman Run Modes saat ini membingkai mode Allowlist sebagai perilaku deterministik untuk sekumpulan kecil aksi tepercaya yang berulang.
Trade-off: isolasi punya harganya
Rekomendasi Pillar adalah isolasi eksekusi penuh, dengan sanitisasi dianggap kontrol yang lebih lemah. Saya setuju dengan arahnya, dan tulisan sandbox Cursor sendiri memberi motifnya: persetujuan per perintah menurun menjadi approval fatigue, dan Cursor melaporkan agent ber-sandbox berhenti 40 persen lebih jarang dibanding yang tanpa sandbox. Cursor memakai Seatbelt di macOS, serta Landlock dan seccomp di Linux. Ini angka Cursor tentang produknya sendiri, bukan pengukuran independen.
Sandbox punya pintu keluar. Dokumentasi Cursor menyebut beberapa perintah butuh akses sistem penuh dan melewatinya, dan perintah ber-sandbox yang gagal karena pembatasan bisa dijalankan ulang di luar sandbox, dengan classifier meninjau ulang. Konfigurasinya juga punya nilai type, insecure_none, yang mematikan sandbox sepenuhnya. Sandbox yang bisa di-opt-out per perintah hanya sekuat orang yang menyetujui opt-out itu.
Biayanya adalah friksi. Jaringan diblokir secara default lalu dibuka oleh network mode dan sandbox.json Anda, jadi npm install pertama di proyek baru akan meminta sebuah domain. Friksi itu adalah kontrol yang bekerja, tetapi nyata, dan tim yang merasakannya cenderung menjawab dengan Run Everything, yang di tabel Cursor dijelaskan untuk orang yang menerima risiko dan ingin nol prompt.
Yang tidak bisa saya konfirmasi
Ada tiga celah yang perlu disebut. Pertama, saya tidak menjalankan satu pun dari ini, jadi saya tidak bisa bilang varian mana yang masih berfungsi di versi tertentu; sumber hanya mendukung bahwa 2.3 adalah versi yang diperbaiki. Kedua, Pillar adalah penemu dan menjual produk keamanan, sehingga framing-nya condong ke isolasi, dan artikelnya tidak menyebut versi terdampak atau terperbaiki maupun CVSS. Ketiga, halaman database SentinelOne menyebut dalam teksnya sendiri bahwa kontennya dibuat AI dan perlu diverifikasi, jadi saya hanya memakainya untuk cek silang angka NVD.
Yang dilakukan hari Senin
Patching adalah bagian terkecil dari ini. Kerjakan berurutan.
- Cek versi Cursor di setiap mesin dan perbarui yang sebelum 2.3. Konfigurasi Anda tidak otomatis aman hanya karena merasa tidak pernah mengaktifkan allowlist; pastikan apa yang sebenarnya tampil di Settings > Agents > Approvals and Execution.
- Audit file startup shell untuk perubahan yang tidak Anda buat, dengan perintah di bawah. Lakukan ini meski sudah patching, karena varian persistensi meninggalkan file.
- Pangkas allowlist menjadi perintah read-only yang berani Anda jalankan tanpa melihat. Panggilan di allowlist berjalan di luar sandbox, jadi setiap entri adalah jalur tanpa sandbox.
- Aktifkan sandbox dan tutup jaringan dengan sandbox.json tingkat proyek, lalu buka hanya domain yang dibutuhkan proyek. Commit file itu agar berlaku untuk seluruh tim.
- Larang Run Everything dan insecure_none di mesin mana pun yang menyimpan kredensial produksi atau deploy key.
- Perlakukan apa pun yang dibaca agent sebagai input tidak tepercaya: README, issue, dokumentasi dependency. NVD menyebut prompt injection tidak langsung sebagai jalur pengirimannya.
# Step 2: audit startup files. A write here survives a Cursor update.
# Newest first: anything modified recently that you did not touch is suspect.
ls -lt ~/.zshenv ~/.zprofile ~/.zshrc ~/.zlogin \
~/.bash_profile ~/.bashrc ~/.profile 2>/dev/null
# Variables Pillar names as hijackable. None belong in a startup file
# unless you put them there on purpose.
grep -nE 'PAGER|LD_PRELOAD|GIT_ASKPASS' \
~/.zshenv ~/.zprofile ~/.zshrc ~/.zlogin \
~/.bash_profile ~/.bashrc ~/.profile 2>/dev/null
# Hygiene only: GIT_PAGER and core.pager outrank PAGER, but anyone able to set
# variables can set GIT_PAGER too. This does not close the vulnerability class.
git config --global core.pager lesssandbox.json di bawah hanya memakai field dari halaman referensi Cursor. readBoundary membutuhkan Cursor 3.23 atau lebih baru menurut halaman itu, jadi hapus di build lama. permissions.json mengarahkan Auto-review dengan bahasa biasa; Cursor menyebut Auto-review bukan batas keamanan, jadi anggap itu dorongan di atas sandbox, bukan pengganti.
// <project>/.cursor/sandbox.json (commit it; per-repo wins over ~/.cursor/sandbox.json)
{
"type": "workspace_readwrite", // never "insecure_none": that disables the sandbox
"networkPolicy": {
"default": "deny", // the documented default, stated on purpose
"allow": ["registry.npmjs.org"] // exact domains; add one per real need
},
"readBoundary": "workspace", // Cursor 3.23 or later: ask before reading outside the workspace
"additionalReadPaths": [],
"disableTmpWrite": false
}
// <project>/.cursor/permissions.json (plain-English steering for Auto-review)
{
"autoRun": {
"allow_instructions": [],
"block_instructions": [
"Any command that sets, changes or unsets environment variables such as PAGER, LD_PRELOAD or GIT_ASKPASS should go through approval first."
]
}
}git config --global core.pager less adalah kebersihan, bukan fix. Urutan git menaruh GIT_PAGER dan core.pager di depan PAGER, tetapi penyerang yang bisa mengatur variabel juga bisa mengatur GIT_PAGER. Jangan mengira mengunci pager menutup kelasnya.
Aturan yang saya ambil: persetujuan menempel pada sebuah perintah, tetapi perilaku perintah bergantung pada state yang diubah perintah sebelumnya. Kontrol apa pun yang menyetujui string tanpa mengendalikan environment tempat string itu berjalan pada akhirnya akan menyetujui hal yang salah. Patch ke 2.3, audit file startup Anda, jaga allowlist tetap kecil, dan taruh batas yang sebenarnya di sandbox yang tidak Anda opt-out sembarangan.
Sumber dan bacaan lanjutan
- GitHub Security Advisory GHSA-82wg-qcm4-fp2w: Terminal Tool Allowlist Bypass via Environment Variables
- NVD: catatan CVE-2026-22708
- Pillar Security: paradoks keamanan agent, ketika perintah tepercaya di Cursor menjadi vektor serangan
- Database kerentanan SentinelOne: CVE-2026-22708
- Dokumentasi Cursor: Run Modes
- Dokumentasi Cursor: referensi sandbox.json
- Blog Cursor: mengimplementasikan sandbox aman untuk agent lokal
- Dokumentasi Git: git-var, urutan pemilihan pager

