Zurück zu allen Beiträgen
Veröffentlicht am · von Renaud Deraison

Einer alle drei Tage

StepSecurity hat am Samstag ein Jahr Angriffe mit bösartigen Paketen ausgezählt: 56 davon, 6 in den ersten sechs Monaten und 50 in den sechseinhalb Monaten seit Februar, also seit März etwa einer alle drei Tage. Dann benennt der Bericht, warum sie weiterhin funktionieren: Geheimnisse auf Entwicklermaschinen und CI-Runnern, ungepinnte latest-Versionen, offener ausgehender Netzwerkzugang. Keine dieser drei Sachen ist eine Eigenschaft eines Pakets. Alle drei beschreiben die Maschine, auf der die Installation läuft, und auf der Maschine, die heute die meisten Pakete installiert, sitzt ein Coding-Agent.

Ein bösartiges Paket zündet bei der Installation. Es gibt keinen verwundbaren Codepfad zu erreichen, keinen Exploit zu schreiben, kein Fenster zum Patchen. Bei einem alle drei Tage hat das Paket, in dem es ankommt, aufgehört, die nützliche Frage zu sein.

Am Samstag veröffentlichte StepSecurity eine Zwölfmonatszählung der Angriffe auf die Open-Source-Lieferkette. Sechsundfünfzig davon. „In den sechs Monaten von August 2025 bis Januar 2026 haben wir 6 Vorfälle erfasst. In den sechseinhalb Monaten seit Februar 2026 waren es 50.“ Seit März hält sich die Rate bei rund neun im Monat, oder „etwa einem alle drei Tage“.

StepSecurity verkauft eine filternde Registry, also lesen Sie den Bericht im Wissen darum, was er verkauft. Die Zählung hält trotzdem stand. Sie ist die sorgfältigste öffentliche Aufstellung bösartiger Pakete, die irgendwer veröffentlicht hat, und die Definition dahinter ist absichtlich eng.

Was die Zahl zählt

Der Bericht wirft Schwachstellen hinaus. Keine CVEs, kein unsafe-Block, der sich als solcher entpuppt hat. Er zählt Pakete, die jemand vorsätzlich vergiftet hat.

Deshalb ist die Zahl brauchbar. Eine Schwachstelle braucht ein zweites Ereignis: Jemand muss Ihre Instanz finden, den betroffenen Codepfad erreichen und etwas daraus ziehen. Sie können eine verwundbare Version ein Jahr lang betreiben, und nichts passiert. Ein bösartiges Paket überspringt all das. Wie es der Bericht formuliert, „läuft es in dem Moment, in dem eine Entwicklermaschine oder ein CI-Runner es installiert“. Die Installation ist die Ausnutzung. Sie bekommen nie ein Fenster zwischen Offenlegung und Patch, weil niemand etwas offengelegt und niemand einen Patch ausgeliefert hat. Sie bekommen eine Versionsnummer und dann eine Hetzjagd danach, wer sie geholt hat.

Der März 2026 sah 13. April 9, Mai 9, Juni 10, Juli 6. In fünf Tagen im März hat eine als Team PCP verfolgte Operation 78.330 Geheimnisse aus 2.186 Organisationen entwendet, 92 davon börsennotierte Unternehmen, indem sie 76 der 77 Tags der Trivy-GitHub-Action und eine Handvoll weiterer Build-Komponenten vergiftete. axios, bei über 100 Millionen wöchentlichen Downloads, lieferte zwei bösartige Versionen mit einem plattformübergreifenden Fernzugriffstrojaner aus. Sechs Würmer tauchen in dem Jahr auf: Shai-Hulud zweimal, CanisterWorm, Mini Shai-Hulud, Miasma und diesen Monat ChainDrop. npm, PyPI, RubyGems, Composer, crates.io, GitHub Actions. „Jedes größere Paket-Ökosystem und jede CI/CD-Plattform wurde getroffen.“

