Hardening memori coding agent yang tersinkron via SSH perlu diperlakukan sebagai masalah keamanan data dan eksekusi, bukan sekadar konfigurasi Git atau transfer berkas. Memori agent dapat berisi konteks repository, keputusan teknis, token yang tidak sengaja tersimpan, hingga instruksi yang kelak dibaca agent lain. Bila kanal sinkronisasi dikompromikan, penyerang dapat mencuri data, merusak riwayat, atau menyisipkan instruksi berbahaya.

Tren proyek seperti Deja Vu menunjukkan kebutuhan untuk membawa memori kerja agent lintas sesi atau mesin. Pola ini berguna, tetapi sinkronisasi harus dirancang sebagai jalur input tidak tepercaya. Prinsip utamanya adalah: agent hanya boleh melakukan operasi sinkronisasi yang sempit, server harus memvalidasi semua data, dan setiap perubahan harus dapat ditelusuri.

Threat model: apa yang harus dilindungi?

Mulailah dengan mendefinisikan aset, pelaku, dan dampak kegagalan. Jangan mengasumsikan bahwa karena koneksi menggunakan SSH, isi memori otomatis aman.

  • Pencurian private key. Private key agent yang bocor dapat dipakai untuk mengakses host sinkronisasi, terutama jika key tersebut mengizinkan shell interaktif atau akses ke banyak repository.
  • Instruksi berbahaya dalam memori. Agent atau pengguna yang terkompromi dapat menulis teks seperti perintah untuk mengabaikan kebijakan, mengunggah source code, atau menjalankan command destruktif. Ini adalah bentuk prompt injection yang persisten.
  • Kebocoran secret. Memori dapat menyimpan API key, token CI, password, file .env, URL database, atau potongan konfigurasi sensitif.
  • Perubahan riwayat tanpa audit. Penyerang dapat menghapus, menulis ulang, atau mengganti memori sehingga tim tidak dapat membedakan perubahan normal dari manipulasi.
  • Abuse sinkronisasi. Endpoint pemicu sync dapat dibanjiri, dipakai untuk mengunggah payload besar, memicu konflik tulis, atau menjadi sarana denial of service.

Tujuan desain bukan membuat agent “tepercaya sepenuhnya”. Tujuannya adalah membatasi blast radius jika satu agent, key, workstation, atau workflow otomatisasi gagal diamankan.

Desain akses SSH dengan hak minimum

Gunakan akun Unix dan key terpisah untuk setiap agent

Buat satu akun Unix khusus untuk setiap identitas agent atau setiap kelas agent dengan tingkat kepercayaan yang sama. Jangan gunakan akun developer bersama, akun deployment, atau key SSH yang sama untuk agent dan manusia. Dengan pemisahan ini, pencabutan akses satu agent tidak menghentikan sinkronisasi agent lain.

  • Simpan private key agent pada secret store atau mekanisme kredensial runtime, bukan di repository atau image container.
  • Beri nama dan inventarisasi key berdasarkan agent, lingkungan, dan tanggal kedaluwarsa.
  • Rotasi key secara berkala dan segera cabut key saat ada indikasi kebocoran.
  • Pin host key server melalui known_hosts; jangan menonaktifkan verifikasi host hanya agar otomatisasi “berjalan”.

Pada server, nonaktifkan autentikasi password untuk akun agent dan hilangkan kemampuan yang tidak diperlukan. Contoh berikut adalah baseline pada sshd_config; sesuaikan dengan kebijakan host dan uji konfigurasi di lingkungan non-produksi terlebih dahulu.

Match User agent_mem_a
    PasswordAuthentication no
    AuthenticationMethods publickey
    PermitTTY no
    AllowTcpForwarding no
    X11Forwarding no
    PermitTunnel no
    GatewayPorts no
    PermitUserRC no
    MaxSessions 1

Validasi sintaks konfigurasi sebelum reload daemon, misalnya dengan sshd -t. Pastikan juga Anda masih memiliki sesi administratif terpisah agar tidak mengunci diri sendiri dari server.

Paksa command dan jangan berikan shell

Key agent sebaiknya tidak membuka shell umum. Gunakan forced command pada authorized_keys agar key hanya menjalankan wrapper sinkronisasi. Opsi restrict pada OpenSSH modern menonaktifkan sejumlah kemampuan tambahan; untuk server yang lebih lama, gunakan opsi pembatas individual yang setara dan verifikasi dokumentasi versi OpenSSH yang dipakai.

