CodeQL-Lieferkettenangriff: Sicherheitsvorfall ausgelöst durch offengelegtes GitHub-Secret
(praetorian.com)- Wenn ein offengelegtes GITHUB_TOKEN in seinem kurzen Gültigkeitsfenster ausgenutzt wurde, konnte sich dadurch ein Angriffsweg für einen Lieferkettenangriff öffnen, der in mehreren Repositories mit CodeQL über GitHub-Actions-Workflows zur Codeausführung führen konnte
- Das Token befand sich in einem Workflow-Artefakt, das von einem fehlgeschlagenen Debug-Workflow des Repositories
github/codeql-actionhochgeladen worden war, und es handelte sich um ein GitHub-App-Installationstoken mit den Berechtigungencontents: write,actions: write,packages: write - Der Erfolg des Angriffs hing von einer Race Condition ab: Das Token musste nach dem Artefakt-Upload und vor dem Ende des Jobs heruntergeladen und genutzt werden; laut tatsächlichen Logs gelang dies in etwa 1,022 Sekunden, beobachtet wurden rund 2 Sekunden für Branch-Erstellung, Push von
poc.txtund Tag-Erstellung - Da die Standardkonfiguration von CodeQL intern den v3-Tag von
github/codeql-actionausführt und dieser Tag nicht unveränderlich war, hätten Angreifer durch das Verschieben des Tags auf einen bösartigen Commit auch Repositories treffen können, die den Standard-CodeQL-Workflow verwenden - GitHub reichte rund drei Stunden nach der Meldung einen PR ein, der den Upload von Debug-Artefakten deaktivierte, vergab CVE-2025-24362 und erklärte im Advisory, dass keine Hinweise auf eine Kompromittierung der Plattform oder Systeme gefunden wurden
Angriffspfad auf die CodeQL-Lieferkette ausgehend von einem öffentlichen Artefakt
- Ein einziges offengelegtes Secret konnte zu einem potenziellen Lieferkettenangriff auf GitHub CodeQL führen
- Das betreffende Secret war jeweils nur etwa 1,022 Sekunden gültig, doch innerhalb dieses Fensters konnten Angreifer die nötigen Schritte ausführen, um innerhalb eines GitHub-Actions-Workflows Code auszuführen
- Der mögliche Wirkungsbereich reichte sowohl bis zu GitHub Cloud als auch zu GitHub Enterprise
- Zu den möglichen Auswirkungen gehörten:
- Abfluss von Quellcode aus privaten Repositories, die CodeQL verwenden
- Diebstahl von GitHub-Actions-Secrets innerhalb von CodeQL-Workflow-Jobs
- Codeausführung auf interner Infrastruktur, auf der CodeQL-Workflows laufen
- Diebstahl von Secrets aus Workflows, die GitHub Actions Cache in CodeQL-nutzenden Repositories verwenden
- Laut GitHub Advisory fand GitHub keine Hinweise auf eine Kompromittierung der Plattform oder Systeme
Wie das Secret entdeckt wurde
- Verwendet wurde ein Actions Artifacts Secret Scanner, der GitHub-Actions-Workflow-Artefakte herunterlädt, rekursiv entpackt und mit Nosey Parker nach Secrets scannt
- Die Funktion wurde in Chariot integriert und als Open Source über die Funktion Gato veröffentlicht
- Nach einem Tag Scanning wurde im Artefakt des Repositories
github/codeql-actionein Token gefunden- Das Zielartefakt war die ZIP-Datei
my-debug-artifacts, die vom Workflow „PR Check – Debug artifacts after failure“ hochgeladen worden war - Nach dem Entpacken von
my-db-java-partial.zipwurde in einem Crash-Report ein GitHub-Token erkannt, das mitghs_begann - Eine manuelle Prüfung ergab, dass es sich um ein GitHub-App-Installationstoken handelte, das in einer Datei mit Umgebungsvariablen des GitHub-Runners gespeichert war
- Das Zielartefakt war die ZIP-Datei
Verknüpfung von GitHub Actions, Artefakten und CodeQL
- GitHub Actions ist eine CI/CD-Plattform, die in YAML-Workflows definierte Aufgaben auf Runnern ausführt
- Jeder Workflow-Run erzeugt ein automatisch generiertes GitHub-App-Installationstoken namens GITHUB_TOKEN
- Der Runner authentifiziert sich damit bei GitHub, um die vom Workflow verlangten Aufgaben auszuführen
- Die Berechtigungen können auf Workflow-, Repository- und Organisationsebene festgelegt werden
- GitHub-Actions-Workflow-Artefakte sind Dateien, die ein Workflow zur späteren Verwendung in GitHub Actions speichert
- Standardmäßig sind sie für Personen mit Leserechten auf das Repository zugänglich
- Sie werden bis zu 90 Tage gespeichert
- CodeQL ist GitHubs Engine für Codeanalyse und wird für statische Analysen in GitHub-Repositories zur Erkennung von Schwachstellen verwendet
- Sicherheitstools wie CodeQL müssen teils auf sensible Systeme und Daten zugreifen und können bei einer Kompromittierung zu einer Backdoor werden
Token-Berechtigungen und Race Condition
- Im Schritt „Setup Job“ der Workflow-Logs war zu sehen, dass das betreffende GITHUB_TOKEN volle Schreibrechte hatte
- Besonders wichtig waren folgende Berechtigungen:
contents: write: Branches erstellen, Tags erstellen, Release-Artefakte hochladenactions: write: Actions-Jobs undworkflow_dispatch-Events auslösenpackages: write: Pakete hochladen
- Da das Token nur während der Laufzeit des Workflow-Jobs gültig war, mussten für den Angriff drei Bedingungen erfüllt sein:
- Das Token musste Schreibrechte haben
- Es musste die Upload-Artifact-API v4 verwendet werden, mit der sich Artefakte vor Abschluss des Jobs abrufen lassen
- Das Zeitfenster zwischen Artefakt-Upload und Job-Ende musste ausreichen, um das Token herunterzuladen, zu entpacken und zu nutzen
- CodeQL verwendete die Action
actions/upload-artifactnicht direkt, sondern nutzte im Quellcode manuell den Upload-Artifact-Client; laut Kommentar im Code kam Version 4 zum Einsatz - Die Zeitabstände in den rohen GitHub-Logs waren extrem kurz:
- „Finalizing artifact upload“: 17:22:09.888
- „Cleaning up orphan processes“: 17:22:10.911
- Rechnerisch waren das rund 1,022 Sekunden; beobachtet blieb das Token nach dem Cleanup noch etwa 1 weitere Sekunde gültig, also insgesamt rund 2 Sekunden
PoC: Ausführung von artifact_racer.py
- Zur Verifikation wurde das Python-Skript
artifact_racer.pyerstellt - Der Ablauf war wie folgt:
- Es fragt fortlaufend ab, ob im Repository
github/codeql-actionder Workflow „PR Check – Debug artifacts after failure“ gestartet wurde - Es überwacht die Artefakte des laufenden Workflows
- Sobald ein Artefakt erscheint, lädt es dieses herunter und extrahiert das GITHUB_TOKEN
- Mit dem extrahierten Token erstellt es einen neuen Branch
- In diesen Branch pusht es eine leere Datei namens
poc.txt - Für den Commit erstellt es einen neuen Tag
- Es fragt fortlaufend ab, ob im Repository
- Da das Artefakt etwa 21 MB groß war, wurde ein Erfolg innerhalb des Zeitfensters als realistisch eingeschätzt
- Nach einem erfolgreichen Test in einem Test-Repository wurde das Skript gegen das Repository
github/codeql-actionausgeführt - Rund zwei Stunden später lief der Workflow, und das Skript konnte das Token abrufen sowie Branch-Erstellung, File-Push und Tag-Erstellung erfolgreich durchführen
Wie Tag-Manipulation die Auswirkungen vergrößerte
- Mit diesem Token konnten Angreifer bösartigen Code in ungeschützte Branches einbringen
- Unauffälliger wäre auch eine Strategie gewesen, kleine bösartige Änderungen in einem Feature-Branch vor dem Merge unterzubringen und anschließend auf den Merge zu warten
- Auch die Berechtigung zum Erstellen von Tags war kritisch
- Wenn ein Commit mit bösartigem Code den Tag
v3erhalten hätte, hätten Nutzer, diecodeql-action@v3manuell einsetzen, den bösartigen Code ausführen können
- Wenn ein Commit mit bösartigem Code den Tag
- Noch größer wurde die Wirkung durch die Standardkonfiguration von CodeQL
- Wenn CodeQL in den Repository-Einstellungen als Standardkonfiguration aktiviert wird, läuft ein spezieller GitHub-Actions-Workflow, der in der Workflow-Liste des Repositories nicht sichtbar ist
- Dieser Workflow führt Repository-Checkout, CodeQL-Initialisierung, CodeQL-Scan und Upload der Ergebnisse aus
- Intern führt er die Action aus dem Repository
github/codeql-actionanhand des Commits aus, auf den der v3-Tag zeigt
- Zu diesem Zeitpunkt war der
v3-Tag nicht unveränderlich, und das von GitHub empfohlene Workflow-Pinning wurde nicht verwendet - Hätten Angreifer den kompromittierten GITHUB_TOKEN genutzt, um den
v3-Tag auf einen bösartigen Commit zu verschieben, hätten Repositories mit dem Standard-CodeQL-Workflow die bösartige CodeQL-Action ausführen können - Da die CodeQL-Action den Quellcode des Ziel-Repositories auscheckt, hätte eine bösartige Action den Quellcode aus Repositories mit CodeQL-Standardkonfiguration exfiltrieren können
Angriffspfad über GitHub Actions Cache Poisoning
- Das GITHUB_TOKEN der Standard-CodeQL-Action hat nur Leserechte, daher konnten mit der Standardkonfiguration allein keine Schreiboperationen am Repository, keine Release-Backdoor und kein unmittelbarer Secret-Diebstahl über
workflow_dispatchdurchgeführt werden - Allerdings läuft die Standard-CodeQL-Action auf dem main-Branch des Repositories
- Der main-Branch eines GitHub-Repositories kann Cache-Einträge schreiben, die repositoryweit verwendet werden, wodurch sich eine Möglichkeit für GitHub Actions Cache Poisoning ergibt
- GitHub Actions Cache Poisoning ist eine in Adnan Khans Beitrag beschriebene Technik; Cacheract ist Malware, die über Cache Poisoning Persistenz in Build-Pipelines herstellt
- Wenn Angreifer Cacheract im CodeQL-Workflow ausbringen, wäre folgender Ablauf möglich gewesen:
- Cache-Eintrag vorhersagen
- Den betreffenden Eintrag mit einer bösartigen Action überschreiben
- Codeausführung in Workflows erlangen, die
actions/cacheverwenden - GitHub-Actions-Secrets und höher privilegierte GITHUB_TOKENs aus diesen Workflows stehlen
- Selbst wenn die bösartige CodeQL-Action entdeckt und die Schwachstelle behoben worden wäre, hätte Cacheract das Cache Poisoning weiter durchführen können
- Als Beispiele für große Repositories, die sowohl CodeQL als auch
actions/cachenutzen, wurden Homebrew, Angular und Grafana genannt
CVE-2025-24362 und die Behebung
- Als Ergebnis dieser Offenlegung wurde CVE-2025-24362 vergeben
- Das offengelegte GITHUB_TOKEN befand sich in einem Debug-Artefakt, das von der CodeQL-Action nach einem fehlgeschlagenen Code-Scanning-Workflow hochgeladen worden war
- Das Repository der CodeQL Actions provozierte den Fehler absichtlich, doch auch bei anderen Nutzern der CodeQL Actions hätten ähnliche Fehler dazu führen können, dass ihre eigenen Secrets über Workflow-Umgebungsvariablen offengelegt werden
- Das Problem wurde in CodeQL Action 3.28.3 behoben
- Die größte potenzielle Auswirkung lag weniger in der CVE selbst als in dem Weg, die Schwachstelle gegen das Repository der CodeQL Actions auszunutzen und anschließend einen Lieferkettenangriff auf CodeQL-Nutzer durchzuführen
Reaktion von GitHub und empfohlene Gegenmaßnahmen
- Die Reaktionszeitleiste von GitHub sah wie folgt aus:
-
- Januar 2025, 15:13 UTC: Meldung an GitHub eingereicht
-
- Januar 2025, 17:48 UTC: GitHub bestätigte den Eingang
-
- Januar 2025, 18:28 UTC: GitHub bestätigte die Schwachstelle, deaktivierte den Workflow „PR Check – Debug artifacts after failure“ vorläufig und reichte den PR zur Deaktivierung des Uploads von Debug-Artefakten ein
-
- Januar 2025: GitHub vergab CVE-2025-24362 und veröffentlichte das Security Advisory
-
- Zur Verringerung des Risikos einer Secret-Offenlegung in GitHub-Actions-Workflow-Artefakten werden folgende Maßnahmen empfohlen:
- Nur bestimmte Dateien oder Verzeichnisse als Workflow-Artefakte hochladen
- Keine Artefakte hochladen, die Umgebungsvariablen,
.git/configoder Dateien aus dem Runner-Verzeichnis<path_to_runner_dir>/_work/_temp/enthalten - GITHUB_TOKEN-Berechtigungen auf read-only beschränken
- Vor dem Artefakt-Upload einen Secret-Scan durchführen
1 Kommentare
Meinungen auf Hacker News
Wenn GitHub immutable actions früher energisch vorangetrieben hätte, wären die Auswirkungen solcher Vorfälle deutlich geringer gewesen.
Ich sage immer wieder, dass diese Funktion derzeit über 70 % der Angriffsfläche von GitHub Actions abdecken würde. Wenn man sieht, dass jede Woche etwas passiert, ist es inzwischen wohl Zeit für den Rollout.
[1] https://github.com/features/preview/immutable-actions
Es gibt keine Erklärung dafür, warum dieses kurzlebige Token überhaupt die Berechtigung hatte, neue Deployments zu erstellen und Artifact Attestations zu erzeugen.
Als Fix wurde gesagt, man habe Debug-Logs abgeschaltet, aber nicht beantwortet, ob die Berechtigungen des kurzlebigen Tokens passend für die Code-Analyse-Engine eingeschränkt wurden.
Früher gab es als Standard nur die permissive Einstellung, weshalb sie leider in vielen alten Organisationen und Repositories noch verwendet wird.
Wenn man ein neues Repository erstellt, erbt es den Standard der übergeordneten Organisation; wenn niemand ihn ändert, bleibt dieser unsichere Standard also bestehen. Eine globale Benutzereinstellung gibt es nicht, daher nutzen neue persönliche Repositories einen restriktiven Standard. Neu erstellte Organisationen verwenden meines Wissens ebenfalls bessere Defaults.
[0]: https://docs.github.com/en/actions/security-for-github-actio...
Ich bin immer stärker davon überzeugt, dass CI und CD vollständig getrennte Umgebungen sein sollten. Nur weil CI kompromittiert wird, dürfen keine CD-bezogenen Tokens durchsickern.
Zum Beispiel sollte eine Bedingung wie
"sub":"repo:octo-org/octo-repo:environment:prod"[1] zwingend erfüllt sein; wenn man das System noch weiter härten will, kann man zusätzliche [fun claims][] ergänzen.1: https://docs.github.com/en/actions/security-for-github-actio...
fun claims: https://github.com/github/actions-oidc-debugger#readme
Die Reaktionszeit war kein Witz. GitHubs Reaktion ist ziemlich beeindruckend.
Als jemand mit dem Nachnamen Prater: Da dieser Name von Praetorian abgeleitet ist, hätte ich wirklich gern praetorian.com gehabt.
Öffentliche GitHub Actions zu nutzen heißt, Ärger geradezu einzuladen – umso mehr, wenn man die Workflow-Prozeduren nicht analysiert.
Besser wäre es, woodpecker oder andere gute CI-Builder (circle, travis, gitlab usw.) selbst zu hosten.
Wir haben CodeQL auf OpenZFS-PRs aktiviert. Für OpenZFS ist das kein Problem, denn unser Code ist nicht geheim. :)
Immerhin wurde es zumindest schnell behoben.
Ist das behoben worden?
Diese Website ist so schlecht performant, dass ich kaum scrollen kann.