Zwei Einträge dieser Liste zählen hier. Der Bericht hält fest, dass hackerbot-claw, „ein KI-gestützter Bot“, es auf die GitHub Actions von Microsoft, Datadog und der CNCF abgesehen hatte, und dass „der Miasma-Wurm gezielt KI-Coding-Agenten ins Visier nahm“.

Die drei Bedingungen, von denen keine ein Paket ist

Dann tut der Bericht das Nützliche. Unter einer Überschrift, die fragt, warum die Angriffe weiter funktionieren, gibt er drei Antworten: „Geheimnisse in CI/CD-Pipelines und auf Entwicklermaschinen, ungepinnte latest-Versionen, offener ausgehender Netzwerkzugang.“

Nichts auf dieser Liste beschreibt ein Paket. Keine Verschleierung, kein Typosquatting- Abstand, keine Raffinesse im Install-Hook. Alle drei beschreiben die Maschine, die die Installation ausführt: was sie hält, wie sie eine Version wählt und wohin sie sich verbinden darf. Ändern Sie eine davon, und die meisten der sechsundfünfzig rentieren sich nicht mehr.

Ungepinntes latest

Irgendetwas in der Auflösungskette sagt „die neueste“. Ein gleitender Bereich, eine transitive Abhängigkeit, ein neu gebautes Lockfile, ein Agent, der in Ihrem Namen eine Bibliothek hinzufügt. Der Angreifer braucht nur, dass der Resolver eine vor Minuten veröffentlichte Version bevorzugt.

Geheimnisse auf der Maschine

~/.ssh, ~/.aws, ~/.kube, ~/.npmrc, ein GH_TOKEN in der Umgebung, ein Registry-Login in ~/.docker/config.json. Nichts davon gehört zum Build, und was der Build gerade gestartet hat, kann alles davon lesen.

Offen nach draußen

Die Beute muss hinaus, und die Binärdatei der zweiten Stufe muss herein. Beides sind gewöhnliche ausgehende Verbindungen von einer Maschine, die ausgehende Verbindungen überallhin erlaubt.

Was zusammenkommen muss1 · das Paketeine vergiftete Versionerscheint und lebt einbis zwei Stunden2 · der Resolveretwas in der Kette will dieneueste, und die neuesteist die vergiftete3 · die PlatteInstall-Code liest~/.ssh ~/.aws ~/.npmrcund die Umgebung4 · die Leitungeine ausgehende Verbindungträgt es fort und holt diezweite Stufe hereinSchritt 2, 3 und 4 entscheidet Ihre Maschine, nicht das Paket„Geheimnisse in CI/CD-Pipelines und auf Entwicklermaschinen, ungepinntelatest-Versionen, offener ausgehender Zugang“ — StepSecuritydas ist der einzigeTeil, den Sie nichtsteuern können
Ein Angriff mit bösartigem Paket braucht vier Dinge in Reihe, und nur das erste betrifft das Paket. Die anderen drei sind Eigenschaften der Maschine: wie sie eine Version wählt, was sie hält und wohin sie sich verbinden darf.

Wessen Maschine installiert heute die meisten Pakete

Die Verteidigung, auf die sich alle verließen, war Aufmerksamkeit. Sie lesen den Diff. Ihnen fällt auf, dass eine Caching-Bibliothek eine Abhängigkeit aufgelesen hat, benannt nach einem Datumsformatierer mit einem geänderten Buchstaben.

Zwei Dinge haben das überholt. Zuerst die Rate: Niemand prüft alle drei Tage transitive Abhängigkeiten. Dann, wer installiert. Ein Coding-Agent fügt eine Bibliothek hinzu, weil Sie ihn gebeten haben, etwas zu bauen, löst den Baum auf, führt die Installation aus und meldet, dass die Tests durchlaufen. Sie lesen den Diff, den er erzeugt hat, und das ist der Teil, der Ihre Zeit wert ist. Ein Tarball taucht in keinem Diff auf. StepSecurity's Liste enthält bereits einen Wurm, der genau nach dieser Arbeitsweise gesucht hat.

Behalten Sie den Agenten. Verlegen Sie die Kontrolle dorthin, wo seine Geschwindigkeit aufhört, eine Rolle zu spielen.

