Design wechseln

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/[email protected]
        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 permissions setzt.
  • 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.complete
  • actor: Auslöser – Benutzer, App oder github-actions[bot]
  • repo: Repository-Pfad
  • token_scopes: genutzte Token-Berechtigungen
  • request_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. 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. 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. 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?
Tags sind veränderbar – Maintainer oder Angreifer können ein Tag jederzeit auf einen neuen Commit zeigen lassen. SHA ist fest; solange Sie die Referenz nicht aktiv aktualisieren, läuft genau dieser Code. Der tj-actions-Vorfall belegt das Risiko der Tag-Manipulation.
Wie steuere ich GITHUB_TOKEN-Berechtigungen?
Mit dem `permissions`-Schlüssel die benötigten Berechtigungen explizit deklarieren. Sobald permissions gesetzt ist, werden nicht angegebene Berechtigungen automatisch auf none gesetzt. Empfehlung: Berechtigungsmodus unter Repository Settings > Actions > General auf Restricted setzen.
Wie erkenne ich, ob ein Workflow kompromittiert wurde?
In Organisations-Audit-Logs workflow_run-Ereignisse prüfen – auf anomalen Zugriff, unbekannte IPs oder häufige Fehler achten. Logs in ein SIEM-System exportieren und automatische Alarme konfigurieren.
Welche Vorteile hat OIDC + Vault gegenüber eingebauten Secrets?
GitHub-eigene Secrets sind Langzeit-Credentials – bei Kompromittierung des Repositories sind alle Secrets offen. OIDC + Vault ermöglicht credential-freien Zugriff: GitHub authentifiziert sich bei Vault und erhält ein kurzlebiges Token, das nach 1 Stunde abläuft – das Angriffsfenster schrumpft erheblich.
Darf ich Third-Party-Actions nutzen?
Ja, aber mit Vorsicht. Offizielle Actions bevorzugen, SHA-fixierte Referenzen verwenden und Abhängigkeiten regelmäßig prüfen. Die GitHub-Roadmap 2026 bringt Workflow-Level-Dependency-Locking für sichereres Third-Party-Action-Management.

9 Min. Lesezeit · Veröffentlicht am: 16. Mai 2026 · Aktualisiert am: 9. Juli 2026

Kommentare

Melde dich mit GitHub an, um einen Kommentar zu hinterlassen

Easton BlogEaston Blog