restrict,command="/usr/local/libexec/agent-memory-sync" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... agent-mem-a-2025q1

Jangan membuat wrapper yang meneruskan SSH_ORIGINAL_COMMAND ke shell, eval, atau sh -c. Pola tersebut dapat mengubah pembatasan SSH menjadi remote command execution. Wrapper harus menerima daftar command yang kecil dan persis.

#!/bin/sh
# /usr/local/libexec/agent-memory-sync
set -eu
umask 077

command="${SSH_ORIGINAL_COMMAND:-}"
case "$command" in
  "memory-sync pull")
    exec /usr/local/libexec/memory-export
    ;;
  "memory-sync push")
    exec /usr/local/libexec/memory-import
    ;;
  *)
    logger -p authpriv.warning \
      "agent-memory-sync: rejected command: $command"
    exit 126
    ;;
esac

Dalam contoh ini, memory-export dan memory-import adalah program server-side dengan lokasi repository yang sudah tetap. Agent tidak boleh mengirim path tujuan, nama branch arbitrer, atau argumen Git mentah. Jika memakai Git sebagai media penyimpanan, lebih aman menerima payload pada staging area lalu membuat commit di server daripada memberi akses langsung ke repository bare.

Validasi memori sebelum menjadi riwayat

Batasi path, format, ukuran, dan struktur

Jadikan memori sebagai format data yang eksplisit, misalnya JSON atau Markdown dengan front matter yang dibatasi. Hindari sinkronisasi seluruh direktori kerja agent. Server hanya boleh menerima path yang telah di-allowlist, misalnya memories/agent-mem-a.json, dan harus menolak traversal seperti ../.ssh/authorized_keys, symlink berbahaya, file device, serta arsip dengan nama path ambigu.

Validasi minimal pada proses import meliputi:

  • ukuran request dan ukuran file maksimum;
  • jumlah entri maksimum per sinkronisasi;
  • encoding UTF-8 yang valid;
  • schema version yang didukung dan field wajib;
  • allowlist kategori, sumber, dan path memori;
  • penolakan field tidak dikenal bila schema harus ketat.
{
  "schemaVersion": 1,
  "agentId": "agent-mem-a",
  "entries": [
    {
      "id": "2025-03-08-auth-decision",
      "kind": "engineering-note",
      "text": "Gunakan refresh token rotasi untuk sesi web.",
      "sourceCommit": "abc123"
    }
  ]
}

Schema membantu menjaga konsistensi, tetapi tidak cukup untuk menangani instruksi berbahaya. Perlakukan field teks sebagai data tidak tepercaya saat dibaca kembali oleh agent. Pisahkan memori faktual, keputusan terverifikasi, dan saran yang belum ditinjau. Jangan izinkan isi memori mengganti system prompt, kebijakan keamanan, konfigurasi tool, atau daftar command yang boleh dijalankan.

Pindai secret sebelum commit

Jalankan pemindaian secret pada staging area, bukan setelah data masuk ke riwayat utama. Pemindai dapat menggabungkan pola token yang dikenal, pemeriksaan entropi, dan aturan organisasi seperti blokir file .env, private key PEM, atau credential URL. Jangan menulis nilai secret mentah ke audit log atau pesan error.

Jika pemindaian menemukan kandidat secret, tolak payload, simpan hanya metadata aman seperti jenis temuan dan hash payload, lalu beri mekanisme remediasi. Pemindaian berbasis pola dapat menghasilkan false positive; gunakan proses override yang diaudit dan dibatasi untuk operator, bukan bypass otomatis oleh agent.

Integritas riwayat, permission, dan audit

Batasi permission direktori dan lindungi riwayat

Direktori memori tidak boleh dapat dibaca oleh semua pengguna host. Parent directory sebaiknya dimiliki administrator, sedangkan staging area dan repository hanya dapat diakses oleh service account sinkronisasi yang diperlukan. Terapkan umask 077 pada proses import agar file baru tidak terbaca grup atau pengguna lain secara tidak sengaja.

