Axios npm Supply-Chain-Angriff: Bösartige Versionen tropften Remote-Access-Trojaner ab

Axios npm Supply-Chain-Angriff: Bösartige Versionen tropften Remote-Access-Trojaner ab

lschvn

Zwei bösartige Versionen von axios, einer Bibliothek, die über 300 Millionen Mal pro Woche heruntergeladen wird, tief eingebettet im Node.js-Ökosystem, wurden am 31. März 2026 auf npm veröffentlicht und innerhalb von Stunden erkannt. axios@1.14.1 und axios@0.30.4 wurden mit einer versteckten Abhängigkeit ausgeliefert, die nichts anderes tat, als einen Postinstall-Dropper auszuführen. Der Dropper lud OS-spezifische Second-Stage-Payloads von einem Live-Command-and-Control-Server herunter, löschte sich dann selbst und ersetzte sein eigenes Manifest, um die Beweise zu verbergen.

Wenn Sie eine dieser Versionen installiert haben, gehen Sie davon aus, dass Ihr System kompromittiert ist.

Der Angriff in Zahlen

  • 2 bösartige Versionen veröffentlicht (1.14.1 und 0.30.4)
  • ~3 Stunden diese Versionen auf npm live, bevor Entfernung
  • ~300M wöchentliche Downloads von axios (enormer Blast-Radius)
  • 3 OS-Ziele (macOS, Windows, Linux), alle vorab erstellten Payloads
  • 18 Stunden der Angreifer infrastrukture aufgebaut, bevor er zuschlug

Wie der Angriff funktionierte

Schritt 1: Kompromittierung des Maintainer-Kontos

Der Angreifer kompromittierte das npm-Konto von jasonsaayman, dem Lead-Maintainer von axios. Sie änderten die registrierte E-Mail zu einer Angreifer-kontrollierten ProtonMail-Adresse und veröffentlichten dann bösartige Builds manuell über npm CLI, und umgingen dabei die normale GitHub Actions CI/CD-Pipeline des Projekts. Diese Art von Konto-Kompromittierung ist eine Erinnerung daran, warum die Verschiebung des JavaScript-Ökosystems zu OIDC Trusted Publishers wichtig ist: Kryptografische Veröffentlichungsherkunft erschwert es einem Angreifer, ein bösartiges Paket als legitimes auszugeben.

Ein kritisches forensisches Signal: Jedes legitime axios 1.x-Release wird über npm's OIDC Trusted Publisher-Mechanismus veröffentlicht, kryptografisch an einen verifizierten GitHub-Actions-Workflow gebunden. Das bösartige 1.14.1 bricht dieses Muster vollständig, kein trustedPublisher, kein gitHead, kein entsprechender Git-Commit oder -Tag.

// axios@1.14.0, LEGITIM
"_npmUser": {
  "name": "GitHub Actions",
  "email": "npm-oidc-no-reply@github.com",
  "trustedPublisher": { "id": "github", ... }
}

// axios@1.14.1, BÖSARTIG
"_npmUser": {
  "name": "jasonsaayman",
  "email": "ifstap@proton.me"
  // kein trustedPublisher, kein gitHead
}

Es gibt keinen Commit oder Tag im axios-GitHub-Repository, der 1.14.1 entspricht. Das Release existiert nur auf npm.

Schritt 2: Inszenierung einer Phantom-Abhängigkeit

Bevor die backdooreten axios-Versionen veröffentlicht wurden, seeded der Angreifer ein bösartiges Paket auf npm: plain-crypto-js@4.2.1, veröffentlicht von einem separaten Wegwerfkonto. Dieses Paket gab sich als legitime crypto-js-Bibliothek aus, gleiche Beschreibung, gleiche Autorzuordnung, gleiche Repository-URL, enthielt aber einen Postinstall-Hook, dessen einzige Aufgabe darin bestand, einen Dropper auszuführen.

Ein Grep über alle 86 Dateien in axios@1.14.1 bestätigt: plain-crypto-js wird nie irgendwo im axios-Quellcode importiert oder require()'d. Es erscheint in package.json nur, um den Postinstall-Hook auszulösen. Null Zeilen bösartigen Codes existieren innerhalb von axios selbst.

Schritt 3: Plattformübergreifender RAT-Dropper