Drei Bedingungen, drei Kontrollen, alle auf der Mac-Seite

Bromure Agentic Coding führt den Agenten in einer Wegwerf-Ubuntu-VM auf Apples Virtualization-Framework aus, mit nur den von Ihnen gewählten Ordnern eingehängt und einem Proxy auf der Host-Seite als einzigem Weg nach draußen. Diese Platzierung stellt jede der drei Bedingungen von StepSecurity vor eine Kontrolle, die der Build nicht erreichen kann.

Ungepinntes latest wird zu einer Uhr. Jeder Paketabruf durchquert zuerst den Host-Proxy: npm, PyPI, Cargo, RubyGems, Maven, NuGet, Go-Module, Packagist. Die Altersschranke ist standardmäßig bei zwei Tagen aktiv. Gleitende Referenzen lösen sich auf die neueste Version vor dem Stichzeitpunkt auf, sodass latest weiter funktioniert und aufhört, „veröffentlicht, während Sie das hier lasen“ zu bedeuten. Eine gepinnte Referenz auf etwas zu Frisches kommt als 451 mit einem Bromure-Fehler zurück. Darüber hinaus können Sie OSV-Abfragen ab einer von Ihnen gewählten Schweregradschwelle einschalten, Pakete über die Reputationsdatenbank von socket.dev oder die filternde Registry von Delpi leiten und preinstall, install, postinstall und prepare im Flug aus npm-Tarballs entfernen. Bromure schreibt den Tarball um und aktualisiert den Metadaten-Hash der Registry, damit npms eigene Prüfung weiterhin besteht. Die .npmrc und pip.conf innerhalb der VM können jede dieser Einstellungen verschärfen und keine davon lockern.

Geheimnisse auf der Maschine sind Attrappen. Echte Zugangsdaten betreten die VM nie. Der Proxy tauscht auf der Leitung einen Platzhalter gegen das echte Token; die kubeconfig im Gast ist synthetisch, mit Wegwerf-Client-Zertifikaten; AWS bekommt einen credential_process-Helfer, der dem SDK eine vierzig Zeichen lange Fälschung reicht, während der Host SigV4 mit dem echten Material neu signiert, sodass alles, was am Proxy vorbeiroutet, eine InvalidSignatureException von Amazon einsammelt. Install-Code, der ~/.aws/credentials liest, findet eine Datei, liest sie und exfiltriert eine Attrappe. Jede Zugangsdatei trägt zudem eine Schreibrichtlinie (Aus, Destruktives blockieren oder Nur lesen), durchgesetzt im Host-Proxy, plus Zustimmung zur Nutzung verlangen, was jede einzelne Verwendung in einen Zustimmungsdialog verwandelt, mit einer Freigabe für fünf Minuten, eine Stunde oder den Rest der Sitzung.

Offen nach draußen antwortet auf eine Regel, die Sie geschrieben haben. Unter Schutzvorrichtungen ist die Tabelle Ausgehende Verbindungen eine Firewall pro Profil: eine Zeile je Regel, jede mit einer Aktion, einem Protokoll (tcp, udp, web oder any), einem Host oder CIDR, Ports und für web einer Liste von HTTP-Methoden. Regeln greifen von oben nach unten, der erste Treffer gewinnt, und Nicht zugeordneter Verkehr ist ein Schalter, den Sie auf Erlauben oder Verweigern stellen. Zwei Schichten setzen dasselbe Regelwerk durch: der virtuelle Switch nach Ziel-IP und nach Hostnamen, die er aus den DNS-Antworten des Gasts mitgehört hat, und der Proxy nach TLS-SNI. Transparente Abfangung ist standardmäßig an, ein Build-Skript, das HTTPS_PROXY löscht, ändert also nichts daran, welche Verbindungen hinausgehen.

