Der Gheist-GitHub-Token-Angriff: 13.500 gepflanzte Branches und eine Sperre, die nur halb greift

Quellcode auf einem grossen Monitor in einem abgedunkelten Raum, warmes Licht einer Schreibtischlampe
Deine Reaktion:

„The control worked, and the malicious payloads never ran.“ So fasst Wiz Research zusammen, was die Freigabesperre von GitHub bei öffentlichen Repositories bewirkt hat. Das klingt nach Entwarnung. Für einen Teil des Angriffs stimmt das auch. Wenige Absätze später steht im selben Bericht jedoch, dass dieselbe Nutzlast in privaten Repositories und in GitHub-Enterprise-Umgebungen ausgeführt wurde – inklusive AWS-Rollen, die Workflows auf Angreifer-Branches annahmen.

Seit dem 15. September 2026 verfolgen die Forscher eine Kampagne, die sie nach dem User-Agent ihrer API-Aufrufe „Gheist“ nennen. Das Muster ist schlicht und wirkt gerade deshalb: Gestohlene GitHub-Tokens werden nicht gezielt eingesetzt, sondern massenhaft abgearbeitet. Ein Werkzeug prüft die Rechte jedes Tokens, pflanzt in jedem erreichbaren Repository einen Branch mit Workflow und lässt GitHub den Rest erledigen. Mehr als 13.500 solcher Branches aus über 850 kompromittierten Konten hat das Team gesammelt – von privaten Bastelprojekten bis zu privaten Repositories großer Unternehmen.

Wer sich unter einem gestohlenen Token wenig vorstellt, kann an ein Schlüsselbund denken. Ein Passwort öffnet ein Schloss, ein Token oft ein ganzes Gebäude: Repositories, Workflows, Environments, Cloud-Rollen. Der Angriff betrifft deshalb nicht nur eine Codebasis, sondern die Lieferkette eines Unternehmens.

Was Wiz Research unter dem Namen Gheist dokumentiert hat

Das Werkzeug wählt keine Ziele aus, es arbeitet ab, was die Tokens hergeben. Für jedes erreichbare Repository entsteht ein Branch, dessen Name aus ci-sync- und sechs zufälligen Zeichen besteht, dazu die Datei .github/workflows/sync-check.yml mit der Commit-Nachricht ci: sync config. Der Commit ist unsigniert und läuft unter dem Namen des Token-Inhabers; in der Historie fällt er zunächst nicht auf. Der Push startet den Workflow, ohne dass jemand etwas anklicken muss.

Die Arbeit erledigt anschließend GitHub. Der Workflow gibt den Inhalt des Secrets-Kontexts aus, das Ergebnis landet im Workflow-Log. Dieses Log holt das Werkzeug über die GitHub-API ab und löscht den Lauf wenige Sekunden später. Zurück bleiben ein Branch und ein Commit. Das Protokoll ist weg.

Zum 24. Oktober läuft die Kampagne weiter, obwohl rund zwei Drittel der beteiligten Konten bei GitHub nicht mehr erreichbar sind. Vermutlich hat GitHub reagiert; die Forscher hatten den Vorfall gemeldet. Ein abgeräumtes Konto heißt aber nicht, dass die dahinterliegenden Tokens unbrauchbar sind – sie können in anderen Zusammenhängen wieder auftauchen.

Wie sync-check die Secrets aus dem Log holt

Ein Workflow-Log lässt sich mit einem schwarzen Brett im Hausflur vergleichen. Normalerweise hängen dort nur Zettel, die jeder sehen darf, und sensible Angaben sind geschwärzt. Gheist hängt den Zettel selbst auf, fotografiert das Brett und nimmt das Foto wieder mit. Nach außen verlässt dabei kein Byte das Gebäude: Es gibt keine Angreifer-Domain und keinen auffälligen ausgehenden Verkehr, den eine Firewall blocken könnte, weil die Exfiltration über GitHubs eigene API läuft. Das erschwert die Erkennung.

Drei Details sorgen dafür, dass die Schwärzung nicht greift. GitHub maskiert Secret-Werte nur dann, wenn sie exakt so im Log erscheinen, wie sie gespeichert sind – ein base32-kodierter Wert ist eine andere Zeichenkette und wird deshalb in voller Länge ausgegeben. Die Angabe permissions: {} beschränkt zwar das GITHUB_TOKEN des Jobs, das der Angreifer nicht braucht, lässt aber den Secrets-Kontext unangetastet. Und wenn ein Repository Deployment-Environments besitzt, listet das Werkzeug sie in einer Job-Matrix auf, um auch die environmentspezifischen Secrets auszugeben – häufig die Produktionszugänge.

