GitHub Actions Sicherheitspraxis: 3 zentrale Schutzmaßnahmen aus dem tj-actions-Vorfall
Im März 2025 hat ein GitHub Advisory mein bisheriges Verständnis verschoben. tj-actions/changed-files – eine Action, die ich drei Jahre lang genutzt habe – wurde als CVE-2025-30066 gemeldet. Über 23.000 Repositories standen über Nacht im Risiko von Secrets-Leaks.
Noch beunruhigender war die Angriffsmethode. Angreifer stahlen zuerst ein PAT eines Projekts und manipulierten dann die Versions-Tags von tj-actions, sodass zuvor sicherer Code auf bösartige Skripte zeigte. AWS-Schlüssel, Datenbankpasswörter, API-Tokens – alles floss lautlos in öffentliche Logs.
Ich war ziemlich fertig. Meine eigene CI/CD-Pipeline war plötzlich die Sprungbrett für Angreifer. Ich durchsuchte alle Repositories: Action-Versionen, GITHUB_TOKEN-Berechtigungen, Audit-Log-Einstellungen. Nach einem ganzen Tag stellte sich heraus, wie viele Details ich jahrelang ignoriert hatte.
Dieser Artikel ist die Schutz-Checkliste aus diesem Schreckmoment. Wir besprechen Supply-Chain-Angriffe, korrektes Secrets-Management, GITHUB_TOKEN-Berechtigungskontrolle und die Neuerungen der GitHub-Sicherheits-Roadmap 2026, auf die Sie sich schon jetzt vorbereiten können.
Wichtig: Das alles können Sie jetzt konfigurieren – Sie müssen auf keine neuen Features warten.
CI/CD-Supply-Chain-Angriffe am Beispiel tj-actions
Wie der Angriff ablief
Zuerst zu tj-actions/changed-files. Die Action ist auf GitHub sehr verbreitet – sie erkennt, welche Dateien in einem PR geändert wurden; viele CI/CD-Pipelines nutzen sie für inkrementelle Deployments. Mehrere meiner Projekte hingen davon ab.
Die Angriffskette sah ungefähr so aus:
Angreifer stahlen zuerst ein PAT aus dem Projekt reviewdog/action-setup. Dieses PAT hatte Schreibzugriff auf Repositories. Damit manipulierten sie Versions-Tags im tj-actions-Repository – das Tag v45, das auf sicheren Code zeigte, wurde still auf einen Commit mit bösartiger Logik umgebogen.
Projekte, die noch uses: tj-actions/changed-files@v45 nutzten, zogen unwissentlich bösartigen Code. Das Skript druckte alle Secrets aus der CI/CD-Umgebung in die Logs. Logs sind öffentlich – Secrets waren offen.
Laut GitHub Advisory waren über 23.000 Repositories betroffen. Das Coinbase-Security-Team berichtete später, dass über 70.000 Kundendatensätze tangiert wurden.
Mein Fehler: Tag-Referenz vs. SHA-Fixierung
Bei der Prüfung meiner Repositories fiel auf: Überall Tag-Referenzen:
# Falsch: veränderbares Tag
- name: Check changed files
uses: tj-actions/changed-files@v45
Tags sind lebendig. Maintainer – oder Angreifer mit Schreibzugriff – können ein Tag jederzeit auf einen neuen Commit zeigen. Sie glauben, v45 zu referenzieren; tatsächlich läuft möglicherweise manipulierter Code.
Richtig ist die Fixierung mit vollem SHA:
# Richtig: voller SHA
- name: Check changed files
uses: tj-actions/changed-files@6cbf527e7a7b6d61c4e7f25e5ce5f7b7c8f3c72a
SHA ist fest. Solange Sie die Referenz nicht aktiv aktualisieren, läuft immer derselbe Code.
Beim Umbau dachte ich: Das ist doch Basis-Sicherheitswissen – warum habe ich das jahrelang ignoriert?
Vertrauenskosten bei Third-Party-Actions
Der tj-actions-Vorfall zeigt ein weiteres Problem: Wir vertrauen Third-Party-Actions zu leichtfertig.
Eine Action mit vielen Stars und vielen Nutzern landet direkt in der Produktions-CI/CD – aber wie ist die Sicherheitskultur des Maintainers? Wird sein PAT gestohlen?
In der GitHub-Sicherheits-Roadmap 2026 gibt es einen Ansatz: Workflow-Level-Dependency-Locking. Analog zu package-lock.json werden alle Action-SHAs in einer Lock-Datei festgehalten. Die Funktion ist noch nicht live – aber Sie können es jetzt manuell tun: jede Action-Referenz auf SHA umstellen und regelmäßig prüfen.
Ein weiterer Rat: weniger Third-Party-Actions. Was offizielle Actions lösen, sollte nicht über Drittanbieter laufen. Dateiänderungen erkennen lässt sich oft mit actions/checkout plus Shell-Skript – ohne tj-actions.
Secrets-Management: 3 Ebenen und fortgeschrittene Praxis
Drei Ebenen der GitHub-Secrets-Speicherung
GitHub-Secrets gibt es auf drei Ebenen: Organisation, Repository und Environment.
Organisations-Secrets können über mehrere Repos geteilt werden – geeignet für AWS-Schlüssel und Cloud-Tokens. Repository-Secrets gelten nur im aktuellen Repo – für projektspezifische DB-Passwörter. Environment-Secrets sind feiner granuliert und lassen sich mit Schutzregeln kombinieren – z. B. erst nach PR-Freigabe Zugriff auf Produktions-Secrets.
Zur Speicherung: GitHub verschlüsselt mit libsodium sealed box. Nach dem Schreiben sind Secrets nicht mehr lesbar – nur zur Laufzeit über den secrets-Kontext:
steps:
- name: Deploy to AWS
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
Ein häufiger Fehler: Secrets direkt in Shell-Befehle interpolieren:
# Gefährlich: Secrets können in Logs landen
- name: Configure AWS
run: aws configure set aws_access_key_id ${{ secrets.AWS_ACCESS_KEY_ID }}
Bei Sonderzeichen im Secret-Wert oder bei Fehlern kann der Befehl Secrets in Logs ausgeben. Sicherer: Übergabe über Umgebungsvariablen:
# Sicher: über Umgebungsvariable
- name: Configure AWS
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
run: aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID"
Dynamisches Masking: ::add-mask::
Manche sensiblen Daten sind keine vorab gespeicherten Secrets, sondern zur Laufzeit erzeugt – z. B. ein temporäres Token aus einem Skript. Dann hilft ::add-mask:::
- name: Generate temporary token
run: |
token=$(generate-token.sh)
echo "::add-mask::$token"
echo "TOKEN=$token" >> $GITHUB_ENV
Maskierte Werte erscheinen in Logs als ***. Wichtig: Maskierung vor der Ausgabe – sonst ist der Wert schon sichtbar.
Fortgeschritten: HashiCorp Vault OIDC-Integration
Bei hohen Sicherheitsanforderungen reichen eingebaute GitHub-Secrets oft nicht. Langzeit-Credentials auf GitHub bedeuten: Bei Repo-Kompromittierung sind alle Secrets weg.
Besser: HashiCorp Vault mit OIDC (OpenID Connect) für credential-freien Zugriff. GitHub Actions beweist bei Vault die Identität; Vault stellt ein kurzlebiges Token aus – keine Langzeit-Credentials mehr auf GitHub.
Schritt 1: OIDC-Rolle in Vault konfigurieren
Vault muss GitHub als OIDC-Provider vertrauen. Eine Rolle definiert, welche Repos welche Secrets erhalten:
resource "vault_jwt_auth_backend_role" "github_actions" {
backend = "jwt"
role_name = "github-actions-role"
bound_audiences = ["https://github.com/your-org"]
user_claim = "repository"
role_type = "jwt"
token_policies = ["ci-policy"]
token_ttl = "1h"
}
Schritt 2: vault-action in GitHub Actions nutzen
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Import Secrets from Vault
uses: hashicorp/vault-action@v2.4.0
id: vault
with:
url: https://vault.example.com:8200
role: github-actions-role
method: jwt
secrets: |
secret/data/ci/aws accessKey | AWS_ACCESS_KEY_ID ;
secret/data/ci/aws secretKey | AWS_SECRET_ACCESS_KEY
- name: Deploy with AWS credentials
run: |
echo "Accessing AWS with Vault-provided credentials"
aws s3 ls
Hier authentifiziert sich vault-action automatisch mit dem OIDC-Token von GitHub. Vault liefert Secrets in Umgebungsvariablen. Nach 1 Stunde läuft das Token ab – beim nächsten Lauf wird neu geholt.
Azure Key Vault unterstützt ähnliche OIDC-Integration – mit azure/login und Azure Key Vault Secrets.
GITHUB_TOKEN-Berechtigungskontrolle in der Praxis
Was ist GITHUB_TOKEN?
Jeder GitHub-Actions-Workflow erhält automatisch ein GITHUB_TOKEN – ein temporäres OAuth-Token für Operationen am aktuellen Repository: Releases, Push, PR-Kommentare.
Problem: GITHUB_TOKEN hat standardmäßig zu viele Rechte.
In älteren GitHub-Actions-Versionen war GITHUB_TOKEN nahezu vollständig les-/schreibbar. Workflows konnten Inhalte ändern, Branches anlegen, pushen. Wird ein Workflow ausgenutzt (z. B. bösartiges Skript via PR), wird GITHUB_TOKEN zur Waffe.
Vollständige permissions-Konfiguration
Seit April 2021 gibt es den permissions-Schlüssel zur präzisen Steuerung von GITHUB_TOKEN.
Grundsyntax:
permissions:
actions: read|write|none # Actions verwalten
contents: read|write|none # Repository-Inhalt
issues: read|write|none # Issues
packages: read|write|none # GitHub Packages
pull-requests: read|write|none # Pull Requests
security-events: read|write|none # Security-Events
deployments: read|write|none # Deployment-Status
statuses: read|write|none # Commit-Status
Wichtig: Sobald permissions gesetzt ist, werden nicht angegebene Berechtigungen automatisch none – die Least-Privilege-Grenze.
Workflow- vs. Job-Ebene
permissions kann auf Workflow-Ebene (global) oder Job-Ebene (lokal) stehen.
Workflow-Ebene gilt für alle Jobs:
name: CI Pipeline
permissions:
contents: read # Alle Jobs: Repository nur lesen
issues: write # Alle Jobs: Issues schreiben
jobs:
lint:
runs-on: ubuntu-latest
steps:
- run: echo "Lint with read-only access"
test:
runs-on: ubuntu-latest
steps:
- run: echo "Test with read-only access"
Job-Ebene kann Workflow-Einstellungen überschreiben:
name: Release Pipeline
permissions:
contents: read # Standard: nur lesen
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read # Lesezugriff
steps:
- run: echo "Build needs read only"
release:
runs-on: ubuntu-latest
permissions:
contents: write # Schreiben für Release
packages: write # Packages veröffentlichen
steps:
- name: Create Release
uses: actions/create-release@v1
Praxisbeispiel: In einem Release-Workflow braucht der build-Job nur Lesezugriff; release erstellt Release und pusht Docker-Images. Durch Job-Level-Isolation kann ein kompromittierter build-Job nicht in Repository-Inhalte schreiben.
Repository-Berechtigungsmodus
Neben Workflow-Konfiguration gibt es zwei Modi in den Repository-Einstellungen:
- Permissive (weit): GITHUB_TOKEN standardmäßig les-/schreibbar, wenn der Workflow kein
permissionssetzt. - Restricted (eingeschränkt): GITHUB_TOKEN standardmäßig nur Lesezugriff auf contents und packages; Schreiben erfordert explizite Deklaration.
Empfehlung: alle Repositories auf Restricted. Unter Repository Settings > Actions > General bei „Workflow permissions“ „Read repository contents and packages permissions“ wählen.
So bleibt die Sicherheitsgrenze auch dann gesetzt, wenn ein Workflow permissions vergisst.
Audit-Logs und Compliance-Prüfung
Workflow-Lauf-Ereignisse in Audit-Logs
Seit Februar 2021 sind Actions-Workflow-Läufe in Organisations-Audit-Logs erfasst. Sie können nachverfolgen, wer welchen Workflow ausgelöst hat, mit welchen Berechtigungen und welchen Secrets.
Einstieg: Organisations-Settings > Security > Audit log.
Wichtige Felder:
action: Ereignistyp, z. B.workflow_run.create,workflow_run.completeactor: Auslöser – Benutzer, App odergithub-actions[bot]repo: Repository-Pfadtoken_scopes: genutzte Token-Berechtigungenrequest_id: Request-ID für Log-Korrelation
Praxis: Bei anomalen Workflow-Läufen Audit-Logs zur Ursachenanalyse – z. B. bei ungewöhnlichem Secrets-Zugriff workflow_run-Ereignisse und Auslöser prüfen.
Enterprise Audit API
Mit GitHub Enterprise können Sie alle Vorgänge über die Audit Log API abfragen:
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.github.com/enterprises/YOUR_ENTERPRISE/audit-log?phrase=workflow_run"
Die JSON-Antwort enthält detaillierte Ereignisse – Export in SIEM-Systeme (Splunk, Datadog) für kontinuierliches Monitoring.
Compliance kurz erklärt
Für SOC 2 oder ISO 27001 ist CI/CD-Sicherheit Pflicht. Audit-Logs sind direkter Compliance-Nachweis – dass Sie CI/CD-Aktivitäten verfolgen, Anomalien erkennen und reagieren können.
Empfohlene Konfiguration: Audit-Logs in externe Systeme exportieren und Alarme für Schlüsselereignisse setzen, z. B.:
- plötzlicher Anstieg der Workflow-Fehlerrate
- anomaler Secrets-Zugriff (viele Reads in kurzer Zeit)
- Workflows von unbekannten IPs
Ausblick: GitHub-Sicherheits-Roadmap 2026
Im März 2026 veröffentlichte GitHub die Actions-Sicherheits-Roadmap mit sechs größeren Neuerungen. Einige sind live, andere in Entwicklung.
Workflow-Level-Dependency-Locking
Offizielle Antwort auf Angriffe wie tj-actions. Analog zu package-lock.json werden Action-Referenzen auf SHA gesperrt. Im Workflow steht weiter uses: tj-actions/changed-files@v45, die Lock-Datei hält den SHA fest. Bei Action-Updates ändert sich die Lock-Datei nicht automatisch – Sie prüfen und aktualisieren aktiv.
Noch nicht live – SHA-Fixierung können Sie heute schon manuell umsetzen.
Layer-7-native Egress-Firewall
Steuerung des externen Netzwerkzugriffs in CI/CD – z. B. nur AWS-API, kein beliebiges Internet.
Heute: Self-hosted Runner plus eigene Netzwerkrichtlinien. Ab 2026 auch auf GitHub-Cloud-Runnern.
Scoped Secrets
Feinere Secrets-Scope-Kontrolle – z. B. Secret nur für bestimmten Branch oder Job. Aktuell: Repository- oder Environment-Ebene, oft zu grob.
Policy-gesteuerte Ausführungskontrolle
Vertrauensgrenzen, Freigaben und Attestierungs-Gates – z. B. PRs aus Forks erst nach manueller Freigabe; Workflows erst nach Security-Scan.
Ähnlich Environment-Schutzregeln, aber feiner und komplexer.
Actions Data Stream
Echtzeit-Sichtbarkeit von CI/CD-Aktivität – wie Audit-Logs, aber Push statt nachträglicher Abfrage. Anbindung an SIEM für Live-Monitoring.
OIDC benutzerdefinierte Attribut-Claims
Erweiterte Cloud-Identitätsprüfung. OIDC-Tokens können mehr benutzerdefinierte Attribute tragen – Repo-Labels, Branch-Infos. Vault oder AWS können darauf feinere Autorisierung stützen.
Fazit
Vom tj-actions-Vorfall bis heute – drei Kernlektionen:
Erstens: SHA-Fixierung. Keine Tag-Referenzen für Third-Party-Actions – voller SHA. Das haben über 23.000 Repositories teuer bezahlt.
Zweitens: Least Privilege. GITHUB_TOKEN ist standardmäßig zu mächtig – mit permissions einschränken und Repository auf Restricted setzen.
Drittens: Audit-Logs. Actions-Ereignisse sind erfasst – regelmäßig prüfen und in Monitoring exportieren.
Das können Sie jetzt umsetzen – ohne auf GitHub-2026-Features oder neue Tools zu warten. Repository öffnen, Action-Referenzen, Berechtigungen und Audit-Logs prüfen – in etwa 30 Minuten Basis-Schutz.
CI/CD-Sicherheit ist keine Hochtechnologie, sondern Detail-Disziplin. Jede SHA-Fixierung und jede entzogene Überberechtigung reduziert Risiko. tj-actions zeigt: Angreifer brauchen keine Genialität – nur Ihre Nachlässigkeit bei einem kleinen Detail.
GitHub Actions Sicherheits-Härtungs-Workflow
Von SHA-Fixierung bis Berechtigungskontrolle – drei Kernschritte zur CI/CD-Sicherheits-Härtung.
⏱️ Estimated time: 30 min
- 1
Step 1: Action-Referenzen per SHA fixieren
Alle Workflow-Dateien prüfen und `uses: action@tag` in `uses: action@full-sha` ändern, um Tag-Manipulation zu vermeiden. Tools wie `pinact` für die Massenumstellung bestehender Referenzen nutzen. - 2
Step 2: permissions-Schlüssel konfigurieren
Auf Workflow- oder Job-Ebene den permissions-Schlüssel hinzufügen und nur erforderliche Berechtigungen vergeben. Beispiel: `permissions: contents: read` für Lesezugriff, `permissions: contents: write` für Release-Erstellung. Repository als Fallback auf Restricted-Modus setzen. - 3
Step 3: Audit-Log-Monitoring aktivieren
Actions-Workflow-Lauf-Ereignisse unter Organisations-Settings > Security > Audit log einsehen. Alarme für Schlüsselereignisse konfigurieren: plötzlicher Anstieg der Workflow-Fehlerrate, anomaler Secrets-Zugriff, Workflows von unbekannten IPs. Logs in ein SIEM-System exportieren für kontinuierliches Monitoring.
FAQ
Warum SHA-Fixierung statt Tag-Referenz?
Wie steuere ich GITHUB_TOKEN-Berechtigungen?
Wie erkenne ich, ob ein Workflow kompromittiert wurde?
Welche Vorteile hat OIDC + Vault gegenüber eingebauten Secrets?
Darf ich Third-Party-Actions nutzen?
9 Min. Lesezeit · Veröffentlicht am: 16. Mai 2026 · Aktualisiert am: 9. Juli 2026
GitHub Actions Komplettleitfaden
Wenn du über die Suche hier gelandet bist, kommst du am schnellsten weiter, indem du zum vorherigen oder nächsten Beitrag dieser Serie springst.
Vorheriger
GitHub Actions Composite Action entwickeln: Praxisleitfaden von action.yml bis Marketplace
GitHub Actions Composite Action Schritt für Schritt: action.yml-Struktur, inputs/outputs, Secrets-Weitergabe, Versionsstrategie und Marketplace-Veröffentlichung – CI/CD-Komponenten sauber kapseln.
Teil 9 von 10
Nächster
Dies ist bisher der neueste Beitrag dieser Serie.
Ähnliche Beiträge
GitHub Actions Einstieg: YAML-Workflow-Grundlagen und Trigger-Konfiguration

GitHub Actions Einstieg: YAML-Workflow-Grundlagen und Trigger-Konfiguration
GitHub Actions CI-Pipeline in der Praxis: Build und Test automatisieren


Kommentare
Melde dich mit GitHub an, um einen Kommentar zu hinterlassen