Skip to content

Dieses Werkzeug ist weder mit GitHub, Inc. oder der Microsoft Corporation verbunden noch von ihnen unterstützt oder gesponsert. GitHub und GitHub Actions sind Marken von GitHub, Inc. Andere Namen sind Marken ihrer jeweiligen Inhaber.

GitHub-Actions-Secrets geleakt: Exfiltration untersuchen

Wie GitHub-Actions-Secrets trotz ***-Maskierung leaken: manipulierte Workflows, neue Branches, kodierte Ausgaben, fremde Actions – und welche Beweise zählen.

Veröffentlicht am 7 Min. Lesezeit

Kurz gesagt. Ein Workflow kann jedes Secret in seinem Geltungsbereich lesen, und die Maskierung verbirgt nur den exakten Wert. echo "$KEY" | base64 | base64 gibt ihn im Klartext aus. Angreifer kommen dorthin, indem sie einen veränderten Workflow auf einen neuen Branch pushen, pull_request_target missbrauchen oder eine Action eines Drittanbieters kompromittieren (tj-actions/changed-files, 2025). Die Beweise: workflows.created_workflow_run auf einem nie gesehenen Branch im Audit-Log, dazu das Protokollarchiv des Laufs, in dem sowohl das Skript des Schritts als auch die kodierte Zeichenkette sichtbar sind. Laden Sie die Archive herunter, bevor jemand sie löscht, und rotieren Sie dann jedes Secret, das der Workflow lesen konnte.

In GitHub Actions wird aus Quellcode Cloud-Zugriff. Die Workflows, die in die Produktion deployen, halten AWS-Schlüssel, Registry-Tokens und Signaturschlüssel als Secrets. Für einen Angreifer mit einem Token mit workflow-Scope oder einem Brückenkopf in einer Action, von der Sie abhängen, ist die Exfiltration dieser Secrets oft das eigentliche Ziel.

Wie Secrets zum Angreifer gelangen

