3 Punkte von GN⁺ 2025-10-31 | 2 Kommentare | Auf WhatsApp teilen
  • Im NPM-Repository wurden mehr als 100 bösartige Pakete zum Diebstahl von Zugangsdaten hochgeladen, die seit August unentdeckt blieben und zusammen mehr als 86.000 Mal heruntergeladen wurden
  • Das Sicherheitsunternehmen Koi berichtet, dass eine als „PhantomRaven“ bezeichnete Angriffskampagne die NPM-Funktion Remote Dynamic Dependencies (RDD) missbrauchte, um 126 bösartige Pakete zu verbreiten
  • RDD ist eine Struktur, die es Paketen erlaubt, Abhängigkeitscode dynamisch von nicht vertrauenswürdigen Domains herunterzuladen, wodurch sie von statischen Analysewerkzeugen nicht erkannt wird
  • Die Angreifer nutzten diese Funktion, um bösartigen Code über HTTP-Verbindungen herunterzuladen; in den Paketmetadaten wurde dennoch „0 Dependencies“ angezeigt, sodass Entwickler und Security-Scanner dies nicht bemerkten
  • Diese strukturelle Schwachstelle macht die Grenzen des Sicherheitsmanagements im NPM-Ökosystem und die Risiken automatischer Installationsmechanismen deutlich

Ausbreitung bösartiger Pakete im NPM-Repository

  • Angreifer luden seit August mehr als 100 Pakete zum Diebstahl von Zugangsdaten hoch, indem sie strukturelle Schwächen des NPM-Code-Repositorys ausnutzten
    • Die meisten Pakete wurden verbreitet, ohne entdeckt zu werden; die kumulierte Zahl der Downloads lag bei mehr als 86.000
  • Das Sicherheitsunternehmen Koi bezeichnete diesen Angriff als PhantomRaven-Kampagne und analysierte, dass eine bestimmte NPM-Funktion missbraucht wurde
    • Laut Koi befanden sich von den 126 bösartigen Paketen zum Zeitpunkt der Artikelerstellung noch etwa 80 weiterhin auf NPM

Die verwundbare Struktur von Remote Dynamic Dependencies (RDD)

  • RDD ist eine Funktion, die es Paketen erlaubt, Abhängigkeitscode dynamisch von externen Websites herunterzuladen
    • Normalerweise werden Abhängigkeiten über die vertrauenswürdige Infrastruktur von NPM bezogen, doch RDD erlaubt Downloads auch über unverschlüsselte Verbindungen wie HTTP
  • Die PhantomRaven-Angreifer konfigurierten dies so, dass Code von einer bösartigen URL heruntergeladen wurde, etwa http://packages.storeartifact.com/npm/unused-imports
    • Diese Abhängigkeiten sind für Entwickler und Security-Scanner unsichtbar und werden in den Paketinformationen als „0 Dependencies“ angezeigt
  • Durch die automatische Installationsfunktion von NPM werden solche „unsichtbaren“ Abhängigkeitscodes automatisch ausgeführt

Grenzen bei der Erkennung durch Security-Tools

  • Oren Yomtov von Koi sagte, PhantomRaven sei „ein Beispiel dafür, wie die blinden Flecken bestehender Sicherheitswerkzeuge raffiniert ausgenutzt werden“
    • RDD wird von statischen Analysewerkzeugen nicht erkannt
  • Dadurch konnten die Angreifer Sicherheitsprüfungen umgehen und bösartigen Code verbreiten

Zusätzliche Risikofaktoren

  • Koi erklärt, dass über RDD geladene Abhängigkeiten bei jeder Installation erneut vom Server der Angreifer heruntergeladen werden
    • Da es weder Caching noch Versionsverwaltung gibt, kann selbst bei demselben Paket je nach Installationszeitpunkt unterschiedlicher bösartiger Code eingeschleust werden
  • Diese Struktur dynamischer Downloads erschwert die Integritätsprüfung von Paketen