Jangan mengandalkan hash Git saja sebagai audit trail. Hash mendeteksi perubahan dalam graph yang Anda lihat, tetapi penyerang yang memiliki hak tulis penuh dapat mengganti referensi dan objek. Untuk perubahan yang diterima, server dapat membuat commit sendiri dan menandatanganinya dengan signing key yang terlindungi. Alternatif tambahan adalah hash chain atas payload yang sudah dinormalisasi, lalu mengirim ringkasan hash tersebut ke sistem log eksternal yang tidak dapat ditulis agent.

  • Tolak force push dan penghapusan ref dari jalur agent.
  • Simpan salinan audit atau snapshot di storage terpisah dengan retensi yang sesuai.
  • Verifikasi signature atau hash chain saat restore dan sebelum memori dipakai ulang.
  • Jangan menyimpan private signing key pada akun Unix agent.

Buat audit log yang berguna tanpa membocorkan data

Setiap operasi pull, push, penolakan validasi, dan rotasi key perlu menghasilkan event terstruktur. Minimal catat waktu, identitas agent, fingerprint key atau identitas koneksi yang tersedia, request ID, jenis operasi, ukuran payload, hasil validasi, hash payload, commit yang dibuat, dan alasan penolakan. Hindari mencatat isi memori penuh atau secret yang ditemukan.

Catatan: log lokal saja tidak cukup jika host sinkronisasi ikut terkompromi. Kirim audit log ke sistem terpusat dengan kontrol akses dan retensi terpisah.

Gunakan locking untuk konflik tulis

Dua agent dapat mencoba memperbarui memori yang sama pada saat bersamaan. Terapkan lock eksklusif di sisi server pada fase commit, misalnya dengan flock atau mekanisme lock pada database. Jangan menahan lock ketika transfer jaringan berlangsung; lakukan transfer ke staging, validasi, lalu ambil lock hanya ketika memeriksa versi dasar dan menulis commit.

flock -w 10 /var/lock/agent-memory.lock \
  /usr/local/libexec/commit-validated-memory

Gunakan pemeriksaan versi dasar atau compare-and-swap untuk mendeteksi perubahan sejak agent melakukan pull. Saat konflik terjadi, jangan memilih “last write wins” tanpa kebijakan eksplisit. Kembalikan konflik kepada agent atau antrekan proses merge yang dapat diaudit.

Mencegah abuse pada pemicu sinkronisasi

Banyak sistem tidak mengekspos SSH langsung ke agent. Sebagai gantinya, webhook, API internal, scheduler, atau queue memicu job yang kemudian melakukan sync. Endpoint pemicu ini tetap bagian dari attack surface.

  • Autentikasi pemanggil dan otorisasi berdasarkan identitas agent, bukan hanya shared secret global.
  • Terapkan rate limit per agent, per kredensial, dan bila relevan per alamat sumber.
  • Gunakan debounce atau coalescing agar banyak trigger dalam waktu singkat menjadi satu job.
  • Batasi ukuran payload, durasi job, jumlah job aktif, dan kapasitas antrean.
  • Gunakan idempotency key agar retry tidak menciptakan commit duplikat.
  • Catat trigger yang ditolak dan alert bila terjadi lonjakan penolakan atau kegagalan autentikasi.

Rate limit bukan pengganti autentikasi. Ia membatasi dampak abuse, sedangkan autentikasi dan otorisasi menentukan siapa yang boleh meminta sinkronisasi.

Alur implementasi yang direkomendasikan

  1. Agent membuat payload memori dalam schema yang telah ditentukan dan mengirimnya melalui key SSH khusus.
  2. Forced command mengarahkan request hanya ke program import atau export yang tetap.
  3. Program import menyimpan payload di staging area dengan permission ketat.
  4. Server memvalidasi schema, path, ukuran, encoding, dan kebijakan konten; lalu menjalankan pemindaian secret.
  5. Server mengambil lock, memeriksa versi dasar, membuat perubahan atomik, dan menghasilkan commit atau catatan integritas.
  6. Server mengirim audit event ke sistem terpusat dan mengembalikan ID commit atau status konflik ke agent.

Uji desain ini dengan skenario negatif: key dicabut, command SSH tidak dikenal, payload terlalu besar, path traversal, token palsu dan token nyata, dua push paralel, force push, serta endpoint trigger yang dibanjiri. Hardening yang baik terlihat dari kemampuan sistem menolak input salah secara aman, bukan hanya dari keberhasilan sync pada kondisi normal.