Dependency Confusion und Typosquatting: Praktische Abwehr fuer Dev-Teams
Wie Registry-Policies, Lockfiles und Scoping boesartige Pakete vor dem Build blockieren. Hands-on Technik-Guide vom Basilisk-Team.

2021 verdiente ein Forscher ueber 130 tausend Dollar Bug Bounty, indem er Pakete mit internen Namen von Apple, Microsoft, PayPal und dutzenden weiteren Firmen auf den oeffentlichen npm- und PyPI-Registries publizierte. Der Angriff brauchte keinen Zero-Day: er nutzte nur die Praezedenz, die Paketmanager der oeffentlichen Registry geben, wenn ein Name auf beiden Seiten existiert. Fuenf Jahre spaeter finden Basilisk-Teams diesen Vektor noch in sieben von zehn auditierten Pipelines offen. Dependency Confusion und Typosquatting sind keine akademische Spielerei, sondern die billige Eingangstuer, um einen kompletten Build zu kompromittieren und damit jeden Kunden, der dieses Artefakt erhaelt. Dieser Beitrag zerlegt beide Vektoren, zeigt die Angriffskette Schritt fuer Schritt und liefert eine Abwehr, die du heute noch in deine CI eintragen kannst.
Was Dependency Confusion technisch bedeutet
Der Mechanismus ist simpel und brutal. Du hast ein internes Paket namens acme-payments-sdk auf einem privaten Nexus oder Artifactory. Ein Angreifer findet diesen Namen in einer geleakten package.json, einem Stack-Overflow-Post oder einer oeffentlichen Docker-Schicht und publiziert acme-payments-sdk@99.0.0 auf npmjs.com. Beim naechsten npm install ohne strikten Lockfile waehlt der Resolver die hoehere Version, weil die Standardkonfiguration die oeffentliche Registry mit einbezieht und SemVer die groesste kompatible Version bevorzugt. Fertig: beliebiger Code laeuft in deinem CI mit AWS-Credentials, GitHub-Tokens und Zugriff auf die interne Registry. Wir haben das im Feld bei Assessments wie Pentest von REST und GraphQL APIs: Technische Checkliste fur legales Bug Bounty gesehen, wo die Build-Oberflaeche angreifbarer war als die API selbst. Die Wurzel des Problems ist, dass npm, pip und andere denselben flachen Namensraum fuer intern und oeffentlich benutzen und ohne explizite Konfiguration keinen Herkunftsnachweis fordern.
Typosquatting als eigenstaendiger Vektor
Typosquatting spielt in einer anderen Liga. Statt den echten Namen zu uebernehmen, registriert der Angreifer colorss, requets, python-dateutill, lodahs oder djanga. Die Payload landet im postinstall-Hook oder direkt im importierten Modul und laeuft, sobald jemand sich vertippt oder eine KI-Assistenz einen halluzinierten Paketnamen vorschlaegt (der sogenannte Slopsquatting-Effekt). Phylum-Research katalogisierte 2024 ueber elftausend boesartige Pakete auf PyPI mit diesem Muster innerhalb von zwoelf Monaten. Die Payloads variieren: Diebstahl von Umgebungsvariablen, Krypto-Mining, RAT-Installation, DNS-Exfiltration der ~/.aws/credentials. Die erste Verteidigung ist kulturell: verpflichtendes Code-Review fuer jede Aenderung an Dependencies, kein blindes Hochziehen von Versionen. Tools wie Socket, Snyk Advisor und deps.dev markieren bereits frisch veroeffentlichte Pakete, Pakete ohne Maintainer-Historie oder mit verdaechtigen Install-Script-Mustern und geben dir eine Risiko-Signatur vor dem Merge.
Die Angriffskette Schritt fuer Schritt
Verstehe den Angreifer, dann verstehst du die Abwehr. Phase eins ist Reconnaissance: der Angreifer sammelt interne Paketnamen aus GitHub-Suchen nach @acme, aus geleakten .npmrc, aus Sourcemaps im Frontend-Bundle oder aus Fehlermeldungen in oeffentlichen CI-Logs. Phase zwei ist Publikation: er registriert das gleiche Paket mit einer absurd hohen Version auf der oeffentlichen Registry und packt einen preinstall-Hook hinein, der eine Callback-URL kontaktiert. Phase drei ist die Detonation: dein CI zieht bei einem beliebigen Build das oeffentliche Paket, der Hook laeuft mit den Rechten des Runners. Phase vier ist Persistenz und Exfiltration: der Code liest Environment-Variablen, OIDC-Tokens und Deploy-Keys und schickt sie raus, oft ueber DNS oder einen harmlos aussehenden HTTPS-POST. Genau hier verschmilzt Supply-Chain-Kompromittierung mit klassischem Post-Exploitation, weshalb dieselbe Denke wie bei Incident Response greift.
Lockfiles und Hash-Pinning
Lockfiles loesen achtzig Prozent des Problems, wenn man sie ernsthaft nutzt. package-lock.json, yarn.lock, pnpm-lock.yaml, poetry.lock, Cargo.lock und go.sum fixieren nicht nur die Version sondern den Integritaets-Hash. Konfiguriere npm ci, pnpm install --frozen-lockfile, pip install --require-hashes und cargo --locked in Pipelines. Kein loses npm install in Produktion, denn das darf den Lockfile veraendern. Kombiniert mit einer .npmrc, die registry=https://nexus.intern/repository/npm-group/ und always-auth=true setzt, reduzierst du drastisch die Chance, dass der Resolver versehentlich zur oeffentlichen Registry abwandert. Wichtig: Ein Lockfile schuetzt nur, wenn der CI-Runner ihn respektiert und nicht regeneriert. Das Denkmuster spiegelt das, was wir in Supply Chain Security: Sigstore-Signatur und echte SBOMs in CI/CD ueber SBOMs und Attestations behandeln.
Scoping und private Registries pro Oekosystem
Scoping ist die ultimative Waffe gegen Dependency Confusion im JavaScript-Oekosystem. Migriere alle internen Pakete zu @acme/payments-sdk, @acme/auth, @acme/billing. In der .npmrc setze @acme:registry=https://nexus.intern/. Jetzt loest npm diesen Scope nur auf der internen Registry auf, selbst wenn jemand @acme/payments-sdk auf npmjs publiziert (Microsoft reserviert gaengige Scopes seit 2021). In Python nutze getrennte Indizes: pip --index-url fuer intern und --extra-index-url nur wenn wirklich noetig, denn beide Indizes werden gemischt und die hoehere Version gewinnt. Besser, du spiegelst alles ueber devpi oder Artifactory und setzt ausschliesslich index-url. Fuer Go blockiert GOPRIVATE=git.acme.com plus GONOSUMCHECK-Disziplin Anfragen an proxy.golang.org. Dieses Hardening passt direkt zu Linux-Server-Hardening: CIS Benchmark Anwenden Ohne die Produktion zu Zerlegen und dem Least-Privilege-Prinzip.
CI-Isolation und ephemere Credentials
Auf CI-Seite isoliere konsequent. Jeder Build-Job sollte mit ephemeren Tokens laufen, ohne Produktionszugriff, mit Netzwerk-Egress gefiltert durch einen Proxy, der nur interne Registry, github.com und bekannte Endpoints zulaesst. OIDC mit kurzlebigen Credentials in GitHub Actions oder GitLab CI eliminiert langlebige Secrets, die ein Install-Hook stehlen koennte. Deaktiviere Install-Scripts wo moeglich mit npm ci --ignore-scripts und erlaube sie nur fuer eine kuratierte Allowlist. Fuehre den Build in einem Container ohne Root aus, read-only Dateisystem, kein Zugriff auf den Docker-Socket. So wird selbst ein erfolgreicher Install-Hook zum stumpfen Messer: er findet keine langlebigen Secrets, kann nicht nach aussen telefonieren und ueberlebt das Ende des Jobs nicht. Diese Segmentierung ist billiger als jeder Incident und schuetzt auch gegen den Fall, dass eine legitime Dependency spaeter uebernommen wird.
Verifikation vor der Installation
Fuege einen Pre-Install-Verifikationsschritt hinzu: scripts/check-deps.sh fuehrt npm audit signatures aus, validiert dass keine Dependency in den letzten sieben Tagen ohne manuelle Freigabe publiziert wurde (Cooldown gegen frische Uebernahmen), und prueft Pakete gegen eine Allowlist. Ergaenze osv-scanner gegen die OSV-Datenbank und Socket im CI, das Verhaltensdiffs zwischen Versionen zeigt: neue Netzwerkaufrufe, neuer Dateisystemzugriff, neu hinzugekommene Install-Skripte. Ein Paket, das ploetzlich child_process importiert oder eine IP kontaktiert, wird geblockt und geht zur manuellen Pruefung. Das Datadog-Team veroeffentlichte 2025 einen Bericht, der zeigte, dass zweiundsechzig Prozent der Supply-Chain-Kompromittierungen mit diesen drei Regeln kombiniert blockiert worden waeren. Kein einzelnes Tool ist eine Silberkugel, aber die Verkettung von Cooldown, Signatur-Pruefung und Verhaltens-Diff schliesst die haeufigsten Wege.
Kontinuierliches Monitoring und Namensschutz
Kontinuierliches Monitoring schliesst den Kreis. Konfiguriere Sigstore-Rekor-Alarme fuer jede Veroeffentlichung mit deinem Organisationsnamen, registriere defensiv die Typo-Squatting-Domains und Paketnamen deines Produkts (acme-cloud, acme-coud, acmecloud) und pflege ein Inventar cosign-signierter SBOMs fuer jeden Release. Taucht ein verdaechtiges Paket auf, hast du bereits Evidenz fuer den Takedown und Daten fuer Incident Response, im Stil wie in DFIR unter Linux: Live-Triage mit UAC und Velociraptor. Reserviere die Namen deiner internen Pakete proaktiv als leere Platzhalter auf der oeffentlichen Registry, damit niemand sie besetzen kann. Trainiere das Team, jede neue Install-Script-Warnung zu melden statt sie reflexhaft zu ignorieren, denn die Warnung ist oft das einzige Signal vor der Kompromittierung.
Haeufige Fehler in der Praxis
Fuenf Pitfalls sehen wir in fast jedem Audit. Erstens: --extra-index-url in Python als Standard, was intern und PyPI mischt und den Vektor weit oeffnet. Zweitens: Lockfiles, die im CI regeneriert statt respektiert werden, weil jemand npm install statt npm ci im Skript stehen liess. Drittens: interne Pakete ohne Scope, sodass jeder oeffentliche Namensraum sie ueberschreiben kann. Viertens: Install-Scripts global erlaubt, obwohl neunzig Prozent der Builds sie nicht brauchen. Fuenftens: langlebige NPM- oder PyPI-Tokens im CI, die ein Hook exfiltriert und die Monate gueltig bleiben. Jeder dieser Fehler fuer sich reicht fuer eine Kompromittierung; zusammen sind sie ein offenes Scheunentor. Die gute Nachricht ist, dass jeder in unter einem Tag behoben werden kann und keine Codeaenderung am Produkt erfordert.
Praktische Checkliste
Arbeite diese Liste heute ab. Erstens: alle internen npm-Pakete auf einen @scope mit interner Registry-Zuordnung migrieren. Zweitens: in jeder Pipeline npm ci, --frozen-lockfile, --require-hashes oder --locked erzwingen. Drittens: in Python nur index-url auf den internen Mirror, kein --extra-index-url. Viertens: GOPRIVATE fuer alle internen Go-Module setzen. Fuenftens: Install-Scripts per Default deaktivieren, Allowlist pflegen. Sechstens: OIDC statt langlebiger Registry-Tokens. Siebtens: Egress-Proxy im CI mit Allowlist. Achtens: osv-scanner, npm audit signatures und Socket als Merge-Gate. Neuntens: interne Namen defensiv auf der oeffentlichen Registry reservieren. Zehntens: Rekor-Alarme auf den Organisationsnamen. Wer diese zehn Punkte abhakt, hat die billige Eingangstuer verriegelt.
FAQ
Reicht ein Lockfile allein gegen Dependency Confusion? Nein. Ein Lockfile schuetzt bestehende Dependencies, aber sobald du eine neue interne Dependency hinzufuegst oder den Lockfile regenerierst, greift die Registry-Praezedenz wieder. Scope-Bindung an die interne Registry und ein Egress-Proxy sind die strukturelle Loesung; der Lockfile ist die zweite Schicht.
Ist Typosquatting nur ein npm- und PyPI-Problem? Nein. RubyGems, Maven Central, NuGet, Crates und sogar Docker-Hub-Images sind betroffen. Der Verteidigungsansatz ist ueberall gleich: kuratierter interner Mirror, Verhaltens-Diff zwischen Versionen, Cooldown fuer frisch publizierte Artefakte und menschliches Review bei jeder Dependency-Aenderung.
Fazit
Dependency Confusion und Typosquatting sind keine exotischen Angriffe, sie sind die guenstigste Art, an einer Organisation vorbeizukommen, ohne eine einzige Zeile ihres eigentlichen Codes anzugreifen. Die Abwehr ist bekannt, billig und heute umsetzbar: Scope-Bindung, Hash-Pinning, isolierte CI mit ephemeren Credentials, Verifikation vor der Installation und kontinuierliches Monitoring. Praktischer Takeaway: heute noch, auditiere deine .npmrc, .pip.conf und go env. Wenn du nicht in dreissig Sekunden beantworten kannst, aus welcher Registry jede Dependency stammt, bist du bereits verwundbar. Die Angreifer brauchen keinen Zero-Day; sie warten nur darauf, dass jemand die Registry-Reihenfolge nicht konfiguriert hat.


