No. In a chain of reusable workflows, token permissions can be maintained or reduced, never elevated. The caller sets the ceiling, and each called workflow can only stay at or below it. So set permissions deliberately in the caller, and let called workflows narrow them further.
The rule in GitHub's words
GitHub's reusable workflow documentation states that permissions can only be maintained or reduced, not elevated, throughout the chain. The documented example has the caller pass the repository token and set permissions on the calling job.
That gives you a clean mental model. Think of permissions as a funnel. The widest opening is wherever the chain starts, and every hop either keeps that opening or narrows it.
How scopes behave when you specify them
From the workflow syntax reference: if you specify access for any permission, all of those not specified are set to none. And you can disable everything with an empty mapping, written as permissions: {}.
This matters in a reusable workflow because a called workflow that declares one permission is, by that rule, declaring that everything else is none. That is how a called workflow narrows what the caller granted.
A worked example
Suppose a caller job grants read access to contents and write access to pull requests, because the reusable workflow posts a comment. In code:
jobs:
scan:
permissions:
contents: read
pull-requests: write
uses: your-org/shared-workflows/.github/workflows/scan.yml@0123456789abcdef0123456789abcdef01234567
The called workflow cannot do anything beyond those two. If it declares only contents: read in its own job, the pull request write is gone for that job. If it asks for something wider, such as write access to contents, it will not get it, because the ceiling is set by the caller.
Where people go wrong
- Granting the caller broad permissions "so the shared workflow works". The caller is where you should spend the thought. Give the minimum the workflow needs.
- Setting permissions at workflow level when jobs need different amounts. Job level lets the read-only jobs stay read-only.
- Assuming a trusted shared workflow means the permissions do not matter. A shared workflow is code from another repository. If that repository is compromised, the ceiling you set is what limits the damage.
- Skipping the pin on the reference. A reusable workflow referenced by a branch changes whenever the branch does. GitHub says the commit SHA is the safest option for stability and security.
How to check what you grant
Walk through each caller job and write one line: what does the called workflow need to do, and which scope does that require? Then compare with what the job grants. For any write scope, find the specific step that needs it.
The default token permissions for an organization can be restricted so that new workflows start with read access to contents and packages only. See GitHub Actions token permissions and least privilege for the setup.
Token lifetime is part of the picture
Each job gets its own token. It expires when the job finishes, or after its maximum lifetime. For GitHub-hosted runners that is up to six hours. A narrow, short-lived token is a smaller prize than a stored personal access token, which is one reason to avoid replacing the job token with one.
Quick check
Does a called workflow inherit the caller's permissions?
It operates within them. It can use up to what the caller job grants and can narrow further, but cannot add scopes the caller did not grant.
What does an empty permissions mapping do?
It disables all permissions for the token at that level. Use it for jobs that need no repository access, then add scopes only where required.
Sources
- GitHub Docs: Reusing workflows
- GitHub Docs: Workflow syntax for GitHub Actions
- GitHub Docs: GITHUB_TOKEN concepts
Last reviewed: 19 October 2026.