Jeder GitHub-Actions-Job bekommt ein automatisch erzeugtes GITHUB_TOKEN. Welche Rechte dieses Token am Ende tatsächlich trägt, ist keine einzelne Einstellung, sondern das Ergebnis einer Rechnung aus drei Eingaben: der Organisations- oder Repository-Vorgabe „Workflow permissions“, dem permissions:-Block im Workflow und, falls vorhanden, dem permissions:-Block eines einzelnen Jobs. Dieser Artikel geht die Rechenreihenfolge durch und zeigt die eine Stelle, an der ein permissions:-Block tatsächlich an eine dokumentierte Grenze stößt, die er selbst nicht verschieben kann.

Wie du permissions: grundsätzlich minimal scopst, mit contents: read als Baseline auf Workflow-Ebene und gezielten Erweiterungen pro Job für Release- oder Deploy-Schritte, behandeln bereits zwei bestehende Beiträge: Least Privilege in der Pipeline: Rechte, die niemand braucht vom 29.06.2026 auf diesem Blog und die Parallelfassung Least Privilege in der Pipeline: Rechte, die niemand braucht vom 10.07.2026 auf muellermh.blog. Keiner der beiden Beiträge behandelt die Org- oder Repo-Einstellung „Workflow permissions“, die Berechnungsreihenfolge zwischen dieser Vorgabe und der Workflow-Datei oder die Grenzen bei Pull Requests aus Forks. Genau diese Mechanik ist hier das Thema, nicht erneut das Argument für minimale Scopes.

Wo die Rechnung beginnt: das Token selbst

GitHub legt zu Beginn jedes Jobs ein neues GITHUB_TOKEN an. Es handelt sich um ein Installation Access Token der GitHub App, die mit der Aktivierung von Actions verbunden ist, begrenzt auf das Repository, das den Workflow enthält (docs.github.com, „GITHUB_TOKEN“). Auf von GitHub gehosteten Runnern lebt es höchstens sechs Stunden, auf selbstgehosteten Runnern lässt es sich 24 Stunden lang erneuern, auch wenn der Job selbst bis zu fünf Tage läuft, danach braucht ein länger laufender Job ein Personal Access Token oder einen anderen Authentifizierungsweg (docs.github.com, „GITHUB_TOKEN“). Eine Action erreicht das Token über den github.token-Kontext, auch wenn der Workflow es ihr nicht explizit übergibt (docs.github.com, „Automatic token authentication“). Für Rechte, die GITHUB_TOKEN grundsätzlich nicht abdeckt, verweist GitHub auf ein Installation Access Token einer eigenen GitHub App oder auf ein Personal Access Token als Secret (docs.github.com, „Automatic token authentication“). Welche Rechte das Token innerhalb seines Scopes trägt, legt aber nicht das Token selbst fest.

Stufe 1: die Org- oder Repo-Einstellung „Workflow permissions“

In den Repository-Einstellungen, Bereich Actions, Allgemein, liegt die Einstellung „Workflow permissions“. Zwei Optionen stehen zur Wahl: Lese- und Schreibzugriff für alle Berechtigungen, die permissive Einstellung, oder nur Lesezugriff für die Berechtigungen contents und packages, die restriktive Einstellung (docs.github.com, „Managing GitHub Actions settings for a repository“). Gehört das Repository zu einer Organisation und ist dort eine restriktivere Vorgabe gewählt, erscheint in den Repository-Einstellungen dieselbe Option bereits vorausgewählt, und die permissive Option lässt sich nicht mehr anwählen (docs.github.com, „Managing GitHub Actions settings for a repository“). Diese Vorgabe ist der Startwert für jeden Job, der keinen eigenen permissions:-Block mitbringt. Ist der Startwert an irgendeiner Ebene, Enterprise, Organisation oder Repository, auf restriktiv gesetzt, gilt diese Einschränkung laut GitHub für alle Repositories der Organisation als Default (docs.github.com, „Workflow syntax for GitHub Actions“).

Stufe 2: wie der permissions:-Block den Startwert verändert

GitHub beschreibt die Berechnung in zwei Schritten. Zuerst: „The permissions for the GITHUB_TOKEN are initially set to the default setting for the enterprise, organization, or repository.“ Danach: „The permissions are then adjusted based on any configuration within the workflow file“ (docs.github.com, „Workflow syntax for GitHub Actions“, Abschnitt „permissions“). Der permissions:-Block filtert die Vorgabe also nicht nur, er ersetzt sie dort, wo er etwas angibt. Daraus folgt eine Regel, die öfter übersehen wird als die Grundrechnung selbst: „If you specify the access for any of these permissions, all of those that are not specified are set to none“ (docs.github.com, „Workflow syntax for GitHub Actions“). Ein Workflow, der nur contents: read setzt, behält damit keinen impliziten Lesezugriff auf Issues oder Pull Requests, selbst wenn die Org-Vorgabe das vorsah. Alles, was im Block nicht genannt ist, steht auf none.

Zu den verfügbaren Scopes zählen unter anderem actions, checks, contents, deployments, id-token, issues, packages, pages, pull-requests, security-events und statuses, die meisten mit den Werten read, write oder none. Zwei Ausnahmen: id-token kennt nur write oder none, vulnerability-alerts nur read oder none (docs.github.com, „Workflow syntax for GitHub Actions“). Als Kurzformen stehen read-all, write-all und ein leerer Block {} zur Verfügung, der alle Berechtigungen deaktiviert (docs.github.com, „Workflow syntax for GitHub Actions“).