Das Postinstall-Script ist eine stark obfuscierte JavaScript-Datei. Alle sensiblen Strings, C2-URL, Shell-Befehle, Dateipfade, sind XOR-kodiert in einem Array und werden zur Laufzeit mit einem aus dem String "OrDeR_7077" abgeleiteten Schlüssel dekodiert. Der Dropper verzweigt in drei OS-spezifische Angriffspfade:

  • macOS: Lädt eine RAT-Binary nach /Library/Caches/com.apple.act.mond herunter (dazu gedacht, einen Apple-System-Cache nachzuahmen), macht sie ausführbar und startet sie still über osascript
  • Windows: Kopiert PowerShell nach %PROGRAMDATA%\wt.exe (als Windows Terminal getarnt), droppt ein VBScript zum Abrufen und Ausführen einer Second-Stage-RAT
  • Linux: Zielt auf CI/CD-Umgebungen ab, lädt eine Python-basierte RAT herunter

Schritt 4: Selbstzerstörung

Nach dem Deployen der Second-Stage-Payload löscht sich der Dropper und tauscht ein sauberes Paketmanifest ein:

// Des Angreifers eigener Bereinigungscode im Dropper eingebettet
// Ersetzt bösartige package.json durch ein sauberes Lockmittel
rename("package.md", "package.json")  // sauberer Stub überschreibt Beweise
unlink("setup.js")                    // Dropper löscht sich selbst

Ein Entwickler, der seine node_modules anschließend inspiziert, sieht keine Anzeichen dafür, dass etwas schiefgelaufen ist.

Kompromittierungsindikatoren (IOCs)

Bösartige Pakete:

  • plain-crypto-js@4.2.1, bösartige Abhängigkeit, Postinstall-RAT-Dropper
  • axios@1.14.1, backdooretes 1.x-Release
  • axios@0.30.4, backdooretes 0.x-Legacy-Release

C2-Infrastruktur:

  • sfrclak.com:8000, Command-and-Control-Server (Stage-2-Lieferung)
  • Pfadsegmente: /6202033, packages.npm.org/product0, packages.npm.org/product1, packages.npm.org/product2

macOS-Persistenz:

  • /Library/Caches/com.apple.act.mond, RAT-Binary auf macOS gedroppt

Windows-Persistenz:

  • %PROGRAMDATA%\wt.exe, RAT als Windows Terminal getarnt

Was Sie jetzt tun müssen

  1. Überprüfen Sie Ihre node_modules auf axios-Versionen 1.14.1 und 0.30.4. Wenn vorhanden, gehen Sie von Kompromittierung aus.
  2. Downgraden Sie sofort auf axios@1.14.0 oder axios@0.30.3, die letzten bekannten sauberen Versionen.
  3. Auditen Sie Ihre Systeme auf IOCs: prüfen Sie auf unerwartete ausgehende Verbindungen zu sfrclak.com:8000, ungewöhnliche Cron/geplante Aufgaben oder unbekannte Binaries in /Library/Caches (macOS) oder %PROGRAMDATA% (Windows).
  4. Rotieren Sie alle Secrets und Anmeldedaten, auf die von Entwicklermaschinen zugegriffen wurde, die npm install während des Zeitfensters ausführten, in dem die bösartigen Versionen live waren (~31. März, 00:21–03:15 UTC).
  5. Überprüfen Sie Ihren npm-Veröffentlichungs-Workflow: stellen Sie sicher, dass Ihr Projekt OIDC Trusted Publishers verwendet, sodass manuelle tokenbasierte Veröffentlichungen die Signaturkette unterbrechen.

Warum dieser Angriff nicht opportunistisch war

Die operationelle Raffinesse hier ist bemerkenswert:

  • Der Angreifer seeded ein sauberes Lockmittel-Paket (plain-crypto-js@4.2.0) 18 Stunden vor der bösartigen Veröffentlichung, um npm-Veröffentlichungshistorie zu etablieren und "Zero-History-Paket"-Warnungen zu vermeiden
  • Beide 1.x- und 0.x-Release-Zweige wurden 39 Minuten auseinander getroffen, um die Abdeckung zu maximieren
  • Separate Payloads wurden für drei Betriebssysteme vorab erstellt
  • Die C2-URL verwendet Pfadsegmente, die an die npm-Registry-Pfadstruktur gebunden sind, packages.npm.org/product0/1/2, wodurch die Exfiltration wie gewöhnlicher npm-Traffic aussieht
  • Der Dropper verwendet Apples legitimes osascript-Binary auf macOS, keine bösartige Binary wird vor der Validierung auf die Disk geschrieben, was EDR-Erkennung erschwert