WegWas passiertWo es sichtbar wird
Workflow auf einen neuen Branch gepushtDer Angreifer pusht eine veränderte .github/workflows/*.yml auf einen frischen Branch. Ein push-Trigger führt sie mit den Secrets des Repositorys ausgit.push + workflows.created_workflow_run mit neuem head_branch
Missbrauch von pull_request_target / workflow_runNicht vertrauenswürdiger PR-Code läuft in einem privilegierten KontextLäufe, ausgelöst durch PRs aus Forks, siehe GitHub Security Lab zu „pwn requests“
Kompromittierte Action eines DrittanbietersEin von Ihnen genutzter Tag zeigt jetzt auf bösartigen CodeJeder Lauf, der den Tag verwendet hat, mit derselben seltsamen Ausgabe
Selbst gehosteter RunnerSecrets und Tokens werden von einem persistenten Host gelesenSiehe Sicherheit selbst gehosteter Runner
Schutz der Umgebung entferntErforderliche Reviewer oder Branch-Richtlinien gelöscht, sodass Umgebungs-Secrets erreichbar werdenenvironment.remove_protection_rule, environment.delete

ATT&CK hat für diese Familie inzwischen eine eigene Technik, T1677 Poisoned Pipeline Execution. Der Glossareintrag zu Poisoned Pipeline Execution erklärt die direkte und die indirekte Variante.

Ein öffentliches Beispiel

Im März 2025 veröffentlichte die CISA eine Warnung zur Kompromittierung von tj-actions/changed-files (CVE-2025-30066) und des damit zusammenhängenden reviewdog/action-setup (CVE-2025-30154). Versions-Tags der Action waren so umgebogen worden, dass sie auf bösartigen Code zeigten, der CI-Secrets in die Workflow-Protokolle schrieb. In öffentlichen Repositories kann jeder diese Protokolle lesen. Jede Organisation, die einen verschobenen Tag nutzte, musste ihre Laufprotokolle für den betroffenen Zeitraum prüfen. Die Erkennungsfrage lautete: Welche unserer Läufe haben in diesem Schritt eine kodierte Zeichenkette ausgegeben?

Warum Maskierung keine Schutzmaßnahme ist

GitHub ersetzt registrierte Secret-Werte in Protokollen durch ***. Die Referenz zur sicheren Nutzung ist eindeutig: Die Schwärzung ist nicht garantiert, und ein umgewandeltes Secret (Base64, URL-kodiert) muss separat registriert werden, damit es maskiert wird. Deshalb gibt

echo "$AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY" | base64 -w0 | base64 -w0

eine lange Zeichenkette aus, zu der keine Maske passt. Zweimal dekodiert, haben Sie das Schlüsselpaar. Varianten sind xxd, rev, od, das Aufteilen des Werts, toJSON(secrets) oder das direkte Versenden des Werts mit curl -d an einen Dienst zum Mitschneiden von Requests. Der Glossareintrag zur Secret-Maskierung fasst zusammen, was die Maskierung abdeckt.

Die Beweise, nach Aussagekraft geordnet

1. Das Protokollarchiv des Laufs

Repository → Actions → Lauf → ⋯ → Download log archive. Das ZIP enthält ein zusammengefasstes Protokoll pro Job und eine Datei pro Schritt. Darin stehen das Skript des Schritts (der Block ##[group]Run … gibt die Befehle wieder) und seine Ausgabe. Nur hier sehen Sie, was der Workflow mit einem Secret getan hat. Protokolle werden standardmäßig 90 Tage aufbewahrt, und jeder mit Schreibzugriff kann sie löschen. Laden Sie sie zuerst herunter.

Der Analyzer liest diese ZIPs direkt. Zwei Regeln gelten für sie:

  • actions-secret-exfil (kritisch): eine Skriptzeile, die ein Secret, Token, einen Schlüssel, env oder eine $-Variable erwähnt und sie durch einen Encoder leitet (base64, xxd, rev, od), die Umgebung ausgibt (printenv, env |, toJSON(secrets)) oder Daten an einen externen Endpunkt sendet (curl -d, wget --post, /dev/tcp/, gängige Dienste zum Mitschneiden von Requests und für Tunnel). Reines Dekodieren (base64 -d) ohne Netzwerkaufruf ist ausgenommen, um Fehlalarme zu begrenzen. Nennt die Zeile Zugangsdaten für AWS, Google Cloud oder Azure, zeigt der Befund den nächsten Schritt in der Cloud an.
  • actions-encoded-output (mittel): eine Ausgabezeile mit einer durchgehenden Base64- oder Hex-Zeichenkette von 60 oder mehr Zeichen. Genau so sieht ein doppelt kodierter Schlüssel aus.

Jede Protokollzeile kommt in einem Archiv zweimal vor (in der zusammengefassten Datei und in der Datei pro Schritt). Der Analyzer dedupliziert, sodass ein bösartiger Schritt genau einen Befund ergibt.

2. Die Workflow-Lauf-Ereignisse im Audit-Log

workflows.created_workflow_run und workflows.completed_workflow_run enthalten repo, name (den Workflow), event (push, pull_request, workflow_dispatch …), head_branch, head_sha, workflow_run_id und den Akteur. Die Regel workflow-new-branch (niedrig) markiert einen Workflow, der auf einem Branch läuft, auf dem er noch nie gelaufen ist, und zwar für die Trigger push und workflow_dispatch. Für sich allein ist sie laut, da jeder Feature-Branch sie auslöst. Bedeutsam wird sie, wenn der Akteur oder das Token weitere Befunde hat oder wenn der Branch-Name nach Wartung klingt (ci/cache-fix, dependabot-fix) und der Branch danach gelöscht wurde.

3. Git-Events

Ein git.push kurz vor dem Lauf, vom selben Token und derselben IP-Adresse, verknüpft die Workflow-Änderung mit den Zugangsdaten. Ohne Git-Events bleibt Ihnen head_sha, den Sie im Repository nachschlagen können, sofern der Branch noch existiert.

4. Änderungen an Secret-Metadaten

repo.create_actions_secret, org.update_actions_secret und environment.create_actions_secret (Regel actions-secret-created, niedrig) sind routinemäßige CI-Arbeit. Relevant werden sie, wenn der Akteur verdächtig ist. Ein Angreifer kann ein Deployment-Secret ersetzen, um Artefakte umzuleiten. Beachten Sie, was das Audit-Log nicht protokolliert: Dass ein Workflow ein Secret liest, ist kein Ereignis.

Umfang bestimmen und Maßnahmen

  1. Listen Sie jeden Lauf des veränderten Workflows und jedes Workflows auf den Branches des Angreifers auf, mit den Werten von workflow_run_id aus dem Audit-Log.
  2. Rotieren Sie jedes Secret, das der Workflow lesen konnte: Secrets des Repositorys, der Organisation (sofern das Repository Zugriff hat) und der Umgebungen. Auch diejenigen, die nicht ausgegeben wurden. Ein Skript, das env ausführt, verschickt alles.
  3. Löschen Sie die Protokolle der Läufe, die Secrets ausgegeben haben – nachdem Sie sie für die Fallakte archiviert haben –, damit die kodierten Zeichenketten in der Oberfläche nicht mehr lesbar sind.
  4. Entfernen Sie die Branches des Angreifers und prüfen Sie .github/workflows auf allen verbliebenen Branches.
  5. Verfolgen Sie die Schlüssel in AWS, Google Cloud oder Azure: siehe geleakte Cloud-Schlüssel.

Härtung, die die Angriffsfläche tatsächlich verkleinert

  • Pinnen Sie Actions von Drittanbietern auf einen vollständigen Commit-SHA. GitHub nennt das „die einzige Möglichkeit, eine Action als unveränderliches Release zu verwenden“.
  • Setzen Sie die Standardberechtigung des GITHUB_TOKEN auf Nur-Lesen und vergeben Sie Schreibrechte pro Job.
  • Schützen Sie Deployment-Secrets mit Umgebungen, die Reviewer verlangen und Branches einschränken. Der Analyzer markiert, wenn dieser Schutz entfernt wird (environment-protection-removed, hoch).
  • Ersetzen Sie gespeicherte Cloud-Schlüssel durch OIDC-Federation. Ein kurzlebiges Token, das auf ein Repository und einen Branch beschränkt ist, ist für einen Angreifer weit weniger wert.
  • Verlangen Sie ein CODEOWNERS-Review für .github/workflows/ und schützen Sie das Verzeichnis mit einem Repository-Ruleset.
  • Nutzen Sie die Prüfungen von OpenSSF Scorecard (Token-Berechtigungen, gepinnte Abhängigkeiten, gefährliche Workflows), um riskante Muster zu finden.

FAQ

Können GitHub-Actions-Secrets leaken, obwohl sie als *** maskiert werden?

Ja. Die Maskierung ersetzt in Protokollen nur den exakten Wert des Secrets. Ein Skript, das ihn Base64-kodiert, umkehrt oder aufteilt, gibt eine Zeichenkette aus, die nicht mehr übereinstimmt – sie erscheint also im Klartext und lässt sich dekodieren. GitHubs eigene Dokumentation warnt, dass die Schwärzung bei umgewandelten Secrets nicht garantiert ist.

Zeigt das Audit-Log, wann ein Workflow ein Secret liest?

Nein. Das Audit-Log protokolliert, wenn Secrets angelegt, geändert oder entfernt werden und wenn Workflow-Läufe erstellt und abgeschlossen werden. Das Lesen eines Secrets während eines Laufs ist kein Audit-Ereignis; was ein Schritt damit getan hat, belegt daher nur das Laufprotokoll.

Verwandte Artikel

Verwandte Artikel

Fremde oder kompromittierte Self-hosted Runner in GitHub: relevante Audit-Log-Ereignisse, Spuren in _diag auf dem Host, Umfang bestimmen, Runner neu aufbauen.
Ein fiktiver Supply-Chain-Angriff auf GitHub, durchgehend untersucht: gestohlenes PAT, 38 Repos geklont, AWS-Keys per Workflow geleakt, Branch-Schutz entfernt.
AWS-, Google-Cloud- oder Azure-Keys aus GitHub Actions oder einem Repo geleakt: Key sperren, Nutzung in Cloud-Audit-Logs verfolgen, Keys durch OIDC ersetzen.

Dieses Werkzeug ist weder mit GitHub, Inc. oder der Microsoft Corporation verbunden noch von ihnen unterstützt oder gesponsert. GitHub und GitHub Actions sind Marken von GitHub, Inc. Andere Namen sind Marken ihrer jeweiligen Inhaber.