In Enterprise-Organisationen kam noch etwas dazu: Das Werkzeug wechselte innerhalb von Minuten zwischen den Tokens mehrerer Nutzer und Automationskonten, klonte private Repositories, bevor es den Workflow pflanzte, und griff Stunden später mit Cloud-Credentials derselben Organisation auf AWS Secrets Manager zu. Die Kette reicht vom Repository bis in die Infrastruktur.

Tool A, Tool B und der Sprung auf self-hosted Runner

Die Forscher unterscheiden zwei Varianten, die parallel liefen und sich an den Branch-Namen auseinanderhalten lassen. Tool A nutzt ein hexadezimales Suffix und die schlichte Nutzlast. Tool B verwendet base36 und ergänzte innerhalb von Stunden nach dem ersten Lauf am 28. September timeout-minutes: 6 sowie die Environment-Matrix; außerdem wählte es die Nutzlast pro Repository aus.

Am 19. Oktober kam ein echo X | base32 -w 120 zwischen die Ausgaben, das LAFA==== als Trenner druckt – vermutlich für den Log-Parser des Operators. Stunden später folgte ein zweiter Job namens sync-host mit runs-on: self-hosted, offenbar nur für Repositories mit registriertem self-hosted Runner. Er schreibt drei Hilfsdateien (.gdmp_pat, .gdmp_patg, .gdmp_sweep) und protokolliert jede Stufe unter einem gdmp-pivot-Header: Hostdetails und Crontab, dann eine rekursive Suche nach 31 Token-Formaten in Home-Verzeichnis, Workspace und Systempfaden, inklusive Schlüsseln für KI-Anbieter wie Anthropic, Hugging Face, Groq und NVIDIA.

Danach folgen die Umgebung jedes laufenden Prozesses aus /proc/<pid>/environ, ein Container mit dem Root-Dateisystem des Hosts über den Docker-Socket, AWS-Instance-Role-Credentials samt GCP- und Azure-Metadaten, die Credential-Dateien von GitHub Actions und GitLab Runnern sowie das Kubernetes-Service-Account-Token. Der Code ist fehlerhaft: Der Job sucht die falsche Runner-Key-Datei, seine Regex für URL-Credentials ist defekt, und GCP- sowie Azure-Tokens sammelt er gar nicht ein.

Die Freigabesperre schützt öffentliche Repositories – und nur die

Seit dem 28. Juli 2026 hält GitHub potenziell bösartige Workflow-Läufe in öffentlichen Repositories zurück, bis ein Mitarbeiter sie freigibt. Jeder öffentliche Gheist-Lauf, den die Forscher prüften, steht auf action_required – über alle Varianten hinweg, den self-hosted Job eingeschlossen. Die Sperre hat gegriffen, die Nutzlasten liefen nicht.

Für private Repositories und GitHub Enterprise Server gilt diese Sperre nicht. Dort zeigen die Audit-Logs von GitHub Läufe auf ci-sync--Branches, die abgeschlossen und anschließend mit dem User-Agent gheist gelöscht wurden. CloudTrail wiederum zeigt die eigenen Workflows der Organisationen, die auf diesen Branches liefen und AWS-Rollen annahmen – der Beweis, dass Actions ohne Freigabe ausgeführt wurden. Der Vorfall betrifft damit nicht nur GitHub, sondern auch die Cloud-Umgebungen der betroffenen Organisationen.

Für Verteidiger ist das ein brauchbarer Hinweis: Dieses Signal findest du auch ohne GitHub-Logs. Wer OIDC einsetzt, hat die Spur bereits in der Cloud.

Dieselben Konten, andere Kampagnen

Die kompromittierten Zugänge gehören nicht einer einzigen Gruppe. Andere Akteure nutzen dieselben Konten, und gestohlene Credentials wandern durch das Ökosystem. Am 6. Oktober benannten 391 Konten rund 1.461 Repositories in Lockangebote für Raubkopien um, etwa fl-studio-crack oder solana-sniper-lite; als Nebenwirkung verschwanden dabei 610 ci-sync-Branches. 166 dieser Konten tauchen in der Gheist-Aktivität überhaupt nicht auf – der Zugangspool ist also größer als diese Kampagne.

