Model keamanan

aipager menjalankan Claude Code atas namamu dan dikendalikan dari Telegram. Dari situ muncul dua pertanyaan:

Sumbernya di GitHub ↗Halaman ini diterjemahkan dari bahasa Inggris; kalau keduanya berbeda, versi bahasa Inggris yang berlaku. English
  1. Siapa yang bisa mengendalikan bot?
  2. Apa yang bisa dilakukan bot saat dikendalikan?

Batas kepercayaan#

Setiap penangan yang dibuka bot (pesan, file, pesan suara, tombol) melewati filter chat python-telegram-bot yang dibangun dari chat yang diatur di ~/.config/aipager/aipager.yaml, atau (untuk perintah) pemeriksaan yang sama di otorisasi milik aipager sendiri. Satu-satunya pengecualian hanya mencatat pengirim di grup yang tidak diatur (di bawah). Hanya chat yang diatur yang bisa berinteraksi dengan bot. Tidak ada apa pun dari chat lain yang diproses atau diteruskan ke sesi mana pun. Chat pribadi yang tidak diatur mendapat satu balasan “Bot ini belum diatur untuk bicara denganmu”. Di grup yang tidak diatur, bot tidak pernah membalas, tapi mencatat siapa yang mengiriminya pesan di sana (ID Telegram, username, dan nama orang itu, serta ID, judul, dan jenis grup) ke ~/.claude/aipager-pending-users.json, supaya aipager config bisa menemukan grup baru itu dan orang-orangnya selama aipager berjalan. Siapa pun bisa menambahkan bot ke grup, jadi siapa pun bisa menambahkan baris ke file ini; itu tidak memberi hak apa pun. Hanya kamu yang bisa membaca file itu (izin 0600), file itu ditulis ulang utuh setiap kali (tidak pernah tertinggal setengah tertulis), dan menyimpan paling banyak 200 orang terakhir, membuang yang tidak terlihat selama 30 hari. Dalam mode tim, di atas itu berlaku daftar orang yang diizinkan beserta perannya, dan di grup hanya pesan yang ditujukan ke bot yang diproses (perintah, balasan ke pesannya, sebutan, atau ketukan pada keyboard-nya), apakah bot itu admin grup atau tidak (lihat grup).

Jadi yang terbuka ke “dunia luar” adalah:

  • Token bot (rahasia).
  • ID chat (bilangan bulat panjang).

Kalau keduanya bocor, penyerang bisa mengendalikan aipager-mu. Kalau hanya token yang bocor, penyerang bisa membaca pesan yang dikirim ke bot dari chat-mu, tapi tidak bisa mengirim perintah yang akan dijalankan aipager. Kalau hanya ID chat yang bocor, tidak ada yang berguna: bot butuh token untuk bisa bicara dengan Telegram sama sekali.

Rahasia#

RahasiaDi manaIzin
Token bot~/.config/aipager/aipager.yamlbawaannya 600
ID chatfile yang samabawaannya 600

Token tidak masuk ke log aipager: baris permintaan HTTP yang membawanya tidak dicatat, dan pesan error, aipager doctor, serta wizard menyamarkan apa pun yang mirip token bot. ID chat memang muncul di log aipager (misalnya di baris tentang batas), jadi anggap keluaran aipager logs sebagai hal pribadi. Keduanya tidak masuk ke repo: konfigurasi ada di ~/.config milik pengguna, bukan di dalam repo. Rilis ke PyPI lewat Trusted Publisher juga tidak pernah menyentuh rahasia; autentikasinya ditangani OIDC.

Kalau kamu curiga token-nya bocor, cabut lewat @BotFather (/revoke), buat yang baru, lalu jalankan lagi aipager config.

Kredensial Claude: apa yang sebenarnya melindunginya#

aipager menjalankan agen otonom dengan akses Bash sebagai pengguna UNIX-mu. Jadi rahasia apa pun yang bisa dibaca aipager juga bisa dibaca agen yang dijalankannya. Ini perlu dikatakan terang-terangan, karena mudah sekali berpegang pada jenis perlindungan yang salah.

~/.config/aipager/ ada di daftar larangan safety.py, yang mencegah sesi yang dikendalikan dari Telegram membaca file di dalamnya. Itu perlindungan berbasis path, dan di sini tidak ada gunanya: kredensial Claude (CLAUDE_CODE_OAUTH_TOKEN atau ANTHROPIC_API_KEY) tidak dibaca lewat path, tapi diwariskan ke environment proses setiap sesi yang dijalankan. Di dalam sesi, echo $CLAUDE_CODE_OAUTH_TOKEN akan mencetaknya, ada daftar larangan atau tidak. Aturan path file bukan jenis perlindungan yang tepat untuk variabel environment.

Di mana kredensial itu disimpan#

PemasanganSumberIzin
Layanan pengguna systemdLoadCredential=claude_oauth:%h/.config/aipager/daemon.env, dibaca dari $CREDENTIALS_DIRECTORY/claude_oauth600 (daemon.env); systemd menjaga kredensial di luar environment layanan itu sendiri
macOS / Docker / tanpa systemd~/.config/aipager/daemon.env, dibaca langsung600

Kedua jalur dibaca oleh kode yang sama (aipager/daemon_secrets.py) dan diteruskan ke sesi yang dijalankan lewat tabel env= subproses, tidak pernah dimasukkan ke string perintah bash -c. /proc/PID/cmdline bisa dibaca semua orang (0444); /proc/PID/environ adalah 0400 (hanya pemilik).

Yang benar-benar diberikan LoadCredential= + 0600: pengguna UNIX lain di komputer yang sama tidak bisa membaca kredensial itu, dan kredensial itu tidak pernah muncul di systemctl show, di cadangan file layanan, atau di tangkapan layar keluaran journalctl yang mungkin ditempel operator ke laporan bug. Ini tidak membuat batas antara aipager dan agen yang dijalankan aipager: batas seperti itu tidak ada, dan tidak ada pengaturan izin file yang bisa membuatnya, karena seluruh tugas agen adalah bertindak sebagai operator di environment yang sama.

Satu-satunya pengaman yang benar-benar bekerja#

Batasi kredensialnya sendiri. Jalankan aipager dengan akun Anthropic terpisah, atau dengan kunci API yang punya batas pengeluaran, bukan dengan token yang sama yang kamu pakai untuk login claude interaktifmu sendiri. Mencabut kredensial aipager seharusnya tidak pernah membuat orang ter-logout; kalau sampai begitu, itu kredensial yang sama dan keduanya tidak dibatasi. aipager doctor --fix bisa menemukan token yang ada untuk mengisi daemon.env, tapi token mana yang diberikan adalah keputusan operator, dan itulah satu-satunya keputusan di dokumen ini yang lebih penting daripada izin file di sekitarnya.

Memeriksa login tanpa menebak#

aipager doctor (dan notifikasi satu baris yang datang sekali setiap aipager mulai) melaporkan login lewat claude auth status milik Claude Code sendiri, tidak pernah lewat pemeriksaan file buatan sendiri. Tiga keadaan selalu dibedakan dengan teks yang berbeda di mana pun muncul:

  • auth: <method> (<source>): login terkonfirmasi.
  • auth: none (not logged in): terkonfirmasi tidak login.
  • auth: unknown (...): percobaannya sendiri gagal (batas waktu, program tidak ada, keluaran tidak bisa dibaca) atau programnya lebih tua dari versi yang memperkenalkan keluaran JSON. Ini tidak pernah ditampilkan sebagai “belum login”: aipager tidak menolak meluncurkan sesi karena pemeriksaan login yang hasilnya tidak pasti. Login lewat Keychain macOS, kredensial yang hanya berisi refresh token, dan login paket Max tanpa file tidak terlihat oleh pemeriksaan file mana pun dan kalau tidak, akan terlihat persis seperti “sudah logout”.

Siapa yang memutuskan apakah pemanggilan alat dijalankan#

Dua pemeriksaan terpisah memutuskan apakah pemanggilan alat dijalankan, dan urutannya begini:

  1. Pemeriksaan keamanan aipager. Sebelum setiap pemanggilan alat, Claude Code menjalankan hook PreToolUse milik aipager. Untuk tugas yang dimulai dari Telegram, hook itu menahan pemanggilan pada aturan peran pengirimnya dan pada batas bawah keamanan (path yang dilindungi, pola perintah), dan menolak apa yang dilarang keduanya: Claude Code lalu menolak alat itu tanpa bertanya, apa pun kata aturannya sendiri. Pesan yang diketik di terminal tidak dibatasi oleh pemeriksaan ini. Apa yang dicakupnya dijelaskan di bawah, di cara aturan diterapkan di tim.
  2. Aturan Claude Code sendiri (~/.claude/settings.json, mode izin sesi). Kalau aturan itu bilang tanya, Claude Code memanggil PermissionRequest dan aipager menampilkan permintaannya di Telegram (lihat hooks). Ketukanmu kembali ke Claude Code sebagai keputusan hook, atau diketikkan ke dialog Claude Code sendiri kalau penantian 20 detik sudah habis. Kalau aturan Claude Code menolak pemanggilan itu, pemanggilan tidak pernah sampai ke Telegram.

