Pada 8 September 2025, penyerang mengkompromikan 18 paket npm yang banyak digunakan — termasuk chalk, debug, ansi-styles, dan strip-ansi — yang secara kolektif diunduh lebih dari 2,6 miliar kali per minggu. 80% dependensi aplikasi tetap tidak diperbarui selama lebih dari setahun, bahkan ketika 95% komponen yang rentan memiliki versi yang diperbaiki tersedia. Statistik ini mendefinisikan taruhannya: supply chain Anda seaman maintainer paling tidak aman dari paket apa pun di pohon dependensi Anda.
Menjalankan `npm audit` memeriksa paket yang diinstal terhadap database advisory npm — kerentanan yang diketahui dengan CVE yang diterbitkan. Ini mengembalikan daftar kerentanan dengan rating keparahan, versi paket yang terpengaruh, dan perbaikan yang direkomendasikan. Keterbatasan: `npm audit` hanya menangkap kerentanan yang diketahui dengan advisory yang diterbitkan. Tidak dapat mendeteksi eksploitasi zero-day, paket berbahaya, serangan typosquatting, atau versi berbahaya yang baru diterbitkan dari paket yang sah.
Output npm audit mencakup tingkat keparahan: critical (dapat dieksploitasi, dampak tinggi), high (dapat dieksploitasi, dampak signifikan), moderate (memerlukan kondisi yang tidak biasa), dan low (dampak minimal). Untuk aplikasi produksi, perbaiki critical dan high segera. Moderate dapat dijadwalkan di sprint berikutnya. Low dapat di-batch.
Package.json Anda mencantumkan dependensi langsung — paket yang Anda instal secara eksplisit. Dependensi transitive adalah paket yang diperlukan oleh dependensi langsung Anda. Aplikasi Next.js tipikal memiliki 30-50 dependensi langsung dan 500-1.000 dependensi transitive. Sebagian besar kerentanan yang ditandai oleh `npm audit` ada dalam dependensi transitive.
npm Dependency Landscape (2025 reality):
────────────────────────────────────────────────────────────
Typical Next.js app:
package.json: ~40 direct dependencies
node_modules: ~800 total packages (transitives included)
↑ you didn't install 760 of these directly
Vulnerability sources:
Direct deps: You chose these → easy to update
Transitive: Pulled by your deps → harder to control
Sept 2025 supply chain attack:
Packages compromised: chalk, debug, ansi-styles, strip-ansi
Weekly downloads: 2.6 BILLION combined
Attack vector: Phishing against package maintainer
Detection: Not by npm audit (no CVE yet)
npm audit severity levels:
critical → Fix immediately (RCE, SQLi, auth bypass)
high → Fix this sprint
moderate → Schedule within 30 days
low → Batch with monthly updates
info → Review, may be false positive
npm audit --audit-level=high ← CI threshold I use
Fails CI only on high/critical → meaningful signal
Low/moderate reviewed weekly as separate taskDari pengalaman saya mengelola dependensi proyek Next.js: jalankan `npm audit --audit-level=high` di CI daripada hanya `npm audit`. Level audit default adalah low, yang menandai kerentanan yang biasanya informatif dan dapat menyebabkan 'audit fatigue' — pengembang mulai mengabaikan output karena selalu ada item yang ditandai. Mengatur --audit-level=high membuat CI gagal hanya untuk kerentanan high dan critical, memberi alert makna.
Pertahanan terbaik terhadap kerentanan yang diketahui adalah tetap terkini — sebagian besar CVE memiliki versi yang diperbaiki tersedia. `npm outdated` mencantumkan paket dengan pembaruan yang tersedia. Gunakan `npx npm-check-updates` (ncu) untuk memperbarui package.json ke versi terbaru. Proses pembaruan yang aman: jalankan `ncu -u --target minor` untuk memperbarui versi minor (semver menjamin tidak ada perubahan yang merusak), tes, lalu tangani pembaruan versi major satu per satu.
GitHub Dependabot secara otomatis membuat pull request untuk pembaruan dependensi. Aktifkan dengan menambahkan file .github/dependabot.yml. Konfigurasikan untuk memperbarui ekosistem npm mingguan, mengelompokkan pembaruan patch dan minor bersama, dan memperbarui GitHub Actions secara terpisah. PR Dependabot mencakup jenis perubahan (patch/minor/major), tautan changelog, dan skor kompatibilitas.
# Weekly dependency audit workflow
npm audit --audit-level=high # check for critical/high CVEs
npm outdated # list packages with updates available
npx npm-check-updates -u --target minor # update minor versions in package.json
npm install # install updated packages
npm test && npm run e2e # verify nothing broke
# Fix transitive dependency vulnerability (can't update the parent yet):
# In package.json, use overrides:
{
"overrides": {
"vulnerable-transitive-package": "^2.1.0" // force safe version
}
}
# .github/dependabot.yml — automated PR for updates
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: weekly
day: monday
groups:
patch-and-minor:
patterns: ["*"]
update-types: ["minor", "patch"]
ignore:
- dependency-name: "@types/*"
update-types: ["version-update:semver-major"]
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: monthly
# CI — npm audit check in GitHub Actions
- name: Security audit
run: npm audit --audit-level=high
# Fails build if high or critical vulnerabilities found
# Use npm ci (not npm install) in CI — respects lockfile exactly
- name: Install dependencies
run: npm ci
# Fails if package-lock.json is out of sync with package.jsonUntuk proyek dengan jaminan lebih tinggi, jauh di luar `npm audit`. Socket.dev memindai paket untuk perilaku mencurigakan (akses jaringan, eksekusi proses, kode yang diobfuskasi) yang tidak memicu CVE. Snyk menawarkan pemindaian dependensi dengan lebih banyak konteks daripada npm audit. OWASP npm Security Cheat Sheet merekomendasikan: mengunci dependensi transitive dengan lockfile, menggunakan `npm ci` alih-alih `npm install` di CI.
File package-lock.json menyematkan versi tepat dari setiap paket dalam pohon dependensi Anda, termasuk transitive. Tanpanya, `npm install` menyelesaikan versi terbaru dari setiap paket — artinya deployment dapat menarik versi berbahaya yang baru diterbitkan dari dependensi transitive yang bersih saat pengembangan. Selalu commit lockfile Anda, dan verifikasi itu tidak berubah sebelum deploy.
Keamanan bukan satu-satunya risiko dependensi — lisensi adalah risiko hukum. Paket dengan lisensi GPL dalam pohon dependensi Anda dapat memaksakan persyaratan copyleft GPL pada seluruh proyek Anda. Gunakan `license-checker` (CLI) atau FOSSA (komersial, dengan integrasi CI) untuk memindai dependensi Anda untuk jenis lisensi. Untuk proyek komersial, Anda biasanya menginginkan lisensi MIT, BSD, Apache-2.0, dan ISC.
Yang benar-benar saya lakukan: Senin — jalankan `npm audit` dan periksa kerentanan critical/high baru. Mingguan — tinjau dan merge PR Dependabot untuk pembaruan patch dan minor setelah CI lulus. Bulanan — jalankan `ncu --target major` untuk melihat pembaruan major yang tertunda. Triwulan — audit penuh: kepatuhan lisensi, jumlah dependensi, dan dampak ukuran dependensi utama menggunakan `bundlephobia`.