Der crates.io-Angriff der vergangenen Woche zeigt, was diese Regel abfängt. In StepSecuritys Analyse dekodierte das Build-Skript des Droppers eine base64-URL und holte eine plattformspezifische Binärdatei von einer nackten IP auf Port 9089, mit abgeschalteter Zertifikatsprüfung, und löste dann den Kindprozess ab, damit Cargo nicht auf ihn wartet. Bei verweigertem nicht zugeordnetem Verkehr kommt dieser Abruf nie zustande, und der Exit-Code des Build-Skripts hört auf, eine interessante Frage zu sein.

Eine Installation, zwei MaschinenAuf dem Laptopder Resolvernimmt, was zuletzt veröffentlicht wurdedie Install-Skriptelaufen als Sie, vor jedem Importdie Zugangsdaten~/.ssh ~/.aws ~/.npmrc $GH_TOKENdie Leitungerreicht jeden Host, ohne ProtokollIn einem Bromure-ArbeitsbereichAltersschranke, standardmäßig bei zwei Tagengleitende Refs bleiben unter der Grenze · einegepinnte zu frische Version bekommt ein 451aus dem Tarball entferntMetadaten-Hash neu, npm prüft weiterhin erfolgreichAttrappen, auf der Leitung getauschtechte Werte bleiben auf dem Mac · SigV4 neu signiertnicht zugeordnet: verweigern · Sicherheitsprotokoll
Dieselben vier Schritte, ausgeführt in einem Bromure-Arbeitsbereich. Schritt eins passiert weiterhin, denn niemand kann jemanden davon abhalten, eine schlechte Version zu veröffentlichen. Die Schritte zwei, drei und vier treffen jeweils auf eine Kontrolle, die auf dem Mac lebt, außerhalb von allem, was die Installation beschreiben kann.

Sechsundachtzig Minuten

Gehen Sie zu demselben Angriff zurück, um zu sehen, warum eine Uhr ein Urteilsvermögen schlägt. Die vergifteten Releases von arrayref, internment und append-only-vec lebten 86, 90 und 107 Minuten, bevor crates.io sie zurückzog. Um Resolver auf sie zu lenken, zog der Angreifer die sauberen Versionen zurück, 0.3.9 bis hinunter zu 0.3.5, in einem Schwall, der sechzehn Sekunden dauerte, und ließ ein Release übrig, das niemand zurückgezogen hatte. Der schärfste Satz von StepSecurity zu dem Vorfall: „Der Angreifer hat die eigene Sicherheitsfunktion der Registry in den Zustellkanal verwandelt.“ Und arrayref selbst trug gar keinen bösartigen Code. Die Nutzlast kam über einen Build-Zeit-Typosquat von proc-macro2 herein.

Eine Zwei-Tage-Altersschranke muss nichts davon je erkennen. Eine sechsundachtzig Minuten alte Version ist jünger als die Grenze, und bis sie alt genug zum Installieren ist, hat crates.io sie längst gelöscht. Der Angreifer baute ein Fenster, das kürzer ist als das, welches die Schranke ohnehin ignoriert.

Angriff siebenundfünfzig

Der Bericht schließt mit einem Satz, den man behalten sollte: „56 Angriffe in 12 Monaten. Angriff Nummer 57 wird bereits gebaut.“

Sie werden nicht wissen, welches Paket ihn trägt, und Sie werden ihn nicht lesen. Ihr Agent auch nicht. Fünf Monate mit einem alle drei Tage laufen weit jenseits der Taktung, in der irgendwer prüft, und das Unachtsamkeit zu nennen bringt niemanden weiter. Sie entscheiden aber sehr wohl, worauf er landet: ob die Version, die er braucht, eine ist, die Ihr Resolver nimmt, ob die Geheimnisse, nach denen er sucht, echt sind, und ob die Adresse, die er erreichen will, eine ist, zu der Ihre Maschine routet. Drei Einstellungen, alle auf Ihrer Seite der Grenze.


Quellen: StepSecurity, „The State of Open Source Supply Chain Attacks“ (22. August 2026) · StepSecurity, „Rust Supply-Chain Attack: arrayref, internment, and append-only-vec Poisoned by the proc-macro1 Build-Time Dropper“ (20. August 2026) · StepSecurity, „Team PCP Stole 78,330 Secrets From 2,186 Organizations“ (13. August 2026)