Jadi aipager bisa menolak pemanggilan yang akan diizinkan Claude Code, dan saat Claude Code bertanya, aipager tidak pernah menjawab “ya” sendiri: izin selalu berupa ketukan manusia. Tiga hal membuat pemanggilan berjalan tanpa bertanya ke manusia:

  • Mode Akses penuh, untuk admin (dan untuk seseorang di chat pribadinya sendiri). Sesi dalam Akses penuh dimulai dengan --dangerously-skip-permissions: Claude Code tidak bertanya apa pun, jadi setiap pemanggilan yang tidak ditolak pemeriksaan keamanan aipager berjalan tanpa ketukan. Hanya admin (peran owner dan admin, atau peran dengan can_manage) yang bisa memulai sesi dalam Akses penuh, mengalihkan sesi ke sana (/mode full, setelah konfirmasi), atau melanjutkan sesi di sana, dengan satu pengecualian: di chat pribadinya sendiri dengan bot, orang yang perannya bisa mengirim pesan dan menjawab Claude (can_prompt dan can_approve, yaitu user tapi bukan read_only) bisa melakukan hal yang sama untuk sesinya sendiri (/new !x1, atau pengaturan “Sesi baru” yang diatur ke Akses penuh di chat itu, /mode full, /resume), di Telegram dan di Mini App. Tidak pernah di grup dan tidak pernah di chat pribadi orang lain. Semua orang lain mendapat Mode Auto sebagai gantinya, dan balasannya mengatakan itu. Akses penuh hanya melewati permintaan milik Claude Code sendiri: hook PreToolUse milik aipager tetap menerapkan aturan peran orang itu (batas bawah keamanan, batas folder, aturan larangan, file kredensial) pada setiap pemanggilan, persis seperti di Mode Tanya dan Mode Auto; mode yang dilaporkan Claude Code tidak pernah melonggarkannya. Pemeriksaan keamanan aipager tetap berjalan di setiap pemanggilan dalam Akses penuh, tapi tidak menolak apa pun pada tugas pemilik sendiri dan pada pesan yang diketik di terminal.
  • Mode Auto, bawaannya. Sesi dalam Auto dimulai dengan --permission-mode auto: pemeriksaan keamanan Claude Code sendiri melihat setiap pemanggilan, menjalankan yang aman, dan menghentikan yang berisiko, yang kemudian datang ke Telegram sebagai permintaan seperti di Mode Tanya. Setiap sesi dimulai dalam Auto kecuali chat itu memilih lain di /settings → Sesi baru. Siapa pun yang boleh bertindak pada sesi bisa mengalihkannya antara Tanya dan Auto (/mode); aipager melakukannya tanpa mulai ulang dengan menekan Shift+Tab di sesi itu, dan tidak pernah memakai flag yang akan memasukkan Akses penuh ke siklus Shift+Tab milik Claude Code. Kalau suatu saat Claude Code melaporkan Akses penuh untuk sesi yang tidak dimulai aipager di sana, aipager menampilkan apa yang datang, mencatat peringatan di log, dan karena itu tidak pernah memulai atau memulai ulang sesi dalam Akses penuh. Batasan yang diketahui: mode yang dilaporkan Claude Code datang lewat soket hook, yang bisa ditulisi proses lokal mana pun (lihat koneksi jaringan). Pesan palsu bisa mengubah mode yang ditampilkan untuk sesi, dan selama peralihan antara Tanya dan Auto menunggu konfirmasi, pesan itu bisa membuat aipager menekan Shift+Tab sekali lagi, sehingga sesi yang hidup tetap di Auto padahal yang diminta Tanya (hook asli berikutnya menampilkan lagi mode yang sebenarnya). Pesan palsu tidak pernah mengubah flag yang diberikan saat mulai ulang atau melanjutkan, dan tidak pernah bisa mencapai Akses penuh: mode itu hanya diatur oleh flag saat peluncuran. aipager tidak menekan Shift+Tab pada sesi yang diketahuinya bisa berputar ke Akses penuh: sesi yang diluncurkan dalam Akses penuh (bahkan setelah dialihkan ke Tanya atau Auto di terminal), atau sesi yang melaporkan Akses penuh ke aipager yang sedang berjalan sejak sesi itu dimulai. Di sana setiap pergantian mode adalah mulai ulang yang memberikan flag mode baru dan membuang flag Akses penuh, dan pesan Akses penuh yang palsu hanya bisa mengubah pergantian menjadi mulai ulang. aipager tidak bisa mengetahui ini untuk sesi yang diluncurkan di terminal dengan flag yang memasukkan Akses penuh ke siklus Shift+Tab (--allow- di depan flag Akses penuh), atau dengan --dangerously-skip-permissions kalau sesi itu sudah keluar dari Akses penuh sebelum aipager mengetahuinya (aipager sedang tidak berjalan, atau sudah dimulai ulang sejak itu). Di sana, langkah dari Tanya ke Auto bisa berhenti di Akses penuh, dan kartunya kemudian mengatakan sesi itu dalam Akses penuh. Jangan pakai flag-flag itu untuk sesi terminal yang mode-nya bisa diganti dari Telegram oleh orang yang bukan admin. Supaya Akses penuh bisa berjalan dari Telegram, aipager mengatur skipDangerousModePermissionPrompt di ~/.claude/settings.json setiap kali mulai (kalau tidak, peringatan Claude Code sebelum berjalan dalam mode itu akan menghentikan sesi); ini juga mematikan peringatan itu untuk sesi yang kamu jalankan sendiri. Begitu pula aipager menandai folder tempat setiap sesi dimulai sebagai tepercaya di ~/.claude.json (kecuali folder itu atau folder di atasnya sudah tepercaya), supaya pertanyaan Claude Code “Do you trust this folder?” tidak menghentikan sesi yang diluncurkan dari Telegram: pesan pertama akan menjawabnya dengan “No, exit”. Pengaturan .claude/, hook .git/, dan .mcp.json milik folder tepercaya bisa menjalankan perintah; karena itu anggota tanpa can_manage tidak pernah bisa menulis file-file itu (kecuali policy.yaml memberi peran mereka shell lagi). Claude Code memberlakukan kepercayaan pada satu folder juga untuk folder di bawahnya yang tidak berada di dalam repositori git; repositori tetap mendapat pertanyaannya sendiri. Folder home ditandai saat sesi dimulai di sana, karena Claude Code hanya menyimpan jawaban ya di folder home untuk sesi itu saja. Setelah itu, Claude Code tidak menanyakan apa pun di folder di bawah folder home-mu yang tidak berada di dalam repositori git, termasuk di sesi yang kamu jalankan sendiri. / dan folder di atas folder home tidak pernah ditandai: itu akan mencakup semua folder seperti itu di komputer ini, jadi sesi yang dimulai di salah satunya berhenti di pertanyaan itu. Saat mulai, aipager tidak menandai apa pun, hanya folder tempat sesi akan dimulai. Sesi baru dimulai di folder tempat aipager berjalan (folder home untuk aipager service install di Linux dan macOS, juga di kontainer) atau di AIPAGER_WORK_DIR kalau itu diatur; log aipager memberi peringatan saat mulai kalau folder itu / atau folder di atas folder home dan belum tepercaya. Versi sebelum ini menandai folder aipager setiap kali mulai, termasuk / untuk layanan macOS (yang berjalan di /); aipager tidak bisa membedakan entri seperti itu dari entri yang kamu buat sendiri, jadi entri itu dibiarkan. aipager tidak menyentuh ~/.claude.json dan ~/.claude/settings.json kalau tidak bisa membacanya utuh, atau kalau Claude yang sedang berjalan mengubahnya saat aipager sedang memperbaruinya.
  • Selalu izinkan, yang mengembalikan ke Claude Code aturan “jangan tanya lagi” yang ditawarkan bersama permintaan itu, persis seperti yang dilakukan opsi itu di dialog Claude Code sendiri.

Untuk menutup alat bagi semua orang, larang di ~/.claude/settings.json; untuk menutupnya bagi sebagian orang, pakai aturan peran mereka di policy.yaml (lihat grup).

Yang ditampilkan permintaan adalah yang dijalankan. Permintaan izin menampilkan perintah atau path yang sebenarnya di bawah deskripsi yang diberikan Claude. Karakter kontrol arah Unicode (U+202A-U+202E, U+2066-U+2069, U+200E, U+200F, U+061C) mengubah urutan Telegram, browser, atau ponsel menggambar teks setelahnya, sedangkan shell menjalankan karakter sesuai urutannya, jadi karena karakter itu satu perintah bisa terbaca seperti perintah lain (trik “Trojan Source”, CVE-2021-42574). Di setiap permintaan, pertanyaan, pratinjau perubahan, dan entri audit, karakter itu ditampilkan sebagai label yang terlihat (⟨U+202E⟩), dan permintaannya memperingatkan bahwa perintah itu mungkin tidak menjalankan apa yang terlihat. Karakter tak terlihat lain dibiarkan apa adanya.

Cara aturan diterapkan di tim#

