Jede Woche erscheint eine neue Meldung über kompromittierte npm-Pakete – ein Phänomen, das Entwickler seit Jahren begleitet.
Doch warum gelingt es immer wieder, die npm-Supply-Chain zu manipulieren? Und vor allem: Was können Teams konkret tun, um ihre Installationen abzusichern?
Die Antwort liegt nicht in einer einzelnen Maßnahme, sondern in einer Kombination aus technischen Schutzmechanismen und bewusster Projektkonfiguration.
Warum npm besonders anfällig für Angriffe ist
Ein typisches Node.js-Projekt listet in seiner package.json etwa 30 direkte Abhängigkeiten. Doch im node_modules-Ordner landen schnell 1.500 oder mehr Pakete – und jedes davon kann potenziell schädlichen Code ausführen.
Dies geschieht nicht erst während der Laufzeit, sondern bereits während der Installation. Durch folgende Mechanismen werden Angriffe erst möglich:
- Installationsskripte: Pakete können über
preinstall,installoderpostinstallbeliebigen Code ausführen. - Wartungslücken: Bei gestohlenen oder geleakten Tokens von Maintainern können Angreifer Pakete übernehmen.
- Typosquatting: Absichtlich falsch geschriebene Paketnamen wie
lodahsstattlodashwerden in kritische Build-Prozesse eingeschleust. - Transitive Abhängigkeiten: Eine scheinbar harmlose Änderung in
package.jsonkann Dutzende neue, unkontrollierte Pakete nach sich ziehen.
Das Problem: All diese Schritte laufen ab, bevor Tests, Linter oder Code-Reviews durchgeführt werden. Ein einziger npm install-Befehl öffnet bereits die Tür für potenziell bösartigen Code.
Installationsskripte deaktivieren: Der erste und wichtigste Schritt
Die einfachste, aber wirksamste Maßnahme ist die Deaktivierung aller Installationsskripte. Dies gelingt über eine .npmrc-Konfiguration im Projektverzeichnis:
# Deaktiviert alle Installationsskripte für dieses Projekt
ignore-scripts=trueAlternativ lässt sich die Option direkt beim Installationsbefehl angeben:
npm install --ignore-scriptsNatürlich hat diese Einstellung Konsequenzen: Pakete mit nativen Abhängigkeiten wie node-gyp, sharp oder better-sqlite3 funktionieren ohne Skripte nicht mehr. Die Lösung: Skripte gezielt nur für vertrauenswürdige Pakete wieder aktivieren.
# Installiert zunächst ohne Skripte
npm install --ignore-scripts
# Installiert anschließend nur die nativen Abhängigkeiten erneut
npm rebuild sharp better-sqlite3Diese Vorgehensweise erfordert zwar eine initiale Einrichtung pro Projekt, eliminiert aber den häufigsten Angriffsvektor in npm-Supply-Chain-Inzidenzen.
npm ci statt npm install in Produktionsumgebungen
Ein oft unterschätzter Risikofaktor ist die automatische Aktualisierung der package-lock.json-Datei. In CI-Pipelines oder Docker-Builds kann dies dazu führen, dass Transitive Abhängigkeiten unbemerkt durch kompromittierte Versionen ersetzt werden.
Hier setzt npm ci an: Der Befehl installiert Pakete strikt gemäß der package-lock.json und scheitert, falls diese nicht zur package.json passt.
# In Dockerfiles oder GitHub Actions
npm ci --ignore-scriptsDiese Kombination aus festen Versionen und deaktivierten Skripten reduziert das Risiko von stillen Upgrades, die unbemerkt Malware einschleusen.
Die package-lock.json ist wichtiger als package.json
In Code-Reviews liegt der Fokus oft auf der package.json, weil sie übersichtlich ist. Doch die wahre Gefahr lauert in der package-lock.json – eine scheinbar minimale Änderung kann Dutzende neue, transitive Abhängigkeiten einführen.
Bei der Prüfung von Pull Requests sollten Entwickler insbesondere auf folgende Warnsignale achten:
- Unbekannte Top-Level-Pakete: Pakete, die nicht zum Projektkontext passen.
- Neu veröffentlichte Pakete: Erst kürzlich veröffentlichte Versionen mit geringer Stabilität.
- Single-Point-of-Failure-Pakete: Pakete mit nur einem Maintainer, aber hoher Download-Zahl.
- Typosquatting-Varianten: Absichtlich falsch geschriebene Paketnamen wie
cross-env-shellstattcross-env.
Tools wie npm audit oder Dependabot erkennen zwar bekannte Sicherheitslücken, doch Zero-Day-Angriffe bleiben oft unerkannt. Eine manuelle Prüfung der package-lock.json-Änderungen bleibt daher ein wichtiger Bestandteil der Sicherheitsstrategie.
Paket-Herkunft verifizieren mit Provenance-Attestierungen
Seit 2023 unterstützt npm Provenance-Attestierungen über Sigstore. Diese ermöglichen es, die Herkunft eines Pakets kryptografisch zu überprüfen – etwa ob es tatsächlich in einer vertrauenswürdigen CI-Pipeline gebaut wurde.
Die Herkunftsinformationen lassen sich mit folgendem Befehl abrufen:
npm view <paketname> --jsonDabei sollte im dist-Block nach dem Feld attestations gesucht werden. Pakete mit Provenance-Attestierungen sind deutlich schwerer zu manipulieren, da sie direkt mit einem öffentlichen Repository und einem spezifischen Build-Prozess verknüpft sind.
Für eigene Paket-Publikationen lässt sich Provenance mit einem einfachen Flag aktivieren:
npm publish --provenance --access publicZusätzliche Absicherungsmaßnahmen für kritische Projekte
Neben den genannten Schritten gibt es weitere Best Practices, die sich mit minimalem Aufwand umsetzen lassen:
- Exakte Versionsangaben: Verzicht auf Wildcards wie
^oder~in derpackage.json. Dies verhindert automatische Updates, die neue Sicherheitslücken einschleusen könnten. - Privater Paket-Proxy: Tools wie Verdaccio ermöglichen das Zwischenspeichern, Spiegeln und Filtern von Paketen. So lassen sich nur geprüfte Versionen in die Produktionsumgebung übernehmen.
- Isolierte Installationsumgebungen: Ein Docker-Container mit eingeschränktem Netzwerkzugriff verhindert, dass Installationsskripte unerwünschte Verbindungen aufbauen.
- Software Bill of Materials (SBOM): Ein Inventar aller Abhängigkeiten, generiert mit CycloneDX, beschleunigt die Reaktion auf Sicherheitsvorfälle.
Realistische Erwartungen an die Sicherheit
Es gibt keine Konfiguration, die npm-Installationen absolut sicher macht. Der Grund liegt im Vertrauensmodell: Entwickler führen täglich Code aus unbekannten Quellen aus.
Doch jede der genannten Maßnahmen erhöht die Hürden für Angreifer. Der Fokus sollte auf einer mehrschichtigen Verteidigung liegen:
- Reduzierung der Angriffsfläche durch Deaktivierung von Skripten.
- Verlangsamung von Updates durch feste Versionen und Lockfiles.
- Erhöhung der Transparenz durch Herkunftsprüfung und SBOMs.
- Eingrenzung des Schadens durch isolierte Umgebungen.
Die Implementierung dieser Strategien erfordert zwar einen initialen Aufwand, zahlt sich jedoch langfristig durch stabilere und sicherere Projekte aus.
Langfristig wird die npm-Community weitere Mechanismen entwickeln, um Supply-Chain-Angriffe zu erschweren. Bis dahin bleibt die Kombination aus technischer Absicherung und bewusster Projektkonfiguration der beste Weg, um das Risiko zu minimieren.
KI-Zusammenfassung
Learn how to harden npm installations against supply chain threats with five practical steps—from disabling install scripts to verifying package provenance.