Build kamu bisa aman pagi ini, lalu berubah jadi pintu masuk attacker sore nanti, tanpa satu baris kode aplikasi pun berubah. Penyebabnya sering sepele: nama package internal kamu juga tersedia di registry publik.
Itulah inti dependency confusion defense: memastikan npm, Composer, dan CI kamu nggak pernah salah mengambil package publik saat harusnya mengambil private package. Buat SaaS team, agency, dan enterprise dev, ini bukan teori supply chain security. Ini risiko deploy harian.
Dependency confusion terjadi saat package manager mengambil package dari registry publik karena nama package internal bentrok atau prioritas registry salah. Defense terbaik: pakai scope/vendor namespace, registry pinning, lockfile ketat, CI allowlist, dan monitor nama package internal di registry publik.

Apa Itu Dependency Confusion?
Dependency confusion adalah serangan saat attacker menerbitkan package publik dengan nama yang sama seperti package internal perusahaanmu. Kalau konfigurasi registry longgar, package manager bisa memilih versi publik itu.
Masalahnya makin berbahaya karena package manager biasanya mengejar resolusi tercepat, versi tertinggi, atau registry yang dianggap valid. Akibatnya, package berbahaya bisa masuk ke laptop developer, CI runner, build image, lalu production artifact.
Kenapa Private Packages Jadi Target Empuk?
Private packages sering punya nama yang mudah ditebak: auth-client, billing-sdk, shared-ui, atau company-core. Selain itu, nama itu kadang bocor lewat stack trace, job log, Docker layer, package manifest, atau dokumentasi onboarding.
Attacker cuma perlu satu petunjuk. Setelah itu, mereka bisa publish package publik dengan nama mirip, versi lebih tinggi, lalu menunggu pipeline kamu mengambilnya.
Pola Serangan yang Sering Kejadian
- Name collision: package internal punya nama sama dengan package publik.
- Version bait: attacker publish versi lebih tinggi, misalnya
99.99.99. - Registry fallback: private registry gagal, npm atau Composer fallback ke registry publik.
- CI token exposure: script install mencuri env var, token registry, atau secret deploy.
- Transitive trap: dependency internal menarik dependency lain yang resolusinya belum dipin.
Framework 5 Pagar untuk Dependency Confusion Defense
Jangan mulai dari scanner. Mulai dari rute resolusi package. Scanner bagus, tetapi scanner cuma melihat setelah keputusan install terjadi.
Defense yang matang punya lima pagar berurutan: nama, registry, lockfile, pipeline, monitoring. Kalau satu pagar gagal, pagar berikutnya tetap menahan serangan.
1. Pakai Namespace yang Tidak Ambigu
Untuk npm, gunakan scope organisasi seperti @perusahaan/auth-client, bukan auth-client. Scope membuat resolver lebih jelas dan menurunkan risiko bentrok dengan package publik.
Untuk Composer, gunakan vendor prefix unik seperti perusahaan/billing-sdk. Jangan memakai vendor generik yang bisa membingungkan tim lain atau automation.
2. Pin Registry Per Scope, Bukan Global Saja
Konfigurasi global sering kelihatan rapi, tetapi terlalu mudah berubah di environment berbeda. Karena itu, pin registry per scope di repo.
# .npmrc @perusahaan:registry=https://npm.pkg.github.com/ always-auth=true registry=https://registry.npmjs.org/
Untuk Composer, definisikan repository private secara eksplisit, lalu batasi Packagist bila projectmu memang tidak butuh package publik tertentu. Dokumentasi resminya bisa kamu cek di Composer repositories.
3. Jadikan Lockfile Sebagai Kontrol Keamanan
Lockfile bukan cuma alat stabilitas. Ia juga bukti rute dependency yang disetujui. Karena itu, CI harus pakai npm ci, bukan npm install.
Untuk PHP, gunakan composer install dengan lockfile yang sudah direview. Kamu juga bisa baca pembahasan terkait di Lockfile Kamu Bohong Kalau CI Masih Pakai Install Biasa.

