Sicheres Coding mit AI - Supply-Chain-Schutz für Node-Projekte und Guardrails für Agenten
Praktische Sicherheits-Defaults für npm und pnpm, damit AI-gestütztes Coding nicht zur Supply-Chain-Falle wird.
Kurzfassung: Wer KI oder Agenten Code schreiben und Dependencies installieren lässt, braucht Sicherheits-Geländer. Dieser Artikel zeigt praktische Defaults, sinnvolle Workflows und „Least Privilege“ für das Ausführen von Server-Code.
Warum das Thema gerade wichtig ist
Im JavaScript-Ökosystem kommen neue Pakete und Updates täglich. Das ist super für Innovation – aber es öffnet auch die Tür für Supply-Chain Angriffe.
Aktuelles Beispiel: kompromittierte npm-Versionen rund um das Axios-Ökosystem (malicious versions / Remote Access Trojan). Hintergrund & Analyse:
Typische Angriffswege:
- Maintainer-Account kompromittiert
- Dependency-Tree/Transitive Dependencies
- Typosquatting (ähnlicher Paketname)
- bösartiges Update, das zunächst „normal“ aussieht
Ziel: Selbst wenn etwas schiefgeht, soll der Schaden klein bleiben.
1) 60 Sekunden: Was ist npm überhaupt?
- npm ist Paketmanager + Registry für Node/JavaScript.
- Du installierst Pakete mit
npm install <paket>. - Abhängigkeiten stehen in
package.json. - Installierte Pakete landen in
node_modules. - Ein Lockfile (
package-lock.json,pnpm-lock.yaml) pinnt exakte Versionen.
Wichtig: Du holst dir Code von außen. Das ist der Kern des Supply-Chain Risikos.
2) Die größten Risiken beim Installieren
2.1 Bösartige Updates oder neue Pakete
- Neue Versionen können kompromittiert sein und werden oft erst später entdeckt.
2.2 Lifecycle-Skripte beim Install
Pakete können beim Install automatisch Skripte ausführen:
preinstallinstallpostinstall
Das kann legitime Gründe haben (z. B. native Binaries, Build-Schritte), aber es ist auch ein Einfallstor.
3) Die 2 wichtigsten Sofort-Maßnahmen (Copy/Paste)
3.1 Release-Cooldown: keine brandneuen Releases
Setze einen Cooldown, z. B. 7–14 Tage.
Wichtig: Diese Option ist aktuell ein pnpm-Feature, nicht Teil der npm-CLI.
pnpm-workspace.yaml:
minimumReleaseAge: 20160
20160 Minuten entsprechen 14 Tagen.
Warum das hilft: Wenn ein kompromittiertes Paket „gerade erst“ veröffentlicht wurde, nimmst du es nicht sofort mit.
Tipp: Für produktive Systeme sind 7–14 Tage oft ein guter Start. Für sehr sensible Projekte ggf. 30 Tage.
3.2 Install-Skripte blocken
.npmrc:
ignore-scripts=true
Was passiert dann? Dependencies führen keine pre/postinstall Skripte aus. Das reduziert Risiko – aber manche Pakete brauchen diese Schritte und können dann scheitern.
4) Warum postinstall manchmal „nötig“ ist (und wie du damit umgehst)
Einige Pakete benötigen beim Install:
- Download/Setup von nativen Binaries
- Kompilierung
- Plattform-spezifische Checks
Wenn du ignore-scripts=true aktivierst, kann das zu Fehlern führen.
Pragmatischer Umgang:
- Standard: Scripts aus (sicher)
- Ausnahme: Scripts temporär erlauben, wenn du das Paket wirklich brauchst
- Danach wieder auf „Scripts aus“ zurück
Wichtig: Nie Scripts dauerhaft global aktivieren „damit alles klappt“, wenn du eigentlich Sicherheit willst.
5) KI/Agenten: Die wichtigste Policy
Wenn KI/Agenten an einem Repo arbeiten, ist das Risiko nicht „KI böse“, sondern: KI ist schnell.
5.1 Goldene Regel
Agenten dürfen keine Dependencies installieren ohne Approval.
5.2 Minimal-Policy (Copy/Paste)
Wenn die KI ein Paket installieren will, muss sie liefern:
- Warum ist das Paket nötig? (konkreter Use Case)
- Alternativen (native Lösung? existierendes Paket im Projekt?)
- Risiko-Check (Repo/Owner, Downloads, Wartung, letzte Releases)
- Minimal Scope (kleinstmöglicher Zusatz, keine „Tool-Suppe“)
- Testplan (wie verifizieren wir, dass nichts kaputt / bösartig ist?)
5.3 Workflow (empfohlen)
- KI schlägt Kommandos nur vor („Proposed commands“)
- Installationen und Updates werden bewusst freigegeben
- Danach laufen Tests, Lint und Build
6) Reproducible Installs: Lockfile + CI
Das ist unspektakulär, aber extrem wirksam.
6.1 Lockfile committen
package-lock.jsonoderpnpm-lock.yamlgehört ins Repo.
6.2 CI-Install strikt
- npm:
npm ci - pnpm:
pnpm install --frozen-lockfile
Warum: Keine „überraschenden“ Versionssprünge im Build.
7) Audits (schnell, aber nicht blind vertrauen)
npm auditist ein guter Start.- Aber: nicht jedes Audit-Finding ist ein echtes Risiko im konkreten Projektkontext.
Pragmatik:
- Im CI mindestens high/critical blocken, oder warnen und manuell prüfen.
8) pnpm & Yarn: kurzer Vergleich
Wenn pnpm ohnehin im Raum steht:
- pnpm hat starke Supply-Chain Features und ist in vielen Teams beliebt.
- Wichtiges Highlight: pnpm kann Build-/Lifecycle-Skripte per Allowlist steuern (statt „alles oder nichts“).
8.1 pnpm: Allowlist für Build-Skripte (Whitelist)
pnpm v10 setzt stark auf das Prinzip: Dependencies dürfen nicht automatisch beliebige Install-Skripte ausführen. Stattdessen lässt sich explizit festlegen, welche Pakete Build-Skripte ausführen dürfen.
Praktisch läuft das über eine Allowlist/Policy wie z. B.:
onlyBuiltDependencies(nur diese Dependencies dürfen Build-Skripte ausführen)- bzw. ein Workflow mit
pnpm approve-builds(interaktiv erlauben, was bauen darf)
In der Praxis bietet pnpm hier einen sinnvollen Mittelweg zwischen „Scripts komplett aus“ und „Scripts immer an“.
9) Runtime-Sicherheit: „Least Privilege“ für Node/Bun/Server-Code
Selbst wenn ein bösartiges Paket reinkommt, soll es nicht alles lesen oder schreiben können.
9.1 Die wichtigsten Prinzipien
- Nicht als root laufen lassen
- Dateisystemzugriff minimieren (nur Projekt/Uploads, nicht das ganze Home)
- Secrets isolieren (nicht überall Env Vars verteilen)
- Netzwerkzugriff minimieren (nur benötigte Hosts/Ports)
9.2 Praktischste Lösung: Container (Docker)
- Prozess läuft als non-root
- Optional read-only filesystem
- Nur definierte Volumes rw
- Capabilities droppen
Vorteil: leicht umzusetzen und in vielen Setups praktikabel.
9.3 Alternative: systemd Sandboxing (Linux)
- Service läuft unter eigenem User
ProtectSystem=strictReadWritePaths=nur benötigte PfadeNoNewPrivileges=true
9.4 Alternative für strikte Permissions: Deno
Deno bringt ein eingebautes Permission-System für Datei-, Netzwerk- und Umgebungszugriffe mit. Dadurch lassen sich Berechtigungen explizit freigeben, statt standardmäßig alles zu erlauben.
Wichtig dabei: Modul-Imports und allgemeiner Dateizugriff sind nicht exakt dasselbe. Statisch erkennbare Imports funktionieren in Deno auch ohne --allow-read, aber normaler Lesezugriff auf lokale Dateien bleibt weiterhin gesperrt.
Beispiel:
- Ohne
--allow-readkann ein Prozess nicht beliebig lokale Dateien lesen.
9.5 Bun
Bun ist Node-kompatibel, aber ohne vergleichbares Permission-System wie Deno. → Isolation eher über Container/systemd/OS.
10) Copy/Paste: sichere Defaults fürs Projekt
10.1 pnpm-workspace.yaml für Release-Cooldown
# Cooldown gegen brandneue Releases
minimumReleaseAge: 20160
10.2 .npmrc für Install-Skripte
# Keine Lifecycle-Skripte von Dependencies
ignore-scripts=true
10.3 Team-Regel (Kurz)
- Keine Installs ohne Approval
- Immer: Zweck, Alternativen, Scope, Testplan
11) Häufige Fragen
„Blockiert ignore-scripts nicht total viel?“
Ja, manche Pakete. Genau deshalb ist es ein Security Default. Wenn Scripts nötig sind:
- temporär erlauben
- möglichst minimal und bewusst halten
„Was ist mit Vibe Coding?“
Vibe Coding ist okay – aber Package-Install ist eine Sicherheitsgrenze. Dort braucht es zusätzliche Regeln.
12) Nächste Schritte
- Sichere Install-Defaults im Projekt standardisieren
- Klare Freigabe-Regeln für KI-gestützte Dependency-Änderungen definieren
- Server-Runtimes mit Container- oder System-Sandboxing absichern