- Ein Forscher berichtet, wie er eine Schwachstelle in Nixpkgs fand, über die sich Schadcode in das gesamte Nix-Ökosystem einschleusen ließ
- Er erläutert das strukturelle Risiko von GitHub Actions mit dem Trigger
pull_request_target, bei dem selbst PRs externer Mitwirkender sensible Berechtigungen und Secrets offenlegen können
- Konkret wies er nach, dass sich in den Jobs zur Prüfung von editorconfig-checker und Code Owners durch Command Injection und den Einsatz symbolischer Links eine Rechteausweitung erreichen ließ
- Unmittelbar nach der Meldung behebte das Nixpkgs-Maintainer-Team die Schwachstellen zügig, deaktivierte anfällige Workflows und überprüfte den Umgang mit Berechtigungen erneut
- Hervorgehoben wird, wie wichtig in der CI/CD-Infrastruktur von Organisationen die Trennung von nicht vertrauenswürdigen Daten und sensiblen Abläufen, Least Privilege und strengere Richtlinien sind
Das gesamte Nix-Ökosystem hacken
Einführung und Hintergrund
- Auf der NixCon im vergangenen Jahr stellten der Forscher und seine Kollegin Lexi eine Schwachstelle in Nixpkgs vor
- Die entdeckte Schwachstelle eröffnete im Rahmen eines Supply-Chain-Angriffs die Möglichkeit, Schadcode in das gesamte Nix-Ökosystem einzuschleusen
- Von der Entdeckung über die Meldung bis zur Behebung erfolgte die Reaktion innerhalb nur eines Tages
- Da der Forscher dieses Jahr nicht an der NixCon teilnehmen kann, dokumentiert er den Ablauf in diesem Beitrag ausführlich
GitHub Actions: ein anfälliges Ziel
- GitHub Actions ist ein System für verschiedene Automatisierungsaufgaben (CI/CD) in Code-Repositories
- Schon mit Zugriff auf Workflow-Dateien lässt sich leicht Code einschleusen, weshalb sie ein wichtiges Ziel für Supply-Chain-Angriffe sind
- Workflow-Dateien werden in YAML geschrieben und sind nicht als Ausführungsformat gedacht, wodurch unerwartete Sicherheitslücken entstehen können
- Als einfaches Beispiel wird ein Workflow genannt, der beim Pushen von Code einen Befehl ausführt
Der gefährliche Trigger pull_request_target
- GitHub Actions bietet mehrere Trigger; pull_request_target unterscheidet sich deutlich von einem normalen
pull_request
pull_request_target besitzt auch bei Fork-PRs standardmäßig Lese-/Schreibrechte und Zugriff auf Secrets
- Bei falscher Verwendung kombiniert dieser Trigger nicht vertrauenswürdige externe Daten mit sensiblen Berechtigungen
- Auch die offizielle GitHub-Dokumentation warnt ausdrücklich vor diesem Risiko
- Der Forscher überprüfte 14 Workflows im Nixpkgs-Repository, die
pull_request_target verwenden
Schwachstelle in editorconfig-checker
- Der erste gefundene anfällige Workflow diente der Prüfung von editorconfig-Regeln
- Nach der Berechnung der Liste geänderter Dateien wurde diese per
xargs an editorconfig-checker übergeben
- Wenn man die Sicherheitswarnungen zum
xargs-Befehl ignoriert, entsteht eine Schwachstelle, über die sich bösartig gestaltete Dateinamen (z. B. --help) einschleusen lassen
- Dadurch lässt sich editorconfig-checker beliebig manipulieren oder möglicherweise zusätzliche Befehle ausführen (eine genauere Analyse wäre noch nötig)
Schwachstelle in codeowners-validator: lokale Dateien einbinden
- Die zweite und schwerwiegendere Schwachstelle wurde im Workflow zur Validierung der CODEOWNERS-Datei entdeckt
- Dieser Prozess checkt den PR-Code aus und prüft die Datei anschließend mit codeowners-validator
- Ein PR-Einreicher konnte die OWNERS-Datei durch einen symbolischen Link ersetzen und so auf beliebige Dateien im Runner verweisen (z. B. Action-Credentials)
- Infolgedessen wurde beim Validieren der Inhalt dieser Datei in die Logs ausgegeben, wodurch ein GitHub-Token mit Lese-/Schreibrechten offengelegt wurde
- Mit diesem Token war anschließend ein direkter Push in das Nixpkgs-Repository möglich
Maßnahmen und Lehren
- Nach der Meldung der Schwachstellen reagierte der Nixpkgs-Maintainer infinisil sofort
- Vorübergehende Deaktivierung anfälliger Workflows
- Korrektur und Trennung der Stellen, an denen nicht vertrauenswürdige Daten mit Berechtigungen verknüpft waren
- Nach den Security-Fixes Umbenennung der Workflows, um Probleme beim Branch-Targeting abzumildern
- Die wichtigsten Lehren
- Nicht vertrauenswürdige Daten dürfen niemals oder nur mit äußerster Vorsicht mit Secrets und sensiblen Abläufen kombiniert werden
- Das Prinzip von Least Privilege muss eingehalten werden
- Die offiziellen GitHub-Leitfäden zu Berechtigungen in GitHub Actions sollten unbedingt bekannt sein
- Bei ähnlichen Schwachstellen können Administratoren einer Organisation Actions zentral per Richtlinie deaktivieren (eine Anleitung zur Konfiguration wird erwähnt)
Fazit
- Der Forscher entdeckte innerhalb eines Tages eine Schwachstelle, die das gesamte Nix-Ökosystem gefährden konnte, meldete sie und wirkte an der Behebung mit
- Der Fall zeigt, dass beim Einsatz von GitHub Actions und insbesondere von
pull_request_target besondere Vorsicht geboten ist
- Er dankt KITCTFs Intrigus für die Unterstützung bei der Untersuchung und infinisil für die schnelle Reaktion
- Interessierte Leser werden auf den Vortragsmitschnitt und weiteres Material verwiesen
- Insgesamt unterstreicht der Beitrag die Bedeutung von GitHub-Actions-Sicherheit und praktische Sicherheitslehren
1 Kommentare
Hacker-News-Kommentare
Ich halte
pull_request_targetfür grundsätzlich sicherheitsanfällig und finde, GitHub sollte diese Funktion komplett abschaffen. Üblicherweise heißt es, man könnepull_request_targetsicher verwenden, solange man keinen vom Branch kontrollierten Code während des Jobs ausführt, aber in der Praxis ist die Angriffsfläche durch Dinge wie Argument-Injection oder Local File Inclusion viel größer. Derzeit sind die legitimen Anwendungsfälle im Wesentlichen automatisches Labeln oder automatisches Kommentieren bei PRs von Dritten. Für solche Aufgaben sollte man meiner Meinung nach nicht standardmäßig Schreibrechte auf das Repository vergeben müssen. GitHub sollte dafür ein Token ausstellen können, das genau auf diese Aufgaben beschränkt ist. Deshalb markiere ich in zizmor jede Verwendung gefährlicher Trigger wiepull_request_target; siehe zizmor dangerous triggerspull_request-Workflow wird nicht ausgelöst. Dann istpull_request_targetpraktisch die einzige Option. GitHub sollte stattdessen lieber eine Einstellung schaffen, mit der Workflows auch für PRs mit nicht sauberem Merge laufen können, standardmäßig deaktiviert und nur für Dinge wie Linter gedacht. Bis dahin ist es wirklich schade, dass man wegen dieser Einschränkung oft nurpull_request_targetverwenden kann. Zur Info: Wenn man solche externen Tools nutzt, zerstört ein manueller Merge auf GitHub den gesamten Flow, also auf keinen Fall manuell mergenpull_request_targetaus zwei Gründen. Erstens läuft der Workflow immer gegenmain, sodass sich ungeprüfter Testcode blockieren lässt. Zweitens wird in der Sub-Claim des JWT innerhalb des Workflows entscheidendjob_workflow_refbereitgestellt, was in OIDC-basierten Systemen eine feingranulare Zugriffskontrolle ermöglichtpull_request_targetim Basis-Kontext des PR, wodurch verhindert werden soll, dass bösartiger Code das Repo oder Secrets stiehlt. Wenn man allerdings weiß, wie leicht sich in der Praxis Secrets exfiltrieren lassen, wirkt das eher absurdHätte das Nix-Team gemäß dem von mir vorgeschlagenen RFC unabhängig von signierten Commits/Reviews signierte reproduzierbare Builds eingeführt, dann wären solche Last-Mile-Supply-Chain-Angriffe unmöglich gewesen. Letztlich will NixPkgs, dass jeder es leicht bearbeiten kann, und hat Angst, dass sicherheitsorientierte Maßnahmen Freiwillige vergraulen, weil der Fokus auf einer Hobby-Distribution liegt. Das ist in Ordnung, aber wenn man diesen Charakter den Leuten klar kommunizieren und schützen will, was schützenswert ist, dann sollte man aufhören, Nix in sicherheitskritischen Umgebungen einzusetzen oder zu empfehlen. Ein Betriebssystem, das etwas schützen soll, muss für jede Änderung strenge Zwei-Parteien-Hardware-Signaturen verlangen und darf das Vertrauen nicht einem einzelnen Rechner oder einer einzelnen Person überlassen. Deshalb habe ich Stagex gebaut Stagex-Link Codeberg-Link
Ich habe traditionell Computersysteme entworfen, und trotzdem bin ich heute noch sehr irritiert darüber, dass moderne Workflows weiterhin Bearer-Tokens vertrauen und sie Programmen ausstellen, denen man vertraut, sogar wenn die Tokens nur kurzlebig sind. Wenn das GitHub-Actions-Framework stattdessen nur privilegierte Unix-Sockets oder Zugriff auf
ssh-agentbereitstellen würde, wären solche Schwachstellen viel schwerer auszunutzenCI/CD-Aktionen für Pull-/Merge-Requests sind ein echter Albtraum. Wenn Entwickler Test- oder Validierungsschritte schreiben, denken sie meist in Kategorien wie „Mein Code läuft im Kontext meines GitHub-/GitLab-Kontos“. Das stimmt für eigene Commits oder die von Teammitgliedern, aber bei PRs führt die CI/CD-Pipeline nicht vertrauenswürdigen Code aus. Diesen Unterschied immer präzise im Kopf zu behalten ist schwer; bei simplen Tests oder Lintern geht es noch, aber sobald Aufgaben mehr Rechte brauchen, weil sie mit Infrastruktur interagieren, wird es schnell gefährlich
pull_requestundpull_request_target). Der eine (z. B.pull_request) ist fast immer sicher, solange man ihn nicht absichtlich falsch benutzt, und der andere (z. B.pull_request_target) lässt sich fast nie sicher verwenden. Noch schlimmer ist, dass GitHub gewöhnliche Aufgaben wie PRs labeln oder automatische Kommentare hinterlassen ausschließlich mit dem gefährlichen Trigger (pull_request_target) erlaubt, sodass alle zu einer instabilen Wahl gedrängt werden. Die von GitHub Actions angebotene Funktionalität ist strukturell fehleranfälligMit der Zeit mache ich mir immer mehr Sorgen über Supply-Chain-Angriffe. Es geht nicht nur um Dinge wie „Verliere ich dadurch meinen Job?“ oder „Entstehen neue Angriffsvektoren in NixOS, CI/CD, Node usw.?“, sondern um eine eher philosophische Sorge. Je mehr man davon abhängt, desto mehr Probleme muss man zwangsläufig mittragen. Sogar Dinge, die man bequem nutzen will, sind inzwischen schon viel zu verwickelt — VSCode, Emacs, Nix, Vim, Firefox, JS, Node und all diese Plugins und Abhängigkeitspakete hängen ineinander. Daher komme ich peinlicherweise immer näher an den seltsamen Schluss, dass ich nur mit Papier und minimaler, wirklich einfacher Technik überhaupt noch ein Gefühl von Kontrolle oder Sicherheit haben kann. Ich weiß, dass das irrational ist, aber diese Komplexität widert mich zunehmend an. Inzwischen spüre ich sogar eine Grenze meiner Komplexitätstoleranz
In der Warnung auf der Manpage von xargs steht „xargs kann nicht sicher verwendet werden“. Dieses Sicherheitsproblem unterscheidet sich aber von dem hier vorliegenden Fall. In diesem Fall hätte ein einfaches
--am Ende gereicht, um es zu vermeidenDer Satz „xargs kann nicht sicher verwendet werden“ wird oft missverstanden. Wenn man zum Beispiel
cat "$HOME/changed_files" | xargs -r editorconfig-checker --ausführt, kann das konkrete Problem hier vermieden werden<div>{escapeHtml(value)}</div>dranhängen. Wenn man überall selbst sichere Verwendungsmuster anwenden muss, ist der Ansatz grundsätzlich falsch--, und die meisten Verwendungen von xargs sind anfällig für Argument-Injection. Im Grunde ist das nicht anders als die Tatsache, dass jede Befehlsausführung inhärent riskant ist. Das ist nicht die Schuld von xargs selbst, sondern ein Problem der Realität, in der Werkzeuge in verschiedenen Berechtigungskontexten wiederholt verwendet werdenDer Artikel hat eine viel schwerwiegendere Lücke mit deutlich breiterer Wirkung: In PR-Code kann man die Datei OWNERS in einen Symlink verwandeln und so beliebige Dateien wie die GitHub-Actions-Credential-Datei offenlegen. Da Git das Committen von Softlinks unterstützt, entsteht dieses Risiko in fast jedem Workflow
pull_request_targetauf das Ziel-Repo, also das Repository, in das gemergt werden soll. Beipull_requestbezieht es sich auf die Credentials des vom Angreifer kontrollierten Source-ReposDie einzige „gute“ Nachricht ist, dass OpenBSD und NetBSD für ihr Paketmanagement immer noch CVS verwenden und daher von dieser Schwachstelle nicht betroffen sind. Bei FreeBSD bin ich mir nicht sicher. Sicherheit ist in gewisser Weise Sicherheit durch Verdeckung. Allerdings scheinen auch diese Projekte über eine Migration zu Git nachzudenken, und OpenBSD wird wohl eher in Richtung got(1) gehen