4. Blok Install Script di Tahap yang Tidak Perlu
Bagian yang sering dilupakan: banyak serangan dependency confusion menang lewat lifecycle script. Package belum dipakai aplikasi, tetapi script postinstall sudah jalan dan membaca secret.
Di job audit atau build awal, jalankan install tanpa script bila memungkinkan:
npm ci --ignore-scripts composer install --no-scripts
Setelah itu, jalankan script hanya di tahap yang benar-benar butuh, dengan secret minimal. Ini kecil, tetapi efeknya besar.
5. Buat Allowlist Package Internal
Tim besar butuh kontrol eksplisit. Buat daftar package internal yang sah, registry asal, owner, dan kontak maintainer. Kemudian, validasi daftar itu di CI.
- Package internal harus berasal dari private registry.
- Versi baru harus lewat PR review.
- Registry publik untuk nama internal harus dianggap indikator risiko.
- Token install harus read-only dan scoped.
Checklist Cepat untuk npm
- Gunakan scoped package:
@org/package. - Commit
.npmrcyang memetakan scope ke private registry. - Pakai
npm cidi CI. - Aktifkan lockfile review untuk perubahan dependency.
- Audit script install, terutama
preinstall,install, danpostinstall. - Ikuti praktik dari npm scopes documentation.
Checklist Cepat untuk Composer
- Gunakan vendor namespace unik.
- Definisikan private repository di
composer.json. - Review perubahan
composer.lock. - Pakai
--no-scriptsdi job yang tidak butuh lifecycle script. - Batasi akses token ke repository yang diperlukan saja.
- Cek transitive dependency seperti yang dibahas di plugin yang memakai library rentan yang sama.
Kesalahan yang Terlihat Aman, Padahal Rapuh
Banyak tim merasa aman karena private registry sudah dipakai. Padahal, masalahnya bukan “punya private registry atau tidak”. Masalahnya: apakah setiap resolver di laptop, Docker build, CI, dan production image selalu memilih registry yang sama?
Jadi, jangan audit config pusat saja. Audit semua tempat dependency di-resolve. Kalau environment berbeda menghasilkan dependency tree berbeda, itu celah.
Sinyal Bahaya yang Perlu Kamu Monitor
- Ada package publik baru dengan nama mirip package internal.
- Lockfile berubah tanpa alasan jelas.
- CI mulai mengambil dependency dari domain registry yang tidak biasa.
- Package punya lifecycle script yang mengakses network.
- Versi dependency melonjak drastis.
Untuk konteks risiko supply chain yang lebih luas, kamu bisa cek panduan OWASP CI/CD Security Risks.
FAQ
Apakah dependency confusion hanya menyerang npm?
Tidak. npm sering jadi contoh karena ekosistemnya besar, tetapi Composer, Python, Ruby, dan package manager lain juga punya risiko serupa jika registry resolution longgar.
Apakah private registry otomatis menyelesaikan masalah?
Belum tentu. Private registry membantu, namun kamu tetap perlu registry pinning, lockfile ketat, token scoped, dan CI policy yang konsisten.
Apa langkah pertama yang paling cepat?
Mulai dari inventaris package internal, lalu cek apakah nama itu muncul di registry publik. Setelah itu, pin registry per scope atau vendor namespace.
Penutup: Jangan Biarkan Resolver Memilih Sendiri
Dependency confusion defense yang kuat tidak bergantung pada keberuntungan. Kamu harus membuat resolver punya satu jalan aman: nama jelas, registry jelas, lockfile jelas, CI ketat, dan monitoring aktif.
Kalau timmu mengelola banyak private packages, jadikan checklist di atas sebagai baseline sprint security berikutnya. Mau insight keamanan software supply chain yang praktis dan langsung bisa dipakai?