Dies ist Supply-Chain-Angriffs-Know-how auf einem Niveau, das zuvor für staatlich gesponserte Operationen reserviert war, jetzt deployed gegen ein Top-10-npm-Paket.


Quellen: StepSecurity, npm-Registry-Metadaten, axios-GitHub-Repository. Der axios-Sicherheitshinweis ist in der npm-Sicherheitshinweisdatenbank verfügbar.

Häufig gestellte Fragen

Verwandte Artikel

Weitere Berichterstattung zu ähnlichen Themen und Tags.

Fastify v5.9.0 ergänzt `request.mediaType` und `onMaxParamLength`, härtet das Vertrauen in `forwarded`-Header, chunkiert große HTTP/2-Antworten und migriert die Typ-Tests zu TSTyche
security

Fastify v5.9.0 ergänzt `request.mediaType` und `onMaxParamLength`, härtet das Vertrauen in `forwarded`-Header, chunkiert große HTTP/2-Antworten und migriert die Typ-Tests zu TSTyche

Fastify v5.9.0, veröffentlicht am 2026-06-28 (github.com/fastify/fastify), ist die erste Minor-Version der v5-Linie im Jahr 2026 und ein substanzieller 65-PR-Zyklus. Die Hauptfunktionen sind `request.mediaType` (ein typisierter Accessor für den ausgehandelten Medientyp, [#6653](https://github.com/fastify/fastify/pull/6653) von climba03003), die Routen-Option `onMaxParamLength` ([#6716](https://github.com/fastify/fastify/pull/6716) von climba03003) und ein Sicherheitsfix, das `X-Forwarded-Host` und `X-Forwarded-Proto` nicht mehr vertraut, wenn der eingehende Socket fehlt ([#6684](https://github.com/fastify/fastify/pull/6684) von mcollina). Der Zyklus liefert einen HTTP/2-Buffer-Chunking-Fix für große Antworten ([#6746](https://github.com/fastify/fastify/pull/6746) von mcollina), drei schema-bezogene Performance-Gewinne (verzögertes `getSchemaSerializer`-Content-Type-Parsing #6692, gecachte `ContentType`-Objekte im `ContentTypeParser` #6694, `typeof`-Wache vor `toString.call` in `send` / `onSendEnd` #6693 von aquie00t), Node.js 26 zur Test-Matrix hinzugefügt ([#6728](https://github.com/fastify/fastify/pull/6728) von Fdawgs) und Node.js 20 aus der yarn-CI-Matrix entfernt ([#6662](https://github.com/fastify/fastify/pull/6662) von Tony133), die Migration der Typ-Test-Suite von handgeschriebenen `expect-type`-Assertions zu [TSTyche](https://github.com/mrazauskas/tstyche) ([#6532](https://github.com/fastify/fastify/pull/6532) von mrazauskas, mit Folge-PRs #6726 und #6727), und ein TypeScript-only fastify-plugin v6.0.0-Bump. Weitere bemerkenswerte Fixes: Trailer-`res.end`-Deduplizierung (#6676), Trailer-Duplikat-Completion-Wache (#6714), `error.code` auf Routing-Fehlern (#6678), `hasRequestDecorator` / `hasReplyDecorator` erkennen konstruktor-zugewiesene Built-in-Eigenschaften (#6753), `getValidationFunction()` darf `undefined` zurückgeben (#6665), und ein Socket-`_meta`-Clear, der ein Keep-Alive-Leck schließt (#6799).
Deno 2.9 bringt 1,98x schnelleren Cold Start, 2,2–3,1x weniger RSS unter Last, npm Minimum Release Age als Default, No-Downgrade Trust Policy und eingebaute Snapshot-Tests
runtimes

Deno 2.9 bringt 1,98x schnelleren Cold Start, 2,2–3,1x weniger RSS unter Last, npm Minimum Release Age als Default, No-Downgrade Trust Policy und eingebaute Snapshot-Tests

Deno 2.9 (Bartek Iwańczuk, veröffentlicht am 2026-06-25 auf deno.com/blog/v2.9) ist das größte Deno-Release des Zyklus. Der Cold Start sinkt von 34,2 ms auf 17,3 ms (1,98x), der Spitzen-RSS auf der Deno.serve-Realworld-Last fällt um den Faktor 2,2 (142 MB → 64 MB) und um 3,1x bei 1-MiB-Bodies (197 MB → 63 MB), und der Deno.serve-Durchsatz steigt um 1,27x in Realworld (56,8k → 72,4k req/s), 1,11x in Plaintext und 1,18x bei 1-MiB-Bodies. Supply-Chain-Härtung: Das npm Minimum Release Age wird standardmäßig mit einem 24-Stunden-Fenster aktiviert (PR #35458), und eine neue opt-in No-Downgrade Trust Policy (PR #34927) weigert sich, jede Version aufzulösen, deren Vertrauensbeweis (Staged Publishing, Trusted Publishing, Provenance-Attestation) schwächer ist als der stärkste Beweis einer zuvor veröffentlichten Version desselben Pakets. Test-Runner-Parität: eingebautes t.assertSnapshot() (#35139), Deno.test.each (#34938), --shard für CI-Fan-out (#35057), Retry und Repeats (#35053), Change-Aware --changed und --related (#35199) und Coverage-Thresholds (#35056). Lockfile-Interop: deno install seedet deno.lock aus package-lock.json, pnpm-lock.yaml, yarn.lock oder bun.lock (#34296, #35330, #35346, #35350, #35394), pnpm-workspace.yaml migriert automatisch in deno.json / package.json (#34993), und Git-Merge-Konflikt-Marker in deno.lock lösen sich automatisch auf (#34726). Dazu: deno desktop verlässt den experimentellen Status (PR #33441 vom 16. Juni), Subcommands deno link / deno unlink / deno list / deno watch, stabiles --unsafe-proto (#34738), Web Locks API (#31166), Happy Eyeballs v2 (RFC 8305) (#31726), navigator.userAgentData (#34743), der WebCrypto Modern Algorithms-Vorschlag (ML-KEM, ML-DSA, SLH-DSA, ChaCha20-Poly1305, SHA-3-Familie, KMAC, Argon2) (#34447, #34448, #34914, #35223), Node-26.3.0-Kompatibilität (#34746, #34747), Node-API v10 (#35270) und CSS-Modul-Importe unter --unstable-raw-imports (#35093). Über 165 PRs landen in diesem Zyklus.
Node.js 26.4.0 'Current' bringt das node:vfs-Subsystem (Matteo Collina), ESM-Loader-Package-Maps (Maël Nison), TLS-Zertifikatkompression, TCP_KEEPINTVL/TCP_KEEPCNT und argon2 als stabil
security

Node.js 26.4.0 'Current' bringt das node:vfs-Subsystem (Matteo Collina), ESM-Loader-Package-Maps (Maël Nison), TLS-Zertifikatkompression, TCP_KEEPINTVL/TCP_KEEPCNT und argon2 als stabil

Node.js 26.4.0 (Current), veröffentlicht am 2026-06-24 von @aduh95, liefert acht SEMVER-MINOR-Änderungen: ein minimales node:vfs-Subsystem, das vom Anwendungscode bereitgestellte virtuelle Dateisysteme einhängt (PR #63115, Matteo Collina) sowie ein Folgepatch, das node:fs/promises an eingehängte VFS-Instanzen weiterleitet (PR #63537), Package-Maps für ESM-Loader-Hooks, die Bare-Spezifier durch die Loader-Hooks routen (PR #62239, Maël Nison), TLS certificateCompression, das die zlib- und zstd-Kompression aus RFC 8879 durch die OpenSSL-Build-Konfiguration verkabelt (PR #62217, Tim Perry), TCP_KEEPINTVL- und TCP_KEEPCNT-Unterstützung in net.Socket.setKeepAlive (PR #63825, Guy Bedford), vom Aufrufer bereitgestellte Buffer in fs.readFile / fs.readFileSync (PR #63634, Matteo Collina), closeIdleConnections, das nun auch Pre-Request-Sockets schließt (PR #63470, semimikoh), net.BlockList auf Release-Candidate-Stabilität vorgerückt (PR #63050), und crypto.argon2 + KEM encap/decap als stabil markiert (PR #63924, Filip Skokan). Die Release ergänzt außerdem WebCrypto-cSHAKE (PR #63988), QUIC listEndpoints (PR #63536) und X509Certificate-Handles (PR #63191), dgram connectSync / bindSync (PRs #63838 + #63932, Guy Bedford), net.BoundSocket für frühes TCP-Binding (PR #63951), einen experimentellen schnellen FFI-Aufrufpfad für AArch64 und x86_64 (PRs #63068 + #63941, Paolo Insogna), npm 11.17.0 (PR #63857), sqlite 3.53.2 und libffi 3.6.0.

Kommentare

Anmelden Melden Sie sich an, um an der Diskussion teilzunehmen.

Noch keine Kommentare. Seien Sie der Erste, der seine Gedanken teilt.