Am 18. Oktober legten 25 Gheist-Konten innerhalb von neun Minuten jeweils ein Repository namens „Windows RDP Runner“ an, offenbar der Versuch, GitHub Actions als kostenlose Rechenleistung zu missbrauchen. Bei einigen Opfern tauchte zudem PolinRider auf, die DPRK-zugeordnete Malware, die JavaScript in Build-Konfigurationen versteckt und rückdatierte Commits force-pusht: Am 19. und 20. Oktober schoben drei Betroffene ihre Gheist-Commits erneut hoch, mit einem Loader in vite.config.js hinter Hunderten Leerzeichen und in zwei Fällen einer api.js, die package.json vor jedem Dev- und Build-Schritt ausführt. 57 Konten aus der ersten Gheist-Phase waren im Mai bereits Opfer von Megalodon.

Infostealer-Logs und Tokens aus früheren Supply-Chain-Kompromittierungen wie dem Trivy-Vorfall im März passen zur Herkunft der Credentials. Zur Abgrenzung: Gheist ist nicht GhostAction; GhostAction nutzt andere Workflow-Dateien und exfiltriert Secrets an 193.32.204[.]199.

Suchen, reagieren, härten

Für die Suche gibt es eine Handvoll Muster, die sich ohne großen Aufwand prüfen lassen. Branches nach dem Muster ^ci-sync-[0-9a-z]{6}$, deren einzige Änderung die neue Datei .github/workflows/sync-check.yml mit der Commit-Nachricht ci: sync config ist, sind der direkteste Hinweis. In den Audit-Logs von GitHub lohnt der Blick auf Workflow-Läufe auf solchen Branches, die innerhalb einer Minute nach ihrem Ende gelöscht wurden, sowie auf jeden Aufruf mit dem User-Agent gheist.

Der stärkere Hebel liegt außerhalb von GitHub. Wenn Workflows per OIDC Cloud-Rollen annehmen, zeigen die Cloud-Audit-Logs Rollenübernahmen, deren Subjekt einen ci-sync--Branch enthält – dieser Fund beweist, dass Actions auf einem Angreifer-Branch liefen, auch ohne GitHub-Logs. Auf self-hosted Runnern suchen Teams nach den Dateien .gdmp_pat, .gdmp_patg und .gdmp_sweep sowie nach der Zeichenkette gdmp-pivot in Job-Logs.

Beim Reagieren gilt eine unangenehme Reihenfolge: erst rotieren, dann aufräumen. Das Löschen des Laufs oder des Branches macht die Offenlegung nicht rückgängig; deshalb müssen alle Repository-, Organisations- und Environment-Secrets rotiert werden, die dem betroffenen Repository zugänglich waren. Die Tokens, die die Commits gepusht haben, müssen widerrufen werden, und die Geräte ihrer Inhaber sollten auf Infostealer geprüft werden. Lief ein ci-sync-Branch auf einem self-hosted Runner, behandle Host und Instance-Rolle als kompromittiert. Halte sync-check-Läufe zurück und führe keinen Code aus ci-sync-Branches aus.

Für die Härtung reichen vorhandene Mittel: Reviewer für Environments mit Produktionssecrets, OIDC-Trust-Policies, die auf geschützte Branches oder Environments begrenzt sind, GitHub Apps oder kurzlebige feingranulare Tokens statt Personal Access Tokens. Self-hosted Runner laufen am besten ephemer, ohne Docker-Socket und ohne uneingeschränkten Metadatenzugriff.

Die Sperre für öffentliche Repositories hat funktioniert. 13.500 gepflanzte Branches hätten in öffentlichen Projekten großen Schaden anrichten können. Die Kampagne ist trotzdem nicht gestoppt: Sie läuft weiter und entwickelt sich, während rund zwei Drittel der beteiligten Konten bei GitHub verschwunden sind.

Für Betreiber ist der Vorfall kein reines GitHub-Problem. Ein Token mit Rechten auf ein privates Repository öffnet oft mehr als ein Repository. Prüfe deshalb, ob deine Workflows Secrets in Logs schreiben können, und beschränke Token-Rechte sowie OIDC-Vertrauen auf das Nötige. Das kostet einen Nachmittag; ein stiller Abfluss von Cloud-Zugängen kostet mehr.

Quelle: wiz.io

Deine Reaktion:
Artikel teilen:
Krötzsch-Check0 — 100
Fakten 80
Relevanz 85
Hype 40
Einschätzung 75
Redaktion 50 Stand 50 · noch keine Stimmen
Ist das Hype?
Sebastian Krötzsch
Autor

Sebastian Krötzsch

Sebastian Krötzsch schreibt auf sebask.de über Künstliche Intelligenz, Automatisierung, digitale Systeme und die Frage, was davon im Alltag wirklich nützlich ist. Ohne Buzzword-Nebel, dafür mit klarem Blick auf Praxis, Tools und echte Wirkung.