Stufe 3: Workflow-Ebene gegen Job-Ebene

Ein permissions:-Block auf der obersten Workflow-Ebene gilt für jeden Job darin. Ein permissions:-Block innerhalb eines einzelnen Jobs gilt nur für diesen Job (docs.github.com, „Workflow syntax for GitHub Actions“). Bringt ein Job einen eigenen Block mit, gilt für ihn dieselbe Regel wie in Stufe 2: Was dort nicht steht, ist none, unabhängig davon, was auf Workflow-Ebene stand. Ein Job erbt die Workflow-Ebene also nur, solange er selbst keinen eigenen Block mitbringt, nicht als zusätzliche Grundlage, auf der sein eigener Block aufbaut.

Was ein permissions:-Block tatsächlich nicht übersteuern kann

Hier liegt die am häufigsten falsch angenommene Stelle: dass die restriktive Org- oder Repo-Vorgabe eine Obergrenze sei, die kein Workflow mehr anheben kann. Das steht so nicht in der Dokumentation. Sie formuliert es umgekehrt: „Anyone with write access to a repository can modify the permissions granted to the GITHUB_TOKEN, adding or removing access as required, by editing the permissions key in the workflow file“ (docs.github.com, „Managing GitHub Actions settings for a repository“). Wer Schreibzugriff auf das Repository hat, kann die Workflow-Datei ändern und damit Rechte über die Vorgabe hinaus anfordern. Die restriktive Einstellung ist der Startwert für Workflows ohne eigenen Block, keine Sperre gegen Workflows mit einem.

Eine dokumentierte Grenze liegt an anderer Stelle, bei Pull Requests aus Forks. Löst ein Pull-Request-Ereignis, das nicht pull_request_target ist, einen Workflow aus einem geforkten Repository aus, und ist die Einstellung „Send write tokens to workflows from pull requests“ nicht aktiviert, gilt: „the permissions are adjusted to change any write permissions to read only“ (docs.github.com, „Workflow syntax for GitHub Actions“). Für diesen Fall hält die Dokumentation ausdrücklich fest: „typically you can’t grant write access“ (docs.github.com, „Workflow syntax for GitHub Actions“). Das pull_request_target-Ereignis liegt außerhalb dieser Regel: „When a workflow is triggered by the pull_request_target event, the GITHUB_TOKEN is granted read/write repository permission, even when it is triggered from a public fork“ (docs.github.com, „Workflow syntax for GitHub Actions“), weil der Workflow dabei im Kontext des Basis-Repositorys läuft, nicht im Kontext des Forks. Eine zweite, von einzelnen Workflows unabhängige Sperre bleibt Sache der Organisation: „Owners of an organization can restrict write access for the GITHUB_TOKEN at the repository level“ (docs.github.com, „Workflow syntax for GitHub Actions“), unabhängig davon, was im permissions:-Block eines einzelnen Workflows steht.

Was das für dein Access Review heißt

Für ein Access Review auf GITHUB_TOKEN-Ebene lohnen sich drei Fragen in dieser Reihenfolge. Erstens: Welche Workflow permissions-Vorgabe gilt für das Repository, permissiv oder restriktiv, und kommt sie vom Repository selbst oder von der Organisation? Zweitens: Welche Workflows und welche einzelnen Jobs darin haben einen eigenen permissions:-Block, und was steht dort tatsächlich, nicht nur was vermutlich gemeint war, denn jeder nicht genannte Scope fällt auf none. Drittens: Wer im Repository hat Schreibzugriff und damit die Möglichkeit, diesen Block jederzeit zu ändern, denn diese Gruppe entscheidet über die tatsächliche Reichweite des Tokens, nicht die ursprüngliche Org-Vorgabe. Ein Review, das nur die Org-Einstellung prüft und den permissions:-Block in den Workflow-Dateien selbst nicht liest, sieht nur den Startwert, nicht das Ergebnis der Rechnung.

Das Leistungsspektrum ist gestaffelt und baut auf Delivery-Transparenz auf. Es läuft über drei Felder: Implementation (Delivery- und Nachweiskontrollen in die Pipeline einziehen), AI Governance (Nachvollziehbarkeit dort schaffen, wo KI-gestützte Schritte in Build und Deployment Freigaben und Verantwortung verwischen) und Maintenance (die Übergabefrage: wem ein System nach dem Go-Live gehört und woran man merkt, dass es niemandem gehört). Ein festes Angebot daraus entsteht erst, wenn klar ist, was du wirklich brauchst. Kontakt: mm@mhm-dl.de.

Über das Anmeldeformular für den Newsletter trägst du deine E-Mail-Adresse ein, kreuzt die Einwilligung an und bestätigst die Anmeldung danach per Mail. Mit der Anmeldung willigst du ein, dass der Newsletter unter anderem folgende Themen behandelt: Schulungen zu Docker, Kubernetes, CI/CD, Git-Workflows und DevSecOps-Werkzeugen sowie die Anforderungen aus NIS2, CRA und DORA und deren technische Umsetzung.

Kommentar verfassen

MHM Digitale Lösungen

Wir machen Software-Lieferketten sicher. GitSecOps prüft und härtet deine Build- und Deployment-Pipeline, damit du gegenüber Kunden und Prüfern bestehst. Hier schreiben wir nüchtern über Supply Chain Security, DevSecOps und digitales Business.

Kontakt