Dalam mode tim, aipager menambahkan lapisannya sendiri di bawah ketukan: setiap pesan dari Telegram membawa catatan izin (siapa yang mengirimnya dan apa yang diizinkan perannya), ditulis ke /tmp/claude-notes-<session>/, satu file per pesan. Saat Claude mengambil pesan itu, program pembantu aipager-hook mencocokkannya dengan catatan-catatan itu dan menaruh aturan pengirimnya di tempat yang dibaca pemeriksaan PreToolUse. Semua yang lain bertumpu pada sifat-sifat ini:

  • Yang paling ketat menang. Kalau Claude mengambil pesan dari lebih dari satu orang dalam satu tugas (aipager menahan pesan supaya ini tidak terjadi, tapi tetap aman kalau terjadi juga), tugas itu berjalan dengan gabungan yang paling ketat: pesan pemilik tidak pernah bisa meminjamkan haknya ke orang lain.
  • Tugas yang sedang berjalan tidak pernah melebar. Pesan dari orang lain menunggu tugas yang sedang berjalan selesai, lalu berjalan sebagai tugasnya sendiri dengan aturan pengirimnya. Kalau pesan seperti itu tetap ikut bergabung ke tugas yang sedang berjalan, tugas itu mempertahankan aturan paling ketat dari semua yang ikut; pesan Telegram yang bergabung ke tugas yang diketik di terminal menahan sisa tugas itu pada aturan pengirimnya (pesan pemilik tidak mengubah apa pun).
  • Peranmu adalah peran di chat tempat kamu bertindak. Seseorang yang ada di beberapa chat (misalnya user di grup dan owner di chat pribadinya sendiri) memakai peran dari grup untuk semua yang ia kirim atau ketuk di grup, dan peran dari chat pribadi di chat pribadi, apa pun urutan chat itu di aipager.yaml.
  • Tidak dikenal berarti dibatasi. Pesan yang tidak bisa dikaitkan ke siapa pun berjalan dengan batas bawah bawaan (tanpa pengecualian, semua aturan larangan berlaku), tapi tidak pernah sebagai pesan terminal yang tidak dibatasi. Pesan yang kamu ketik langsung di terminal tetap tidak dibatasi; apa pun yang membawa tanda Telegram di baris mana pun diperiksa. Setiap pesan dari Telegram membawa tanda ini dengan nama orang yang mengirim pesan itu sendiri (tidak pernah orang yang terakhir mengendalikan sesi); pengirim yang tidak dikenal aipager, misalnya yang dihapus dari aipager.yaml saat pesannya menunggu, mendapat [via Telegram] saja dan batas bawah.
  • Perintah slash butuh admin. Perintah slash diketik ke Claude apa adanya, tanpa tanda, dan perintah atau skill seperti /deliver menjalankan satu tugas utuh berdasarkan teksnya sendiri. Jadi anggota yang perannya tidak melewati aturan peran (user dan read_only bawaan, peran yang kamu definisikan tanpa bypass_role_denies, dan siapa pun yang tidak dikenal aipager) hanya bisa mengirim perintah dari keyboard “Perintah” milik aipager (ditambah /compact) dan penggantian model (/model <name>); perintah slash lain, yang diketik, dikirim ke sesi lewat /<name>, sebagai keterangan file, sebagai pesan pertama /new, atau sebagai templat, ditolak dengan “Perintah itu khusus admin.” dan 🤷. Pemilik dan admin bisa mengirim apa saja. Perintah slash yang tetap sampai ke Claude dari Telegram tetap diperiksa: hook melihat bahwa tugas itu mengambil pesan Telegram yang mengirim perintah tersebut, dan menahan perintah itu pada aturan pengirimnya. Perintah slash yang kamu ketik di terminal tetap tidak dibatasi, kecuali perintah yang sama (dengan argumen apa pun) pernah datang dari Telegram sebelumnya di sesi ini: aipager tidak bisa membedakan salinanmu dari salinan Telegram yang dikirim ulang Claude Code, jadi salinanmu saat itu berjalan dengan aturan tugas Telegram terakhir. Ini berakhir bersama sesinya.
  • Pesan tanpa pengirim baru mempertahankan aturan tugas. Selama tugas Telegram berjalan, Claude Code juga melaporkan pesan yang tidak dijelaskan oleh pesan Telegram mana pun: pesan yang diketik di terminal dan diantrekan di belakang tugas (dilaporkan saat diantrekan), pesan dari sesi Claude lokal lain, atau pesan Telegram yang sama yang dikirim ulang setelah peringkasan. Pesan seperti itu tidak menambahkan pengirim Telegram, jadi tugas mempertahankan aturan yang dipakainya, diperketat oleh pesan apa pun yang masih menunggu, dan tidak pernah dilonggarkan. Pesan yang membawa teks Telegram yang tidak bisa dikaitkan aipager ke siapa pun tetap jatuh ke batas bawah bawaan, dan pesan dari pengirim dengan hak lebih sedikit tetap menurunkan tugas ke aturan pengirim itu.

Apa yang sebenarnya menahan orang yang dibatasi. Sesi Claude berjalan sebagai pengguna sistem yang sama yang memiliki konfigurasi aipager (token bot di ~/.config/aipager/aipager.yaml, kredensial Claude di ~/.config/aipager/daemon.env) dan file aturan per tugas (/tmp/claude-policy-<session>.json). Shell milik pengguna itu bisa menjangkau keduanya dengan cara yang tidak akan diantisipasi pola apa pun (sed -i … /tmp/*-policy-*.json, loop for atas glob, satu baris Python) dan menulis ulang aturannya sendiri menjadi aturan pemilik. Jadi pola perintah adalah filter, bukan batas. Untuk tugas dengan peran terbatas bawaan (user, read_only) dan untuk tugas yang tidak bisa dikaitkan aipager ke siapa pun, aipager menerapkan aturan berikut, dan tidak satu pun bergantung pada pola perintah (untuk yang tidak dicakupnya, lihat batasan yang diketahui di bawah):

  • Tanpa shell. Mereka tidak bisa memakai Bash atau alat lain yang dipakai Claude Code untuk menjalankan kode (PowerShell, Monitor, REPL, Workflow, penjadwal pesan CronCreate dan RemoteTrigger, …; daftarnya safety.CODE_EXECUTION_TOOLS). Pesan terjadwal akan datang tanpa tanda Telegram, jadi tanpa batasan, karena itu alat-alat ini juga dihitung. Dengan alasan yang sama mereka tidak bisa memakai SendMessage (bisa meneruskan pesan ke sesi Claude lokal lain, yang akan menjalankannya sebagai pesan terminal) dan EnterWorktree/ExitWorktree (memindahkan folder kerja sesi, yang menjadi dasar aturan berikutnya).
  • Penulisan tetap di dalam proyek. Write, Edit, MultiEdit, dan NotebookEdit hanya menulis ke folder sesi (folder kerja yang dilaporkan Claude Code di isi hook, tidak pernah path dari pemanggilan alat) dan ke scratchpad Claude Code milik sesi ini (/tmp/claude-<uid>/<project>/<session id>/, atau /tmp/claude-<uid>/ kalau itu tidak bisa ditentukan). Semua yang lain ditolak: file startup shell-mu, ~/.ssh, proyek lain, file aipager di /tmp. Di dalam folder itu, .claude/, .git/, dan .mcp.json juga ditolak, karena masing-masing membuat Claude Code atau git menjalankan perintah. Symlink diurai dulu sebelum keputusan. Sesi yang foldernya adalah folder home-mu, /, atau folder di atas home tidak punya folder proyek: di sana tugas yang dibatasi hanya menulis ke scratchpad-nya, dan penulisan ke tempat lain ditolak dengan “sesi ini berjalan di folder home (atau di atasnya), dan peran ini hanya boleh menulis di dalam folder proyek”. Supaya anggota yang dibatasi tidak terjebak di sana, /new dan Mini App tidak membiarkan mereka memulai sesi di folder-folder itu (folder aipager sendiri, folder bawaan sesi baru, yang di bawah layanan latar belakang adalah folder home-mu); mereka bisa membuat folder baru di dalam folder home-mu dan memulai di sana (yang benar-benar baru: bukan folder yang sudah kamu punya di sana, dan bukan bin atau node_modules, tempat program lain memuat kode).
  • Anggota tetap di folder utamanya. Peran tanpa can_manage (user dan read_only bawaan) bekerja di folder utama chat itu, yang kamu atur di aipager config (bawaannya ~/aipager-users/<label>; ~/aipager-users dan foldernya sendiri dibuat dengan izin 0700). /new, Lanjutkan, Ganti, Mulai ulang, pergantian mode, dan Mini App hanya memulai atau memulai ulang sesi anggota seperti itu di dalamnya. Hook keamanan menjaganya, lewat jalur mana pun pesan itu datang (Telegram, Mini App, pesan dari sesi lain): folder utama ikut di snapshot aturan tugas, di tanda terima pesan antarsesi, dan di hak yang dikunci dan dijadwalkan, dan saat anggota dengan folder utama berbeda berbagi satu tugas, yang lebih sempit menang (dua folder yang tidak saling bersarang hanya menyisakan folder sesi itu sendiri). Penulisan masuk ke folder sesi hanya kalau folder itu ada di dalam folder utama (sesi di luarnya, misalnya yang dimulai sebelum ada folder utama, tetap berjalan, tapi tugasnya hanya menulis ke scratchpad: “sesi ini berjalan di luar folder milik peran ini”), dan Read, LSP, Grep, dan Glob tidak menjangkau apa pun di folder home-mu di luar folder utama (“di folder home, peran ini hanya boleh membaca di dalam foldernya sendiri”), kecuali scratchpad sesi dan file balasannya sendiri. Folder utama chat lain mana pun adalah path yang dilindungi bagi anggota itu, di mana pun letaknya, begitu juga folder unggahan setiap chat lain di bawah /tmp/aipager-files/ (Read, Grep, Glob, dan alat penulisan; untuk peran yang diberi Bash, perintah yang menyebut salah satu folder itu ditolak, sebisanya), termasuk file yang dulu ditaruh di sana untuk semua chat sebelum ada folder per chat. File yang diunggah di chat anggota itu sendiri tetap bisa dibaca. Folder di luar folder home-mu (/usr, /etc, /srv) tetap bisa dibaca. Peran buatanmu dengan bypass_role_denies atau bypass_safety tapi tanpa can_manage menulis dan mencari di mana saja di dalam folder utamanya, dan pembacaannya di folder home-mu juga tetap di dalamnya: yang tanpa batasan hanya pemilik dan admin. Dengan bypass_safety, pada sesi yang foldernya di luar folder utamanya, peran itu hanya menulis dan mencari di scratchpad, seperti user, dan begitu salah satu pemanggilan alatnya ditolak, sisa tugasnya berhenti.
  • Pencarian tetap di dalam proyek. Grep atau Glob hanya diizinkan kalau semua ini terpenuhi: folder yang dicarinya (path-nya, atau folder sesi kalau tidak ada, dengan symlink diurai) ada di dalam folder sesi (tapi bukan kalau itu folder home-mu, /, atau folder di atas home, sama seperti penulisan) atau di scratchpad; folder itu bukan path yang dilindungi dan tidak memuatnya (sesi yang dimulai di folder home-mu memuat ~/.config/aipager, jadi tidak bisa mencari dari paling atas); setiap glob adalah pola relatif sederhana (tanpa /, ~, $, atau huruf drive di awal, tanpa .., tanpa # (komentar untuk ripgrep) atau ! (negasi), tanpa escape \); dan kamu tidak punya aturan path yang dilindungi tanpa / atau ~ di awal (**/.env bisa ada di mana saja di proyek, jadi dengan aturan seperti itu setiap pencarian terbatas ditolak). Semua yang lain ditolak. Ini sengaja berupa daftar yang diizinkan: tiga putaran peninjauan masing-masing menemukan cara menulis glob baru yang membawa ripgrep keluar dari folder yang diharapkan model penguraiannya, dan salah satunya membaca token bot.
  • Alat file menghormati path yang dilindungi. Read, LSP, dan alat penulisan memeriksa ke mana path benar-benar mengarah, termasuk lewat symlink. Satu-satunya file kontrol yang boleh dibaca tugas adalah /tmp/claude-reply-<session>.txt milik sesinya sendiri, yang disebutkan aipager di pesan saat kamu membalas pesan yang lebih lama; file balasan sesi lain dan penulisan apa pun ke file ini tetap dilarang. Di macOS, /tmp adalah /private/tmp dan disk-nya tidak membedakan huruf besar-kecil, jadi kedua penulisan dan semua variasi huruf dikenali.
  • Pemeriksaan yang rusak akan menolak. Kalau keputusan tentang pemanggilan alat memicu error (byte nol di path, bug) atau hook kehabisan memori saat memutuskan, pemanggilan itu ditolak, kecuali aturan sesi berhasil dibaca dan memberi pengecualian pemilik. Dulu pemanggilan seperti itu diloloskan.