Struktur und Hintergrund von NPM

  • NPM ist ein Paketmanager für JavaScript, verwaltet von npm, Inc., einer GitHub-Tochter
    • Er ist der Standard-Paketmanager für Node.js und besteht aus einem Kommandozeilen-Client und der npm registry
    • In der Registry werden öffentliche sowie kostenpflichtige private Pakete gespeichert; sie können über die Website durchsucht werden
  • Der Vorfall gilt als Beispiel dafür, dass die automatische Abhängigkeitsverwaltung von NPM für Angriffe missbraucht werden kann

Sonstige Erwähnungen

  • Am Ende des Artikels wird die Ansicht erwähnt, dass unnötige Ausführung von JavaScript blockiert werden sollte
    • Zugleich wird darauf hingewiesen, dass dieser Angriff sogar essenziellen JavaScript-Code missbrauchte

2 Kommentare

 
developerjhp 2025-11-25

Ich habe ein Echtzeit-Scanner-Skript erstellt.

Im Pfad des verdächtigen Repositorys
npx sha1-hulud-scanner
eingeben.

Quellcode: https://github.com/developerjhp/sha1-hulud-scanner

 
GN⁺ 2025-10-31
Hacker-News-Kommentare
  • Ich habe mir inzwischen einen Alias eingerichtet, der den npm-Befehl innerhalb eines Docker-Containers ausführt
    So werden meine Umgebungsvariablen nicht offengelegt, es gibt keinen Zugriff auf Dateien außerhalb des aktuellen Verzeichnisses, und auch Konfigurationsdateien wie .bashrc sind nicht erreichbar
    Siehe auch: Run tools inside Docker

    • Das wirkt wie übertriebenes Sandboxing. npm lädt schließlich ohnehin beliebigen Code herunter, der direkt ausgeführt wird
      Ich würde stattdessen pnpm empfehlen. Dort werden Lifecycle-Skripte standardmäßig nicht ausgeführt, und man kann erlaubte Skripte per Whitelist festlegen
    • Post-Install-Skripte zu verteufeln vermittelt nur eine falsche Illusion von Sicherheit
      Wer echten Schutz will, muss nicht nur die Installation, sondern die gesamte Ausführung in einer Sandbox laufen lassen
      Nur post-install zu blockieren ist, wie es heute oft gemacht wird, bloß eine halbe Maßnahme. Supply-Chain-Angriffe werden immer gefährlicher
    • Es gibt viel zu viele Angriffsvektoren. Mit böswilliger Absicht könnte man per Typosquatting auf den Namen eines populären Plugins oder LSP setzen und so dafür sorgen, dass beim Start des Editors automatisch Code ausgeführt wird
      Wenn neovim oder vscode kompromittiert sind, kann man mit Benutzerrechten bereits genug Schaden anrichten
    • Ich nutze sandbox-run
      Ein einfacher Alias funktioniert bei node/npm, ist aber auf andere Programme schwerer anzuwenden, weil man die nötigen Ressourcen in den Container mounten muss
    • Am Ende kannst du dir aber trotzdem ein bösartiges Paket herunterladen, oder nicht? Auch eine Abhängigkeit selbst könnte bereits kompromittiert sein
  • Ich habe mich das schon lange gefragt. Warum führen Leute völlig selbstverständlich npm direkt auf ihrem System aus?
    Aus Sicht von jemandem, der an reproduzierbare Builds mit make gewöhnt ist, war es schockierend, dass npm jedes Mal etwas anderes herunterlädt und andere Ergebnisse liefert
    Sogar die CSS-Erzeugung an npm-Abhängigkeiten zu hängen, fand ich seltsam. Deshalb habe ich versucht, die gesamte npm-Umgebung in Docker einzufrieren, aber es fühlt sich letztlich wie ein aussichtsloser Kampf an

    • Inzwischen verhalten sich praktisch alle Paketmanager so. maven, nuget, pip, npm — alle gleich
      Würde man wie früher nur auf Paketmanager der Distribution setzen, wäre das heutige schnelle Ökosystem kaum möglich gewesen
      Allerdings entstehen inzwischen neue Paketmanager mit stärkerem Sicherheitsfokus. Nur das Mittel zu kritisieren, ohne den Grund zu verstehen, ist nicht richtig
    • Frontend-Entwicklung wirkt wie ein Wildwest nach dem Motto „Trust me, bro“. Durch die Entwicklung der Browser ist das Ganze zwangsläufig eher zusammengeflickt wie mit Klebeband
    • Wenn du npm per Docker eingefroren hast, würde ich fragen, ob du diese Umgebung nach jedem Dependency-Update auch validiert hast
      Tatsächlich pinnen npm und pnpm Abhängigkeiten schon standardmäßig über Lockfiles
    • Das Problem ist, dass „npm install thing“ zu einfach und zu billig geworden ist
      Viel Open Source wird mit Code für den Lebenslauf statt für Qualität gefüllt und landet am Ende dabei, Werbetracker großer Konzerne oder Wallet-Apps zu bauen
  • npm install lädt nicht einfach nur Pakete herunter, sondern führt Code aus
    Die Hooks preinstall, install und postinstall in package.json werden tatsächlich ausgeführt
    Aus welchem legitimen Grund müsste der Installationsprozess überhaupt beliebige Befehle ausführen?
    Relevanter Bericht: PhantomRaven npm malware
    Ein weiterer Fall: Socket.dev blog

    • So eine Struktur gab es tatsächlich auch schon bei älteren Paketmanagern wie DEB und RPM
      Zum Beispiel führen Linux-Kernel-Pakete nach der Installation Post-Install-Skripte aus, um initramfs neu zu erzeugen und GRUB zu aktualisieren
      Die meisten DEB-/RPM-Pakete enthalten solche Skripte. Das Problem liegt also im Design selbst
    • Das eigentliche Problem ist, dass bei npm jeder Pakete hochladen kann
      Linux-Distributionen haben ein vertrauenswürdiges Maintainer-System und bauen teils selbst eine Root of Trust auf Basis von PGP auf
      Dagegen sind npm, pip, rubygems, cargo und ähnliche im Grunde nur eine elegantere Version von „curl | bash
    • Das Projekt Mediasoup etwa ist eine in C++ geschriebene Streaming-Bibliothek und kompiliert bei der Installation den Quellcode direkt selbst
      Solche Post-Install-Builds waren nötig, um den Wartungsaufwand zu reduzieren
    • Auch der Swift Package Manager führt die Datei Package.swift tatsächlich aus
      Soweit ich gehört habe, ist das aber stark sandboxed, sodass Missbrauch schwierig ist
      Siehe: SwiftPM docs, PackageDescription
    • Übrigens deaktiviert pnpm v10 standardmäßig alle Lifecycle-Skripte, und der Nutzer muss sie explizit erlauben
      Zugehörige Diskussion
  • Wenn man sich die jüngsten npm-Angriffe ansieht, fragt man sich langsam, ob Entwicklung mit npm überhaupt noch sicher ist
    Jedes Mal, wenn ich ein React-Projekt starte, werden Hunderte Pakete installiert, und ich habe keine Ahnung, was die eigentlich tun
    Im Backend installiert man explizit nur das, was man braucht, aber das Frontend wirkt wie eine Büchse der Pandora voller Schwachstellen

    • Eigentlich ist das in allen Sprachökosystemen ähnlich. npm ist nur das größte und daher am häufigsten in den Nachrichten
    • Als ich Rusts jj installiert habe, wurden 470 Pakete installiert, bei Pythons wan2gp waren es 211. Am Ende ist das überall ähnlich
    • Das JavaScript-Ökosystem ist strukturell anfällig für Angriffe
      Wie beim xz-Vorfall hängen die einzelnen Abhängigkeiten oft an irgendwelchen zufälligen Privatpersonen, und man muss darauf vertrauen, dass sie nicht Opfer von Social Engineering werden
    • Je weniger Abhängigkeiten, desto besser. Null ist perfekt. Das ist der wahre Sieg
    • Zur Erinnerung: Auch PyPI ist nicht sicher. Es gab Fälle, in denen durch kompromittierte GitHub Actions bösartiger Code in legitime Pakete eingeschleust wurde
  • Jedes Mal, wenn ich mit Frameworks wie Angular oder Vue entwickle, macht mich das nervös
    Wenn ich die Tausenden Abhängigkeiten in node_modules sehe, fühlt es sich wie ein Vorbote einer Katastrophe an
    Wenn nur ein einziger Open-Source-Entwickler auf Phishing hereinfällt, kann sofort alles kompromittiert sein
    Das JavaScript-Ökosystem ist grundlegend kaputt. Ein einziger Tippfehler kann einen Supply-Chain-Angriff auslösen
    Bei NuGet oder Maven geht das zwar auch, aber dort ist die Standardbibliothek größer, es gibt weniger Abhängigkeiten und man hat mehr Kontrolle

    • Go verwendet statt Paketnamen Repo-URLs, was Typosquatting reduziert
      Perfekt ist das nicht, aber es ist immerhin ein Schritt besser
    • Deno löst diese Probleme. Das ist ein strukturelles Problem von Node.js / npm
  • Von den 86.000 Downloads dürften die meisten eher automatisierte Scanner oder Bots gewesen sein als echte Nutzer
    Wenn man eine neue Version hochlädt, wird sie oft schon nach ein oder zwei Tagen Hunderte Male heruntergeladen, ohne dass das echte Menschen sein müssen
    Das heißt: Möglicherweise gab es kaum tatsächlich infizierte Nutzer

    • Als ich selbst eine Bibliothek veröffentlicht habe, lag sie anfangs bei etwa 300 Downloads pro Woche und später bei rund 100
      Es gibt auch viele Angriffe, die auf Paketnamen zielen, die von AI-Chatbots halluziniert wurden. Es geht also um mehr als bloße Statistik
    • Oder es ist einfach die Zombie-CI von irgendwem, die das Paket ständig herunterlädt
    • Wenn der Angriff allerdings auf von LLMs erfundene Paketnamen abzielte, könnten tatsächlich viele Entwickler kompromittiert worden sein
  • Eine ausführlichere Beschreibung des Angriffs gibt es in diesem BleepingComputer-Artikel

  • Ich frage mich, ob es eine Möglichkeit gibt, bei npm install Pakete zu erkennen oder zu filtern, die HTTP-URLs als Abhängigkeiten verwenden
    Da je nach Anfragendem unterschiedliche Payloads ausgeliefert werden können, ist das mit gewöhnlichen Scannern schwer zu erkennen

  • Als Hobbyentwickler überlege ich, wie man sich gegen solche Supply-Chain-Angriffe wappnen sollte
    Wenn man bekannten Tutorials folgt und dabei Abhängigkeiten installiert, wird man irgendwann wie von selbst nachlässig bei der Sicherheit
    Ich betreibe auch mehrere Dienste in meinem Homelab und mache mir Sorgen, dass dort irgendwann Bots eindringen könnten. Wo fängt man da am besten an?

    • Wenn man Dienste in Containern oder VMs getrennt betreibt, kann man den Schaden isolieren
      Das ist keine perfekte Garantie, aber deutlich besser, als wenn gleich der ganze Server kompromittiert wird
    • Man sollte alle Abhängigkeiten als potenzielles Sicherheitsrisiko betrachten und nur einsetzen, wenn sie wirklich nötig sind
      Nur den benötigten Code direkt zu kopieren und zu verwenden, ist ebenfalls eine gute Lernmöglichkeit und oft sicherer
    • Populäre Releases, die seit mehr als einem Jahr existieren, sind sicherer. Wenn es Probleme gab, sind sie wahrscheinlich schon entdeckt worden
    • Es gibt auch Betriebssysteme wie FreeBSD, die System-Paketmanager verwenden
      In so einer Struktur kann Vertrauenswürdigkeit auf Distributionsebene hergestellt werden, statt dass Millionen Nutzer alles selbst prüfen müssen
    • Ich bevorzuge Pakete mit mehr als 1 Million Downloads pro Woche und ohne Abhängigkeiten
      Beispiele: Hono, Zod
      Ich bin kürzlich auf Bun umgestiegen, weil dort Dinge wie Datenbanktreiber oder S3-Clients bereits eingebaut sind und weniger zusätzliche Downloads nötig werden
  • Eine Struktur, bei der Abhängigkeiten über Lifecycle-Hooks hereingeholt werden, kann jederzeit zum Angriffsknotenpunkt werden
    Selbst wenn heute noch alles sauber ist, kann es später bösartig werden, wenn der Eigentümer gehackt wird oder seine Meinung ändert
    Solche Installations-Hooks in dieser Form sind letztlich ein nicht tragfähiges Design