Path yang dilindungi milikmu sendiri. Bagian safety: di policy.yaml (deny_paths_no_access, deny_paths_no_write, deny_bash_patterns) ditambahkan ke path yang dilindungi dan pola perintah bawaan. Bagian itu termasuk dalam batas bawah yang didapat setiap tugas dari setiap peran kecuali owner, termasuk admin, dan diterapkan ke alat file, pencarian, dan perintah Bash persis seperti daftar bawaan. aipager menulis daftar gabungannya ke /tmp/claude-policy-.floor-<uid>.json (path yang dilindungi juga) untuk jalur cadangan hook keamanan; kalau file itu tidak ada, tidak bisa dibaca, atau milik pengguna sistem lain, hook memakai daftar bawaan, tidak pernah lebih sedikit. Perubahan lewat muat ulang tanpa mulai ulang berlaku untuk pesan yang dikirim setelah muat ulang, bukan untuk tugas yang sudah berjalan atau pesan yang sudah menunggu. Sampai versi 0.7.20 bagian itu dibaca dan ditampilkan di aipager doctor --safety-check, tapi tidak diterapkan.

Tugas yang tidak bisa dikaitkan aipager ke siapa pun. Tugas Telegram tanpa pengirim yang bisa dikaitkan berjalan dengan batas bawah yang setara dengan peran user bawaan (bukan pembatasan tambahan yang ditambahkan ke user di policy.yaml) ditambah bagian safety: milikmu: tanpa alat yang menjalankan kode, penulisan dan pencarian dibatasi, path yang dilindungi. Ini terjadi pada pesan yang catatan izinnya kedaluwarsa (setelah 24 jam) atau gagal ditulis, dan pada pesan dengan teks Telegram yang tidak cocok dengan catatan mana pun. Tombol Coba lagi berjalan dengan hak orang yang mengetuknya kalau orang itu juga yang mengirim pesan yang diulang, jadi Coba lagi milik pemilik pada pesannya sendiri tetap punya Bash; Coba lagi pada pesan orang lain, atau pada pesan yang pengirimnya tidak dikenal aipager, berjalan pada batas bawah, supaya teks siapa pun tidak meminjam hak orang yang mengetuk.

Membaca di luar path yang dilindungi diizinkan untuk peran yang tidak ditahan folder utama (peran buatan dengan can_manage tapi tanpa pengecualian): peran itu bisa membaca proyek lain milik pengguna sistem. user dan read_only bawaan tidak membaca apa pun di folder home-mu di luar folder utamanya (di atas). File kredensialmu adalah path yang dilindungi untuk setiap peran tanpa bypass_role_denies (user dan read_only bawaan, peran yang kamu definisikan, dan batas bawah): ~/.ssh, ~/.gnupg, ~/.aws, ~/.config/gh, ~/.git-credentials, ~/.netrc, ~/.docker/config.json, ~/.kube, ~/.config/gcloud, ~/.azure, ~/.password-store, ~/.pgpass, ~/.npmrc, dan ~/.pypirc tidak bisa dibaca, ditulis, atau dicari. Ini nilai bawaan peran, jadi deny_paths_no_access milik peran itu sendiri di policy.yaml menggantikannya untuk peran itu, kecuali saat pesan lain atau pesan yang diketik di terminal bergabung ke tugas yang sedang berjalan: sejak saat itu sampai akhir tugas, daftar itu ditaati lagi (aturan paling ketat menang). File kredensial di tempat lain (.env di proyek, token di folder lain) tidak tercakup: tambahkan ke deny_paths_no_access peran itu. Pemilik tidak terpengaruh semua ini. Penulisan admin tidak dibatasi. Grep/Glob mereka bisa mencari di folder mana pun yang tidak menyentuh path yang dilindungi: pencarian ditolak saat folder yang dicarinya (path-nya, atau folder sesi kalau tidak ada; untuk Glob juga folder yang disebut polanya, seperti di /home/you/.config/aipager/*, atau folder di atas pola tanpa wildcard, tempat Claude Code mencari nama itu di kedalaman mana pun), setelah symlink diurai, adalah folder yang dilindungi, ada di dalamnya, atau memuatnya. Jadi Grep atas ~, /, folder di atas home-mu, atau /tmp ditolak (semuanya memuat ~/.config/aipager, ~/.claude, atau file aipager /tmp/claude-*), sedangkan Grep atas folder proyek atau /tmp/myproj tidak. Aturan path yang dilindungi tanpa / atau ~ di awal (seperti **/.env) bisa cocok di folder mana pun, jadi dengan aturan itu di aturan admin (atau di bagian safety:, yang didapat setiap peran kecuali owner) setiap pencarian admin ditolak, seperti pada peran terbatas; aipager doctor memperingatkan tentang aturan seperti itu di bagian safety:. Admin punya Bash, jadi aturan mereka tetap berlaku sebisanya (di bawah).

Batasan yang diketahui. Ini tidak dicakup:

  • Kalau hook-nya sendiri rusak sebelum mulai memutuskan (misalnya tidak bisa membaca file keadaannya, atau kehabisan memori saat mulai), Claude Code menganggapnya “izinkan”. Orang yang dibatasi tidak bisa memicu ini; error apa pun saat memutuskan akan menolak.
  • Alat yang bukan alat file tapi bisa mengirim data keluar tidak diperiksa berdasarkan path: WebFetch (apa pun yang bisa dibaca tugas bisa dikirimnya ke URL mana saja), dan alat pengiriman lain milik Claude Code. Larang alat-alat itu di aturan peran di policy.yaml kalau ini penting bagimu. SendUserFile, yang mengirim file ke chat, diperiksa (lihat file yang dikirim Claude).
  • Agen latar belakang yang dimulai oleh tugas yang dibatasi tetap berjalan setelah tugas itu selesai, dan pemanggilan alat berikutnya dinilai berdasarkan pesan terbaru di sesi: pesan yang lebih belakangan dari pemilik atau dari terminal mencabut batasannya.
  • Peran yang kamu definisikan dengan can_manage tapi tanpa kedua pengecualian tidak ditahan folder utama: peran itu tetap bisa dimulai di folder proyek mana pun tempat chat-nya sudah berjalan (folder yang dipakai sesi sebelumnya), termasuk milikmu, dan membaca proyek-proyekmu yang lain.
  • Tugas yang tidak bisa dikaitkan ke anggota mana pun (pengirim yang tidak dikenal, anggota yang dihapus, pesan dari sesi lain yang pengirimnya tidak bisa diperiksa) berjalan dengan batas bawah terbatas yang tidak punya folder utama. Untuk membaca, batas bawah ini lebih lemah daripada user bawaan: tugas seperti itu bisa membaca file apa pun di folder home-mu yang bukan path yang dilindungi (misalnya proyek-proyekmu yang lain), sedangkan tugas user hanya membaca di dalam folder utamanya. Tugas seperti itu juga bisa membaca unggahan semua chat di /tmp/aipager-files/, sedangkan tugas user hanya membaca unggahan chat-nya sendiri. Penulisannya tetap dibatasi pada folder sesi dan scratchpad. Pesan yang sudah diperiksa dari sesi anggota membawa folder utama anggota itu.
  • Folder utama hanya menahan alat file. Peran buatan yang kamu beri Bash bisa membaca di luarnya lewat shell (user dan read_only bawaan tidak punya Bash). Peran buatan dengan bypass_safety tapi tanpa can_manage mempertahankan pengecualiannya untuk semua hal selain path alat file: tidak ada alat dan tidak ada pola perintah yang dilarang baginya.
  • Alasan penolakan yang menyebut folder utama anggota lain menampilkan path folder itu ke Claude dan di chat.
  • Tugas anggota yang sudah berjalan saat folder utama mulai berlaku (lewat pembaruan) tidak punya folder utama sampai pesan berikutnya dari anggota itu.
  • Di dalam proyek, orang yang dibatasi bisa mengubah apa yang nanti kamu jalankan atau baca (sumber kode, Makefile, skrip package.json, conftest.py, CLAUDE.md yang dimuat tugasmu).

Peran yang punya Bash (admin, yang melewati aturan larangan peran, atau peran mana pun yang dikembalikan aksesnya oleh policy.yaml: allow_tools dengan Bash atau deny_tools yang diganti) hanya terikat pada aturan yang bekerja sebisanya: pola perintah di bawah, yang bisa diakali orang yang bertekad. aipager doctor memperingatkan sekali untuk setiap peran seperti itu yang dipegang anggota. Beri Bash hanya kepada orang yang kamu percayai dengan shell di komputer ini.

Aturan perintah bawaan. Di antara pola Bash yang menahan setiap tugas Telegram dengan Bash yang bukan milik pemilik, ada satu yang memblokir kata claude: pola itu menghentikan claude bersarang (dengan path, pembungkus, atau flag apa pun) dan akses apa pun ke ~/.claude dengan satu aturan, dan juga menangkap nama polos file kontrol aipager /tmp/claude-* yang punya awalan sama (untuk file-file itu pola ini bukan perlindungan sungguhan: penulisan dengan glob bisa mengakalinya). Satu-satunya pengecualian adalah folder scratchpad yang dibuat Claude Code, /tmp/claude-<uid>/…: persis folder itu, sebagai satu bagian path utuh, dikecualikan, jadi perintah dari scratchpad sesi tidak dihentikan. Folder itu milik pengguna sistem, bukan satu sesi, jadi tugas dengan Bash bisa membaca scratchpad dan keluaran tugas sesi lain di sana, sama seperti alat Read. Glob atau kembaran folder itu (/tmp/claude-1*, claude-1000x), folder sementara lain, dan apa pun yang bisa dijangkau dari sana (…/../../home/you/.claude) tetap diblokir. Kemunculan lain kata itu (git log --grep=claude, file bernama claude-notes.md, pip show claude-agent-sdk) juga diblokir, dengan sengaja: kata yang sama menamai program, SDK-nya, dan file kontrol aipager, dan pola tidak bisa membedakannya. Aturan yang kamu tambahkan di policy.yaml melihat perintah persis seperti yang diketik, termasuk scratchpad.

Mencari lewat Bash. Beberapa versi Claude Code tidak punya alat Grep atau Glob (2.1.289 salah satunya), dan Claude lalu mencari lewat Bash dengan grep, rg, atau find, tempat aturan Grep/Glob di atas tidak berlaku. Untuk setiap peran kecuali owner, pola perintah juga melarang pencarian atau pendaftaran rekursif atas seluruh folder home atau /: grep -r (-R, --recursive, -d recurse, egrep, fgrep, rgrep), rg (dan rg --files), ag, ack (dan ack -f), find, fd, tree, du, dan ls -R, kalau foldernya ~, ~user, $HOME, ${HOME} atau "$HOME", /home, /home/<user> (atau /home/$USER), /Users, /Users/<user>, /root, atau / (dengan atau tanpa akhiran /, /., atau /*), atau ~/.config atau ~/.local, tempat folder aipager berada. Ini juga berlaku setelah cd x &&, di dalam pipe, di dalam bash -c "...", setelah xargs, env, atau timeout, dan setelah pengaturan seperti LC_ALL=C. Balasannya menyarankan mencari di dalam folder proyek. Mencari di folder proyek (grep -rn x ~/proj, rg x src/, find . -name y), mencari path home DI DALAM proyek (grep -rn "$HOME" src: kata pertama setelah opsi adalah teks yang dicari, bukan folder), dan pencarian tidak rekursif (grep x ~/.bashrc, ls ~) tidak terpengaruh. Ini bekerja sebisanya, seperti pola perintah mana pun: pola melihat kata-kata, bukan di mana shell menjalankannya, jadi pola itu tidak melihat pencarian tanpa folder, atau dengan . atau .., yang dijalankan dari folder home (atau di bawahnya) (cd ~ && grep -r x .), folder home yang dicapai lewat variabel atau glob lain, folder home yang ditulis lengkap di luar /home, /Users, dan /root, \grep, dan folder tepat setelah kata yang berakhiran -e atau -f (folder itu dianggap teks yang diberikan -e/-f ke grep dan rg, jadi ag x -f ~ lolos). Pola itu juga tidak tahu opsi mana yang mengambil nilai terpisah, jadi rg -t py "$HOME" . atau grep -rn -A 3 "/home/you" src membaca py atau 3 sebagai teks dan path home sebagai folder, lalu ditolak (tulis -A3, --include=*.py, atau taruh opsinya setelah teks), begitu juga path home yang diberikan ke -e di dalam kelompok opsi (grep -rne "/home" src; -r -n -e tidak apa-apa); perintah yang dikutip di dalam teks perintah lain (echo "a; rg x ~") juga ditolak, begitu juga du -sh ~ (hanya ukuran).

Kenapa satu blokir menghentikan seluruh tugas. Setelah satu pemanggilan alat diblokir, setiap pemanggilan berikutnya dalam tugas yang sama juga ditolak sampai pesan berikutnya. Tanpa ini, agen akan terus mengulang tindakan yang sama dengan kata-kata lain (glob, perintah lain, path yang dikodekan) sampai salah satu cara penulisan lolos dari pola. Menghentikan tugas membuat percobaan pertama itu mahal; ini tidak membuat pola menjadi batas, karena cara penulisan pertama yang dicoba bisa saja yang lolos. Satu alarm palsu berarti satu tugas terhenti, karena itu aturan di atas dibuat sempit.

Lihat grup → cara kerja aturan untuk aturan yang dibawa catatan-catatan ini, seperti yang kamu lihat.

File yang dikirim Claude#

Setiap sesi yang dimulai aipager punya alat SendUserFile milik Claude Code (CLAUDE_CODE_ATTACHMENTS_BY_PATH=1), yang membaca file dan mengirimkannya ke chat sesi (perintah). Hook PreToolUse memeriksa setiap file dalam panggilan itu sebelum Claude Code membacanya:

  1. Batas dasar pengiriman, untuk setiap tugas, termasuk tugas owner dan pesan yang diketik di terminal: konfigurasi dan status aipager (~/.config/aipager/**, ~/.local/share/aipager/**, ~/.local/state/aipager/** dan file kendalinya di /tmp), seluruh ~/.claude/** dan ~/.claude.json* (kredensial dan akun Claude), file kredensial yang dijauhkan dari setiap peran terbatas (~/.ssh/**, ~/.gnupg/**, ~/.aws/**, ~/.git-credentials, ~/.netrc dan sisa daftar itu), /proc/**, /sys/**, /dev/**, dan nama yang tampak seperti rahasia di mana pun (.env, .env.*, *.pem, *.key, id_rsa*, id_ed25519* dan nama kunci lainnya, *.p12, *.pfx, *.kdbx, *.jks, *.keystore, .pgpass, credentials, *credentials*.json). Yang dicocokkan adalah path seperti yang ditulis dan ke mana ia benar-benar mengarah, jadi symlink ke salah satunya juga ditolak. Beberapa file yang tidak berbahaya memakai nama-nama ini (*.key dari Keynote, .env.example) dan ikut ditolak.
  2. File itu sendiri: file biasa setelah symlink diselesaikan, dengan satu hard link, tidak kosong, paling besar 50 MB.
  3. Aturan tugas itu sendiri: apa yang tidak boleh dibaca (Read) tugas itu, dan untuk anggota (peran tanpa can_manage, yang terikat pada folder utama) aturan yang lebih ketat bahwa setiap file, seperti yang ditulis dan ke mana ia benar-benar mengarah, ada di dalam folder utama. Berbeda dari bacaan anggota, tidak ada pengecualian untuk file di luar folder home (/tmp, /etc) dan tidak ada untuk scratchpad sesi.

Penolakan adalah penolakan lunak: Claude membaca alasannya ("SendUserFile refused, nothing was sent: ... Tell the person which file could not be sent and why.") dan tugas berjalan terus; sesi tidak dihentikan seperti saat sebuah alat diblokir. Pemeriksaan yang gagal menolak file itu, untuk owner juga. Setiap file yang ditolak punya catatan FileRefused di log audit.

aipager tidak begitu saja percaya pada apa yang dikatakan socket kendali soal sebuah file: proses lokal mana pun bisa menulis ke sana, menyebut sesi, panggilan, atau riwayat percakapan apa pun, dan hook sebuah panggilan alat saja sudah membuat sesi yang diam tampak sedang bekerja. Karena itu sebuah panggilan hanya dihitung selama tugas yang dilihat aipager dimulai dengan sebuah prompt (yang diketiknya dari Telegram, atau sebuah UserPromptSubmit) dan selama pekerjaan latar belakang tugas itu, sampai sesi diam tanpa pekerjaan yang berjalan; di awal itu aipager mencatat waktunya dan riwayat percakapan yang diikutinya untuk sesi itu (UserPromptSubmit berikutnya dari tugas yang sama menyebut riwayat itu lagi). Perintah slash yang diketik aipager tidak memulai tugas (perintah yang menjalankan tugas mengirim UserPromptSubmit-nya sendiri), dan tugas yang tidak pernah dimulai (sesi masih diam tanpa pekerjaan 15 detik kemudian) ditutup lagi. Claude Code memulai beberapa tugas tanpa UserPromptSubmit: pesan yang dikirim saat tugas berjalan lalu diambilnya sebagai tugas berikutnya, dan tugas yang dibuat terus berjalan oleh hook Stop (/goal). Tugas seperti itu dihitung kalau aipager sendiri yang mengetik pesan itu, atau begitu riwayat percakapan yang dicatatnya menunjukkan awalnya setelah Stop terakhir (baris antrean dequeue, atau baris Stop hook feedback: yang ditulis Claude Code); sampai saat itu tidak ada bagian panggilan yang dibaca, paling lama 20 detik. Ia mengambil daftar file dari PreToolUse yang diperiksanya, atau dari PostToolUse kalau yang pertama terlewat (setelah restart); tidak pernah dari hasil Claude Code. Ia menyalin setiap panggilan sekali saja: id panggilan yang sudah disalinnya tidak pernah disalin atau dikirim lagi (ia menyimpan 256 yang terakhir per sesi, juga setelah restart). Ia mencari jalur asli setiap file sekali saja dan memeriksanya lagi di situ (batas dasar, pemeriksaan file, dan folder utama sesi), membuka tepat jalur itu tanpa mengikuti link, memastikan file yang terbuka adalah yang diperiksanya dan masih ada di jalur itu, lalu menyalinnya ke ~/.local/state/aipager/outbox/<chat>/ (folder 0700, file 0600), tempat yang sudah dijauhkan dari setiap tugas terbatas. Sebelum mengirim, ia mencari panggilan itu di riwayat percakapan yang dicatatnya untuk tugas itu (untuk panggilan subagen, di riwayat percakapan subagen itu sendiri, di sebelahnya), tidak pernah di riwayat yang disebut datagram sebuah panggilan alat: baris asisten dengan tool_use SendUserFile ber-id itu dan tepat file-file itu, ditulis dari folder yang sama dan tidak lebih awal dari awal tugas, di file .jsonl di bawah ~/.claude/projects (atau $CLAUDE_CONFIG_DIR/projects, seperti yang diatur untuk aipager sendiri) yang dimiliki pengguna sistem aipager sendiri. Claude Code menulis riwayat percakapannya belakangan, jadi aipager menunggu panggilan itu sampai 20 detik, dan selama pekerjaan sesi masih berjalan (agen latar belakang, panggilan alat) ia menyimpan file-filenya dan mencari lagi nanti. Panggilan yang masih tidak ditemukannya saat tidak ada lagi yang berjalan tidak dikirim dan salinannya dihapus; panggilan yang datang saat tidak ada tugas seperti itu yang berjalan, atau yang datang untuk kedua kalinya, bahkan tidak disalin. Setiap filenya mendapat catatan FileFailed di log audit dengan alasan unverified. Chat mendapat satu baris untuk file itu (⚠️ report.pdf tidak terkirim: aipager tidak bisa memastikan Claude mengirimnya di tugas ini.) hanya kalau riwayat percakapan Claude sendiri menunjukkan panggilan itu juga selama tugas, dan baris itu menyebut file yang tercantum di baris riwayat itu, jadi panggilan palsu tidak bisa memasukkan baris atau nama apa pun ke chat; selain itu tidak ada apa pun di chat. Hanya salinannya yang dikirim, hanya ke chat sesi itu sendiri, setelah jawaban tugas, setelah file-file sesi yang lebih dulu, dan tanpa menahan tugas berikutnya; salinan dihapus begitu terkirim, atau setelah sehari.

Yang tidak dicakup pemeriksaan ini: proses yang berjalan sebagai pengguna sistem aipager sendiri bisa menulis riwayat percakapan Claude sama seperti socket-nya (ia memang sudah bisa membaca file-file itu sendiri). Proses milik pengguna lain yang bisa menjangkau socket juga bisa memalsukan UserPromptSubmit, yang bagi pemeriksaan ini memulai tugas dan menyebut riwayat percakapannya; setelah itu ia bisa membuat aipager mengirim ke chat sesi itu sebuah file yang disebut panggilan SendUserFile yang asli, kalau panggilan itu ditulis di riwayat percakapan itu dari folder yang sama setelah saat itu (misalnya panggilan yang sedang dibuat sesi lain pada saat itu juga), sekali per panggilan. Untuk itu ia juga harus mengirim id milik panggilan yang sedang berjalan itu (tool_use_id), yang tidak bisa dibaca pengguna lain: id itu ada di riwayat percakapan di bawah ~/.claude milik pengguna aipager, dan hook menerimanya lewat input-nya, bukan lewat baris perintahnya. Stop palsu mengakhiri tugas bagi pemeriksaan ini, jadi file yang dikirim tugas itu sesudahnya tidak dikirim. Sesi yang dimulai dengan $CLAUDE_CONFIG_DIR yang berbeda dari milik aipager, atau tugas yang UserPromptSubmit-nya terlewat oleh aipager (diketik di terminal saat aipager sedang restart), tidak mengirim file. Tugas yang dimulai Claude Code tanpa hook dengan cara lain (yang diketahui hanya dua di atas) juga tidak mengirim file; file yang menurut riwayat percakapan Claude diminta di sana mendapat baris di atas. Socket ada di $XDG_RUNTIME_DIR, yang tidak bisa dijangkau pengguna lain, kalau itu diatur; kalau tidak, socket ada di /tmp.

Log audit#

Setiap ketukan Izinkan / Tolak dan setiap jawaban AskUserQuestion menambahkan satu baris JSON ke ~/.claude/aipager-audit.jsonl:

json
{
  "ts": "2026-05-18T15:42:11+00:00",
  "session": "claude-jim",
  "label": "jim",
  "action": "Allowed",
  "tool": "Bash",
  "summary": "ls -la /tmp",
  "user_id": 12345,
  "username": "alice",
  "denied": false
}

Field-nya (untuk set lengkap, lihat aipager/audit.py):

  • ts: stempel waktu UTC ISO 8601, presisi sampai detik.
  • session / label: nama internal dan nama yang mudah dibaca.
  • action: apa yang terjadi (Allowed, Denied, Allowed always, jawaban AskUserQuestion, penolakan otomatis, …).
  • tool / summary: nama alat dan input yang dipendekkan, atau teks pertanyaan.
  • user_id / username: siapa yang mengetuk, supaya di mode tim kelihatan siapa melakukan apa; scope_label / scope_chat_id kalau ada beberapa chat yang diatur.
  • denied: true untuk penolakan apa pun, lewat ketukan atau aturan.

Penulisannya dilakukan sebisanya. Kalau disk penuh atau ~/.claude/ tidak bisa ditulisi, aipager mencatat WARNING di log dan tetap berjalan: tidak ada kehilangan diam-diam, tidak ada crash. Lihat aipager/audit.py.

Log audit di disk hanya ditambahkan. Bersama balasan audit di chat (satu pesan Telegram per keputusan, di bawah kartu kerja), ini memberi dua catatan yang independen.

Batas hak akses#

aipager tidak pernah menaikkan hak aksesnya. Tanpa sudo, tanpa setuid, tanpa doas. Setiap file yang ditulisnya ada di folder home-mu, di /tmp (file kontrol setiap sesi aipager, unduhan, dan log mulai ulang), atau di folder soket kontrolnya ($XDG_RUNTIME_DIR); daftar lengkapnya di arsitektur. Setiap subproses (claude, dtach, installer, claude update) berjalan sebagai pengguna aipager.

Memasang fitur pesan suara dari Telegram ([📦 Pasang fitur pesan suara]) berjalan lewat installer yang memiliki aipager (uv tool install --reinstall aipager[voice], pipx install --force aipager[voice]), atau kalau tidak, memasang paket fitur itu dengan Python milik aipager sendiri (<python> -m pip install): selalu ke environment aipager sendiri, tidak pernah ke Python sistem.

Tombol [🔄 Mulai ulang aipager] di bawah layanan systemd menjadwalkan systemctl --user restart aipager.service di layanan pengguna sementara yang terpisah; di macOS tombol itu menjalankan launchctl kickstart -k; aipager yang kamu jalankan sendiri memulai salinan dirinya yang terlepas, yang menunggu yang lama selesai. Setelah pembaruan, hanya layanan systemd yang memulai ulang dirinya sendiri (lihat perintah → pembaruan). Semua ini berjalan sebagai pengguna yang sama; tidak ada kenaikan hak akses.

Koneksi jaringan#

aipager tidak mendengarkan port TCP apa pun selain loopback. Server Mini App hanya bind ke 127.0.0.1 (ditanam di kode: sengaja tidak ada opsi host) dan hanya bisa dijangkau dari luar lewat tunnel yang dikelola, dijelaskan di bawah. Koneksi keluar:

  • Long polling HTTPS ke api.telegram.org (polling bot Telegram).
  • HTTPS ke telegram.org untuk skrip SDK Mini App (telegram-web-app.js), diunduh sekali saat server Mini App mulai dan disegarkan paling sering sekali sehari; disimpan di cache ~/.local/share/aipager/webapp-sdk/. aipager menyajikan byte itu ke halaman dari asalnya sendiri dan tidak pernah menjalankannya. aipager tidak mendistribusikan skrip ini: skrip itu tidak ada di paketnya, dan saat aipager tidak punya salinannya, halaman memuatnya langsung dari telegram.org seperti dulu.
  • Tunnel Mini App ke Cloudflare, selama menyala (bawaannya menyala). Program cloudflared yang dijalankannya diunduh sekali dari rilis github.com/cloudflare/cloudflared, diperiksa dengan SHA-256 yang dikunci, dan disimpan di cache ~/.local/share/aipager/cloudflared/; cloudflared di PATH-mu tidak pernah dipakai. Dengan URL milikmu sendiri untuk Mini App, semua ini tidak terjadi (lihat di bawah).
  • Pengecekan versi, hanya saat seseorang mengetuk Cek pembaruan atau Perbarui (/update, “Pembaruan” di Mini App), atau saat orang yang boleh memperbarui membuka tab Pengaturan di Mini App (paling sering sekali tiap sepuluh menit per app yang terbuka): pypi.org untuk aipager, dan downloads.claude.ai atau registry.npmjs.org untuk Claude Code, tergantung cara memasangnya. Pembaruan lalu menjalankan installer (yang bicara dengan PyPI atau Homebrew) dan claude update. aipager update di baris perintah hanya menjalankan installer.
  • Pemasangan fitur pesan suara, saat kamu mengetuk tombolnya: installer mengunduh paket dari PyPI, dan model suara diunduh dari Hugging Face (huggingface.co) saat pertama dipakai.
  • HTTPS ke raw.githubusercontent.com (file kunci laporan) dan ke titik penerimaan Sentry, hanya saat kamu mengonfirmasi pengiriman laporan masalah: laporan yang tadi dipratinjau dan ringkasan singkatnya, tidak ada yang lain. Lihat Laporan masalah.

Masuk:

  • Soket datagram Unix di $XDG_RUNTIME_DIR/aipager.sock (dengan cadangan /tmp/aipager.sock saat $XDG_RUNTIME_DIR tidak diatur). Di-bind dan diberi izin lewat chmod saat aipager mulai (aipager/dtach/hook_receiver.py). Izinnya 0o666 supaya proses lokal mana pun bisa mengirim event hook ke sana: kepercayaan yang sama dengan ~/.claude/settings.json, yang memang sudah menentukan apa yang menjalankan hook.

Artinya aipager bukan permukaan serangan jarak jauh. Penyerang di jaringan tidak bisa menjangkaunya tanpa pijakan di komputer itu sendiri.

Teks Claude dan unduhan oleh Telegram sendiri. Server Telegram mengunduh sendiri beberapa alamat yang ada di dalam pesan: blok gambar, video, atau audio di pesan berformat, dan halaman di balik pratinjau tautan. Jawaban Claude, catatannya di kartu kerja, deskripsi agen, dan argumen alat sampai ke Telegram persis seperti yang ditulis Claude, jadi prompt injection bisa membuat Claude menulis alamat yang membawa rahasia keluar, tanpa pemanggilan alat dan tanpa permintaan izin. aipager menutup jalur pertama, dan jalur kedua di tempat Telegram menyediakan pengaturan untuk itu:

  • Di setiap pesan berformat, gambar yang ditulis sebagai ![alt](url) dikirim sebagai tautan biasa dengan teks alt-nya, sedangkan cara penulisan gambar lainnya, serta tag mentah <img>, <video>, <audio>, <source>, <picture>, <figure>, <iframe>, <embed>, <object>, <tg-document>, <tg-collage>, <tg-slideshow>, <tg-button>, dan <tg-button-row>, ditampilkan sebagai teks (aipager/bot/media_guard.py). Di dalam blok kode, misalnya potongan HTML, ini memunculkan \ atau &lt; tambahan.
  • Pratinjau tautan dimatikan di setiap pesan teks biasa dan HTML yang dikirim atau diedit aipager (termasuk versi teks biasa dari jawaban dan kartu), pesan aipager sendiri juga. Tautan Mini App-nya berupa tombol, yang tidak diambil Telegram.

Telegram tidak mendokumentasikan opsi pratinjau untuk pesan berformat; apakah Telegram membuat pratinjau tautan untuk pesan seperti itu belum diperiksa pada layanan yang sebenarnya.

Tunnel Mini App#

Mini App menyala secara bawaan, jadi pada pemasangan standar aipager membuka tunnel ini tanpa bertanya ke siapa pun. Ini pilihan yang disengaja (opsi “nyalakan” yang tidak pernah ditemukan siapa pun adalah fitur yang sebenarnya tidak ada), tapi artinya pemasangan baru langsung terhubung ke internet. Matikan dengan aipager miniapp disable atau taruh enabled: false di bawah miniapp: di aipager.yaml; false yang eksplisit selalu dipatuhi. Perhatikan: blok miniapp: yang tidak ada atau rusak sekarang kembali ke MENYALA, bukan MATI.

Mini App (kecuali --url menggantikannya) menjalankan quick tunnel Cloudflare yang dikelola, mengarah ke server loopback milik aipager sendiri, dan menerbitkan alamat publik https://*.trycloudflare.com yang diberikan kepadanya sebagai tombol menu Telegram dan balasan /app.

Alamat ini bukan rahasia dan memang tidak perlu rahasia: setiap permintaan yang dilayani Mini App diperiksa dengan tanda tangan initData dari Telegram (lihat Batas kepercayaan di atas), dan pemeriksaan itulah yang melindunginya, bagaimanapun URL itu didapat. Mengetahui satu nama host tidak memberi penyerang apa pun yang tidak bisa didapatnya dengan menebak subdomain trycloudflare.com secara acak: gerbang yang sebenarnya adalah pemeriksaan tanda tangan. Perlakukan alamat ini seperti URL lain yang tidak diterbitkan tapi juga tidak dirahasiakan: membiarkannya tetap berjalan tidak apa-apa, tapi menempelkannya ke kanal publik tanpa alasan sebaiknya tidak.

Nama host hanya disimpan di memori: tidak pernah ditulis ke aipager.yaml atau ke mana pun di ~/.config/aipager/. Mulai ulang yang direncanakan (mulai ulang setelah pembaruan, Mulai ulang sekarang, mulai ulang di tempat tanpa layanan) membiarkan tunnel tetap berjalan, jadi alamat, tombol menu, dan Mini App yang sedang terbuka tetap berfungsi: aipager berikutnya baru mengambil alihnya setelah memeriksa bahwa ini boot yang sama, port yang sama, bahwa prosesnya memang cloudflared itu (baris perintahnya), bahwa proses itu masih melaporkan alamat yang sama (~/.claude/aipager-tunnel.json menyimpan hash-nya, tidak pernah alamatnya) dan bahwa alamat itu menjawab. Kalau tidak, aipager menghentikannya dan memulai yang baru, dan tunnel yang dipertahankan tetapi tidak diambil alih aipager mana pun dalam 3 menit dihentikan oleh proses penjaga kecil. Setiap cara berhenti lainnya (Ctrl+C, docker stop, systemctl stop) menghentikan tunnel, dan reboot atau kontainer yang dimulai ulang memberi alamat baru. MINIAPP_KEEP_TUNNEL=0 mematikan fitur mempertahankan ini. Kalau aipager dimatikan paksa (kehabisan memori, kill -9), tunnel tetap berjalan sampai aipager mulai lagi dengan tunnel terkelola menyala (Mini App aktif, tanpa MINIAPP_PUBLIC_URL) lalu mengambil alih atau menghentikannya, atau sampai komputer di-reboot; aipager uninstall juga menghentikannya. Kalau tunnel itu crash di tengah jalan, aipager memulainya ulang dengan jeda yang makin panjang dan menerbitkan alamat baru; kalau setelah beberapa percobaan tunnel tidak juga naik, tombolnya dihapus, bukan dibiarkan menunjuk ke port yang mati.

Mengatur MINIAPP_PUBLIC_URL (atau aipager miniapp enable --url https://…) mematikan tunnel yang dikelola sepenuhnya (program cloudflared tidak pernah diunduh atau dijalankan), dan URL yang diberikan dipakai apa adanya, dengan pemeriksaan initData yang sama di bawahnya. Deteksi otomatis Tailscale (tailscale status --json) tetap menjadi alternatif yang lebih sederhana bagi yang sudah menjalankan Tailscale dan lebih suka tidak bergantung pada Cloudflare sama sekali.

Mengubah pesan suara menjadi teks#

faster-whisper berjalan di dalam proses aipager. Audio diunduh sebagai .ogg ke folder milik chat itu sendiri di bawah /tmp/aipager-files/ (tempat file kiriman masuk, 0700, file-nya 0600), ditranskripsi secara lokal di prosesor, dan file-nya tetap di bawah kendalimu. Tidak ada audio yang keluar dari komputer. Tanpa API pihak ketiga. Tanpa kunci selain token bot yang memang dibutuhkan untuk bicara dengan Telegram.

Kalau kamu menghapus .ogg setelah ditranskripsi, satu-satunya catatan pesan itu dalam teks biasa adalah transkrip yang diketik ke sesi claude (di sana transkrip itu tunduk pada aturan privasi Claude Code sendiri).

Isolasi antarsesi#

Setiap sesi Claude Code berjalan di dtach-nya sendiri. Soket kontrol di /tmp/claude-dtach-<name>.sock milik pengguna aipager; dtach tidak membiarkan pengguna lain menyambung. Setiap sesi dimulai di foldernya sendiri, yang dipilih lewat /new atau Mini App, atau di folder tempat aipager session dijalankan.

aipager tidak mengisolasi sesi satu sama lain di tingkat sistem file: sesi yang terikat ke ~/projects/foo pada dasarnya bisa membaca ~/projects/bar kalau izin Claude Code membolehkannya. Untuk isolasi yang lebih ketat, pakai ~/.claude/settings.json per proyek atau kontainer (image Docker).

Pesan antarsesi Claude#

Claude Code membolehkan satu sesi mengirim pesan ke sesi lain (alat SendMessage-nya). Di sesi penerima, pesan itu sama seperti pesan lain, jadi aipager memutuskan haknya dengan cara yang sama seperti memutuskan hak pesan dari Telegram: berdasarkan siapa yang sebenarnya mengirimnya, bukan berdasarkan isi tulisannya.

  • Pesan membawa hak pengirimnya, tidak pernah lebih. Saat aipager membolehkan sesi mengirim pesan, aipager menulis tanda terima sekali pakai: sidik jari dari teks persisnya, proses Claude yang mengirim (nomor prosesnya dan, di Linux, waktu mulainya), dan hak yang dimiliki tugas itu. Claude Code mencatat pesan yang diterima dengan nomor proses pengirim yang diperiksa kernel, dan tidak pernah memercayai nama yang diberikan pengirim untuk dirinya sendiri. Sebelum tugas yang menerima pesan menjalankan alat apa pun, aipager mencocokkan keduanya dan memberi tugas itu persis hak tugas pengirimnya: pesan pemilik berjalan dengan hak pemilik, pesan anggota dengan hak anggota itu, pesan yang diketik di terminal sesi pengirim tanpa batasan.
  • Tanpa tanda terima, hak dibatasi. Pesan yang tidak bisa dicocokkan aipager (dikirim oleh sesi atau proses Claude yang tidak dimulai aipager, tanda terima yang kedaluwarsa setelah satu jam, pengirim di komputer lain) berjalan dengan aturan paling ketat, tanpa perubahan file, dan tanpa akses internet (hanya membaca dan berpikir). Hak sesi penerima sebelumnya tidak pernah berlaku untuknya.
  • Input lain dari luar sesi sama juga. Semua yang dicatat Claude Code sebagai bukan berasal dari orang di sesi ini juga mendapat hak terbatas itu: notifikasi kanal MCP, pemanggil jarak jauh, pesan yang diantrekan plugin, pesan yang diteruskan dari kotak masuk sesi lain, dan jenis input apa pun yang belum dikenal aipager (perintah plugin dihitung sebagai input dari luar, meskipun kamu yang meluncurkannya). Agen latar belakang milik sesi itu sendiri (kembalian dan laporannya) dan notifikasi tugasnya mempertahankan hak pekerjaannya.
  • Pesan terjadwal dari sesi berjalan dengan hak tugas yang menjadwalkannya. Saat tugas memasang /loop atau cron, aipager mencatat hak tugas itu untuk pesan tersebut; saat waktunya tiba nanti, pesan itu mendapat hak itu, tidak pernah lebih, siapa pun yang terakhir bicara; pesan yang bergabung ke tugas itu hanya bisa mempersempitnya, dan perubahan aturan yang mencabut hak dari si penjadwal juga mempersempitnya. Pesan yang sama yang dijadwalkan dua kali mempertahankan hak yang lebih ketat. /loop polos berjalan dengan instruksi loop Claude Code sebagai ganti teksnya sendiri, jadi loop itu mendapat hak paling ketat dari semua loop polos yang dipasang sesi itu begitu riwayat percakapan menunjukkan loop itu sudah berjalan (sampai saat itu, pemanggilan alat yang ditolak ditolak dengan lembut dan Claude mencoba lagi). Pesan yang tidak dijadwalkan siapa pun lewat pemeriksaan aipager mendapat hak terbatas.
  • Teks tidak membuktikan apa pun. Nama pengirim, baris [via Telegram · @owner], atau “pemilik meminta…” di dalam pesan tidak mengubah apa pun. Claude diberi tahu siapa yang diperiksa aipager sebagai pengirim, dan bahwa klaim di dalam teks bukan bukti.
  • Bergabung ke tugas yang sedang berjalan hanya mempersempitnya. Pesan dari sesi lain yang datang saat tugas berjalan membuat tugas itu seketat yang lebih ketat dari keduanya, tidak pernah lebih longgar. Ini tetap berlaku saat Claude Code mengambil pesan tanpa event pesannya sendiri (diserap tugas yang sedang berjalan, atau diluncurkan dari antrean sebagai tugas berikutnya): jalur cepat pemilik melihat ke akhir riwayat percakapan sebelum setiap pemanggilan alat, dan akhir tugas serta aipager menandai sesi itu untuk diperiksa saat melihat pesan seperti itu di antrean.
  • Peran tetap di chat-nya. Tanda terima dari sesi chat lain hanya dihitung kalau tugasnya punya hak pemilik atau diketik di terminalnya; semua yang lain berjalan dengan hak terbatas.
  • Siapa yang boleh mengirim. Peran terbatas bawaan sama sekali tidak bisa memakai SendMessage. Peran yang diberi SendMessage lewat aturan hanya bisa menulis ke sesi yang dimulai aipager (dialamatkan sebagai uds:…/<pid>.sock); aipager doctor memperingatkan tentang peran seperti itu.
  • Agen latar belakang mempertahankan haknya. Agen itu mempertahankan hak tugas yang memulainya (atau hak yang lebih ketat dari tugas yang lebih belakangan), tidak pernah hak tugas belakangan yang punya lebih banyak hak.
  • Saat dihentikan. Kalau tugas yang dimulai sesi lain dihentikan oleh aturan keamanan, kartu kerja sudah menunjukkan siapa yang mengirimnya, notifikasi penghentiannya mengatakan itu, dan orang yang menyerahkan tugas itu diberi tahu, supaya tugasnya tidak pernah hilang diam-diam: chat sesi pengirim, kalau kedua sesi ada di chat yang sama; kalau tidak, hanya pemilik, di chat pribadi, dan hanya kalau tugas pengirim itu dikendalikan pemilik (atau terminal).

Batasan yang diketahui:

  • Tugas dengan shell (milik pemilik atau admin) berjalan sebagai pengguna sistem yang sama dengan aipager dan bisa memalsukan tanda terima, sama seperti tugas itu memang sudah bisa menulis ulang file kontrol aipager lainnya. Ini model kepercayaan yang sudah ada: beri shell hanya kepada orang yang kamu percayai dengan komputer ini.
  • Sesi Claude yang tidak dimulai aipager sama sekali tidak dikendalikan aipager, siapa pun yang mengirim pesan kepadanya.
  • Di luar Linux, pengirim hanya dikenali dari nomor prosesnya (Claude Code tidak mencatat waktu mulai di sana). Di Linux, catatan penerimaan tanpa waktu mulai tidak cocok dengan apa pun.
  • Claude Code bisa mencatat pesan ke riwayat percakapan sesaat setelah pemanggilan alat pertama tugas itu. Sampai Claude Code melakukannya, pemanggilan yang akan dilarang hak terbatas ditolak dengan lembut (Claude diminta mencoba lagi; tugasnya tidak berhenti). Setelah 8 pemanggilan tanpa catatan itu, tugas berjalan dengan hak terbatas.
  • Jalur cepat pemilik membaca 1 MiB terakhir riwayat percakapan, tidak pernah lebih. Pesan dari sesi lain yang lebih panjang dari itu berakhir dengan baris yang dianggap jalur cepat sebagai pesan seperti itu (setiap baris yang lebih panjang dari 256 KiB dan terpotong oleh jendela itu dihitung begitu). Pesan yang seluruhnya ada lebih jauh ke belakang (lebih dari 1 MiB riwayat ditulis setelahnya sebelum pemanggilan alat berikutnya) ditangkap oleh aipager selama tugas berjalan, atau oleh akhir tugas selama pesan itu masih diantrekan, bukan oleh jalur cepat.
  • Selama sesi punya /loop polos yang terpasang, pemanggilan alat pertama dari tugas mana pun yang tidak dimulai oleh pesan Telegram (termasuk pesan yang diketik di terminal) bisa ditolak dengan lembut sampai Claude Code mencatat pesan tugas itu dan aipager melihat bahwa tugas itu bukan dari loop; lalu Claude mencoba lagi.
  • aipager membaca tugas pesan terjadwal dari apa yang diterima riwayat percakapan sejak tugas itu mulai; di atas 8 MiB, dari 4 MiB pertama dan terakhirnya (bagian di antaranya sudah diperiksa saat masih menjadi bagian terbaru).
  • Hak yang dicatat untuk pesan terjadwal bertahan sampai sesinya diakhiri (/kill): sesi yang berakhir atau dilanjutkan tetap menyimpannya, sama seperti Claude Code menyimpan cron dan jadwal /loop yang masih menunggu. Paling banyak 256 disimpan per sesi, dan menjadwalkan satu lagi di atas itu ditolak bagi semua orang di sesi itu, jadi siapa pun yang bisa menjadwalkan bisa menghabiskannya (lalu mulai sesi dengan nama lain, atau /kill sesi yang ini). Pesan terjadwal yang berjalan tanpa catatan mendapat hak terbatas, atau, di sesi dengan /loop polos, hak loop itu begitu Claude Code mencatatnya ke riwayat percakapan; sampai saat itu aipager membaca tugas itu dari tugas sebelumnya. Ini terjadi pada pesan yang dipasang sebelum versi ini; setelah komputer dinyalakan ulang (catatannya ada di folder sementara sistem, yang dibersihkan saat menyala ulang, dan Claude Code masih bisa membawa kembali jadwal milik sesi yang dilanjutkan dalam satu jam); dan pada cron tahan lama yang dijalankan Claude Code di sesi lain dari folder yang sama setelah sesinya sendiri berakhir. Sesi dengan hak lebih sedikit yang menjadwalkan teks yang sama bisa menurunkan hak pesan itu (tapi tidak pernah menaikkannya).
  • Sesi yang dimulai ulang dengan nama sesi sebelumnya (Ganti) mempertahankan catatan sesi itu, termasuk hak /loop polosnya, sampai /kill.
  • Pesan terjadwal yang dijalankan Claude Code tepat setelah tugas lain tanpa event pesannya sendiri (dari antreannya) mendapat yang lebih ketat dari haknya sendiri dan hak tugas yang diikutinya (setelah tugas yang diketik di terminal, persis haknya sendiri).
  • Pemanggilan alat pertama dari tugas yang diketik di terminal bisa ditolak sampai Claude Code mencatat pesannya ke riwayat percakapan (sampai saat itu aipager membaca tugas sebelumnya).
  • Agen latar belakang yang dimulai dengan hak lebih sempit bisa mengembalikan teks ke tugas belakangan dari pekerjaan yang sama, yang membacanya dengan hak pekerjaan itu, seperti notifikasi tugas Claude Code lainnya.
  • Claude Code bisa menahan pesan sampai disetujui di terminal penerima (pengaturan crossSessionInbound-nya, atau saat dua sesi berjalan di kelas izin yang berbeda, misalnya Akses penuh dan Auto). aipager tidak bisa melepaskan pesan seperti itu dari Telegram; tanda terimanya menunggu sampai satu jam.

Ringkasan ancaman#

AncamanPerlindungan
Orang asing mengirim perintah ke botFilter ID chat menolak
Token bot dicuri/revoke di @BotFather, lalu atur ulang
Pemanggilan alat claude yang disusupiPemeriksaan keamanan aipager menolak apa yang dilarang aturan tugas Telegram; dalam Tanya, aturan Claude Code sendiri di settings.json menentukan apa yang ditanyakannya dan ketukan manusia adalah satu-satunya izin; dalam Auto (bawaan untuk setiap sesi baru) pemeriksaan keamanan Claude Code sendiri menjalankan tanpa bertanya pemanggilan yang dianggapnya aman dan menghentikan yang berisiko untuk manusia; sesi dalam Akses penuh (admin, dan orang di chat pribadinya sendiri) tidak bertanya apa pun, jadi di jalurnya hanya ada pemeriksaan keamanan aipager, dan untuk tugas pemilik sendiri dan pesan terminal tidak ada apa-apa (siapa yang memutuskan)
Orang yang dibatasi di Telegram mendapat hak pemilikTanpa shell, sesi hanya dimulai di folder utama anggota itu sendiri, penulisan dan pencarian dibatasi pada proyek di dalamnya (tidak pernah folder home), tidak ada pembacaan di folder home di luar folder utama, folder utama anggota lain dan unggahan chat lain tidak terjangkau, file kredensial tidak dibaca, path yang dilindungi untuk alat file, pemeriksaan yang rusak menolak (cara aturan diterapkan di tim); hanya sebisanya untuk peran dengan Bash, dan tidak dicakup untuk kasus di “Batasan yang diketahui”
Pesan dari sesi lain mengaku bahwa pemilik yang bicaraPesan berjalan dengan hak tugas pengirim yang terbukti, tidak pernah dengan hak sebelumnya milik sesi penerima; tanpa bukti hanya membaca dan berpikir (pesan antarsesi)
Anggota grup meminjam hak orang lainSetiap pesan berjalan dengan peran pengirimnya di chat asalnya; pesan pengirim lain menunggu tugas yang sedang berjalan; kalau tetap bergabung, aturan paling ketat menang; perintah slash peran terbatas dikurangi menjadi perintah keyboard (cara aturan diterapkan di tim)
Obrolan di grup masuk ke sesiDi grup hanya perintah, balasan ke bot, sebutan bot, dan ketukan pada keyboard bertanda yang diproses (grup)
Anggota yang dihapus tetap punya aksesaipager config memuat ulang aipager tanpa mulai ulang; pesannya yang ditahan dibuang dan tugasnya yang masih berjalan kehilangan hak sebelumnya; mengeluarkannya dari grup Telegram mencegahnya membaca grup itu (grup → muat ulang tanpa mulai ulang)
Pemalsuan log auditHanya ditambahkan; mencegahnya tanpa program penanda tangan terpisah di luar cakupan
Prompt injection membuat Claude menulis alamat yang membawa data keluarGambar dan tag media di teks Claude ditampilkan sebagai tautan atau teks, tidak pernah sebagai media, dan pratinjau tautan dimatikan di pesan teks biasa dan HTML (koneksi jaringan)
Penyerang di jaringanTidak ada port masuk, tidak bisa dijangkau langsung
Kenaikan hak akses lokalTanpa sudo / setuid; aipager tetap di ruang pengguna
Audio pesan suara bocor ke cloudTranskripsi dilakukan lokal
Agen membaca kredensial Claude milik aipager sendiriMemang begitu, bukan bug: lihat Kredensial Claude. Batasi kredensialnya sendiri, bukan file tempatnya disimpan

Lihat juga#