@htekdev/actions-debugger 1.0.123 → 1.0.125
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/errors/caching-artifacts/caching-artifacts-073.yml +100 -0
- package/errors/caching-artifacts/caching-artifacts-074.yml +117 -0
- package/errors/known-unsolved/known-unsolved-070.yml +83 -0
- package/errors/known-unsolved/known-unsolved-071.yml +122 -0
- package/errors/known-unsolved/known-unsolved-072.yml +143 -0
- package/errors/permissions-auth/permissions-auth-071.yml +144 -0
- package/errors/permissions-auth/permissions-auth-072.yml +112 -0
- package/errors/permissions-auth/permissions-auth-073.yml +127 -0
- package/errors/permissions-auth/permissions-auth-074.yml +106 -0
- package/errors/permissions-auth/permissions-auth-075.yml +137 -0
- package/errors/runner-environment/runner-environment-224.yml +74 -0
- package/errors/runner-environment/runner-environment-225.yml +85 -0
- package/errors/runner-environment/runner-environment-226.yml +91 -0
- package/errors/runner-environment/runner-environment-227.yml +106 -0
- package/errors/runner-environment/runner-environment-228.yml +117 -0
- package/errors/runner-environment/runner-environment-229.yml +119 -0
- package/errors/runner-environment/runner-environment-230.yml +129 -0
- package/errors/runner-environment/runner-environment-231.yml +90 -0
- package/errors/runner-environment/runner-environment-232.yml +131 -0
- package/errors/runner-environment/runner-environment-233.yml +90 -0
- package/errors/runner-environment/runner-environment-234.yml +114 -0
- package/errors/runner-environment/runner-environment-235.yml +151 -0
- package/errors/silent-failures/silent-failures-112.yml +97 -0
- package/errors/silent-failures/silent-failures-113.yml +110 -0
- package/errors/silent-failures/silent-failures-114.yml +116 -0
- package/errors/silent-failures/silent-failures-115.yml +130 -0
- package/errors/silent-failures/silent-failures-116.yml +117 -0
- package/errors/silent-failures/silent-failures-117.yml +137 -0
- package/errors/silent-failures/silent-failures-118.yml +156 -0
- package/errors/yaml-syntax/yaml-syntax-075.yml +128 -0
- package/errors/yaml-syntax/yaml-syntax-076.yml +107 -0
- package/package.json +1 -1
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
id: permissions-auth-071
|
|
2
|
+
title: 'OIDC token not available in pull_request events from forks — id-token: write cannot be granted'
|
|
3
|
+
category: permissions-auth
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- oidc
|
|
7
|
+
- fork
|
|
8
|
+
- pull-request
|
|
9
|
+
- id-token
|
|
10
|
+
- attestation
|
|
11
|
+
- aws
|
|
12
|
+
- azure
|
|
13
|
+
- workload-identity
|
|
14
|
+
patterns:
|
|
15
|
+
- regex: 'Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: 'Could not fetch an OIDC token.*id-token.*write'
|
|
18
|
+
flags: 'i'
|
|
19
|
+
- regex: 'Error: Action failed with error: Error: Error message: Unable to get ACTIONS_ID_TOKEN_REQUEST_URL'
|
|
20
|
+
flags: 'i'
|
|
21
|
+
error_messages:
|
|
22
|
+
- 'Error: Error message: Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable'
|
|
23
|
+
- 'Could not fetch an OIDC token. Did you remember to add `id-token: write` to your workflow permissions?'
|
|
24
|
+
- 'Error: Action failed with error: Error: Error message: Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable'
|
|
25
|
+
root_cause: |
|
|
26
|
+
GitHub Actions workflows triggered by `pull_request` events from forked repositories cannot
|
|
27
|
+
mint OIDC tokens, even when `id-token: write` is explicitly set in the workflow `permissions:` block.
|
|
28
|
+
|
|
29
|
+
The restriction is enforced by GitHub's security model for fork pull requests:
|
|
30
|
+
- Fork PRs run with the permissions of the fork, not the base repository.
|
|
31
|
+
- GitHub documentation states: "You can use the permissions key to add and remove read
|
|
32
|
+
permissions for forked repositories, but typically you can't grant write access."
|
|
33
|
+
- The `id-token: write` scope is a WRITE permission. The ACTIONS_ID_TOKEN_REQUEST_URL
|
|
34
|
+
environment variable is only set when the runtime has write-level token access.
|
|
35
|
+
- When the variable is absent, any action or toolkit call to `core.getIDToken()` fails with
|
|
36
|
+
"Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable".
|
|
37
|
+
|
|
38
|
+
This commonly impacts:
|
|
39
|
+
- Cloud provider OIDC authentication (AWS configure-aws-credentials, Azure login, GCP auth)
|
|
40
|
+
- actions/attest-build-provenance and actions/attest for build attestation on PRs
|
|
41
|
+
- Any action that relies on `@actions/core` `getIDToken()` for OIDC federation
|
|
42
|
+
|
|
43
|
+
The restriction exists to prevent malicious fork contributors from using OIDC tokens to
|
|
44
|
+
authenticate against production cloud accounts or push malicious artifacts.
|
|
45
|
+
fix: |
|
|
46
|
+
Option 1 — Use `pull_request_target` instead of `pull_request` (CAUTION required).
|
|
47
|
+
`pull_request_target` runs in the context of the base repository and CAN mint OIDC tokens.
|
|
48
|
+
However, it executes in the base repo's context with full access to base repo secrets —
|
|
49
|
+
this is a significant security risk if the workflow checks out or executes fork code without
|
|
50
|
+
proper isolation. Read all security guides before using this trigger.
|
|
51
|
+
|
|
52
|
+
Option 2 — Split the workflow into two parts.
|
|
53
|
+
Use `pull_request` for the build/test phase (no OIDC). Use a separate workflow triggered
|
|
54
|
+
by `workflow_run` or manual approval to perform OIDC-protected operations (attestation, deploy)
|
|
55
|
+
after verifying the PR code is safe.
|
|
56
|
+
|
|
57
|
+
Option 3 — Use a GitHub App token with explicit repository permissions for operations
|
|
58
|
+
that do not strictly require OIDC (e.g., package publishing). This avoids the OIDC
|
|
59
|
+
restriction entirely.
|
|
60
|
+
|
|
61
|
+
Option 4 — Only run OIDC-dependent steps on `push` events to protected branches (post-merge),
|
|
62
|
+
not on `pull_request` events from forks. Guard OIDC steps with:
|
|
63
|
+
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false
|
|
64
|
+
fix_code:
|
|
65
|
+
- language: yaml
|
|
66
|
+
label: 'Guard OIDC steps — skip for fork PRs, run only for same-repo PRs or push'
|
|
67
|
+
code: |
|
|
68
|
+
jobs:
|
|
69
|
+
build-and-attest:
|
|
70
|
+
runs-on: ubuntu-latest
|
|
71
|
+
permissions:
|
|
72
|
+
id-token: write
|
|
73
|
+
contents: read
|
|
74
|
+
attestations: write
|
|
75
|
+
steps:
|
|
76
|
+
- uses: actions/checkout@v4
|
|
77
|
+
|
|
78
|
+
- name: Build artifact
|
|
79
|
+
run: ./build.sh
|
|
80
|
+
|
|
81
|
+
# OIDC-dependent steps: skip if fork PR (id-token write not available)
|
|
82
|
+
- name: Attest build provenance
|
|
83
|
+
if: >
|
|
84
|
+
github.event_name != 'pull_request' ||
|
|
85
|
+
github.event.pull_request.head.repo.full_name == github.repository
|
|
86
|
+
uses: actions/attest-build-provenance@v2
|
|
87
|
+
with:
|
|
88
|
+
subject-path: './dist/app'
|
|
89
|
+
|
|
90
|
+
- language: yaml
|
|
91
|
+
label: 'Split workflow: use workflow_run to run OIDC steps after fork PR merges'
|
|
92
|
+
code: |
|
|
93
|
+
# Workflow 1: runs on pull_request — builds and uploads artifact (no OIDC)
|
|
94
|
+
on:
|
|
95
|
+
pull_request:
|
|
96
|
+
jobs:
|
|
97
|
+
build:
|
|
98
|
+
runs-on: ubuntu-latest
|
|
99
|
+
steps:
|
|
100
|
+
- uses: actions/checkout@v4
|
|
101
|
+
- run: ./build.sh
|
|
102
|
+
- uses: actions/upload-artifact@v4
|
|
103
|
+
with:
|
|
104
|
+
name: build-output
|
|
105
|
+
path: ./dist/
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
# Workflow 2: runs after workflow 1 completes — performs OIDC operations
|
|
110
|
+
on:
|
|
111
|
+
workflow_run:
|
|
112
|
+
workflows: ['Build']
|
|
113
|
+
types: [completed]
|
|
114
|
+
jobs:
|
|
115
|
+
attest:
|
|
116
|
+
# Only runs on base-repo push events completing after a merge
|
|
117
|
+
if: github.event.workflow_run.conclusion == 'success'
|
|
118
|
+
runs-on: ubuntu-latest
|
|
119
|
+
permissions:
|
|
120
|
+
id-token: write
|
|
121
|
+
attestations: write
|
|
122
|
+
steps:
|
|
123
|
+
- uses: actions/download-artifact@v4
|
|
124
|
+
with:
|
|
125
|
+
name: build-output
|
|
126
|
+
run-id: ${{ github.event.workflow_run.id }}
|
|
127
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
128
|
+
- uses: actions/attest-build-provenance@v2
|
|
129
|
+
with:
|
|
130
|
+
subject-path: './dist/app'
|
|
131
|
+
prevention:
|
|
132
|
+
- 'Never assume `id-token: write` is sufficient — fork PRs override write permissions to read-only regardless of the workflow `permissions:` block.'
|
|
133
|
+
- 'Add an explicit `if:` guard on every OIDC-dependent step to skip it for fork PRs: `if: github.event.pull_request.head.repo.fork == false`.'
|
|
134
|
+
- 'Use `pull_request_target` only after thoroughly reading the security hardening guide — it runs in base repo context and is vulnerable to pwn requests if fork code is checked out.'
|
|
135
|
+
- 'For attestation workflows, run attestation as a post-merge step on `push` to the default branch, not on PRs from forks.'
|
|
136
|
+
docs:
|
|
137
|
+
- url: 'https://github.com/actions/attest-build-provenance/issues/99'
|
|
138
|
+
label: 'actions/attest-build-provenance#99 — OIDC unavailable in fork PR workflows (open)'
|
|
139
|
+
- url: 'https://github.com/aws-actions/configure-aws-credentials/issues/373'
|
|
140
|
+
label: 'aws-actions/configure-aws-credentials#373 — OIDC fails for pull request from fork'
|
|
141
|
+
- url: 'https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#permissions-for-the-github_token'
|
|
142
|
+
label: 'GitHub Docs — GITHUB_TOKEN permissions for forked repos'
|
|
143
|
+
- url: 'https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#using-pull_request_target-safely'
|
|
144
|
+
label: 'GitHub Docs — Security hardening for pull_request_target'
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
id: permissions-auth-072
|
|
2
|
+
title: 'actions/labeler fails with "You do not have permission to create labels" — missing issues: write'
|
|
3
|
+
category: permissions-auth
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- actions/labeler
|
|
7
|
+
- issues
|
|
8
|
+
- labels
|
|
9
|
+
- permissions
|
|
10
|
+
- issues-write
|
|
11
|
+
- GITHUB_TOKEN
|
|
12
|
+
- HttpError
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: 'You do not have permission to create labels on this repository'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'HttpError.+do not have permission to create labels'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
- regex: '"resource":"Repository","field":"label","code":"unauthorized"'
|
|
19
|
+
flags: 'i'
|
|
20
|
+
error_messages:
|
|
21
|
+
- 'HttpError: You do not have permission to create labels on this repository.: {"resource":"Repository","field":"label","code":"unauthorized"}'
|
|
22
|
+
- 'Error: You do not have permission to create labels on this repository.'
|
|
23
|
+
root_cause: |
|
|
24
|
+
`actions/labeler` requires the `issues: write` permission on the
|
|
25
|
+
`GITHUB_TOKEN` whenever it needs to **create** a label that does not yet
|
|
26
|
+
exist in the repository. The labeler's `create-labels: true` setting (or
|
|
27
|
+
its equivalent in older versions that auto-create missing labels) triggers a
|
|
28
|
+
`POST /repos/{owner}/{repo}/labels` API call.
|
|
29
|
+
|
|
30
|
+
In 2023+, GitHub tightened default token permissions. Repositories and
|
|
31
|
+
organizations that enable "Read repository contents and packages permissions"
|
|
32
|
+
as the default GITHUB_TOKEN permission, or workflows that explicitly
|
|
33
|
+
enumerate `permissions:` without including `issues: write`, will cause the
|
|
34
|
+
label-creation API call to return HTTP 403:
|
|
35
|
+
|
|
36
|
+
`HttpError: You do not have permission to create labels on this repository.`
|
|
37
|
+
|
|
38
|
+
Note: If all labels already exist in the repository, the action only calls
|
|
39
|
+
`GET /repos/{owner}/{repo}/labels` (read) and `POST .../issues/{number}/labels`
|
|
40
|
+
(adding a label to an issue/PR — also requires issues:write). In practice,
|
|
41
|
+
any labeling operation that modifies issues or creates labels needs this
|
|
42
|
+
permission. The error is especially confusing because it surfaces as an
|
|
43
|
+
`HttpError` that looks like a GitHub API error rather than a clear
|
|
44
|
+
"permission denied" message.
|
|
45
|
+
fix: |
|
|
46
|
+
Add `issues: write` to the workflow or job permissions block:
|
|
47
|
+
|
|
48
|
+
```yaml
|
|
49
|
+
permissions:
|
|
50
|
+
issues: write
|
|
51
|
+
pull-requests: write # Also needed if labeling pull requests
|
|
52
|
+
contents: read
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
If the repository uses the default broad permissions and the error occurs on
|
|
56
|
+
a fork PR (where fork PRs receive read-only tokens regardless of the
|
|
57
|
+
workflow's permissions block), add a guard:
|
|
58
|
+
|
|
59
|
+
```yaml
|
|
60
|
+
if: github.event.pull_request.head.repo.full_name == github.repository
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
to skip label creation on fork PRs where the token cannot be elevated.
|
|
64
|
+
fix_code:
|
|
65
|
+
- language: yaml
|
|
66
|
+
label: 'Add issues: write permission to the labeler job'
|
|
67
|
+
code: |
|
|
68
|
+
name: Label PRs
|
|
69
|
+
|
|
70
|
+
on:
|
|
71
|
+
pull_request_target:
|
|
72
|
+
types: [opened, synchronize, reopened]
|
|
73
|
+
|
|
74
|
+
jobs:
|
|
75
|
+
label:
|
|
76
|
+
runs-on: ubuntu-latest
|
|
77
|
+
permissions:
|
|
78
|
+
issues: write # Required to create new labels
|
|
79
|
+
pull-requests: write # Required to add labels to pull requests
|
|
80
|
+
contents: read
|
|
81
|
+
steps:
|
|
82
|
+
- uses: actions/labeler@v5
|
|
83
|
+
with:
|
|
84
|
+
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
85
|
+
- language: yaml
|
|
86
|
+
label: 'Skip labeler on fork PRs where token is always read-only'
|
|
87
|
+
code: |
|
|
88
|
+
jobs:
|
|
89
|
+
label:
|
|
90
|
+
runs-on: ubuntu-latest
|
|
91
|
+
# Skip on forks — their GITHUB_TOKEN is read-only regardless of permissions block
|
|
92
|
+
if: github.event.pull_request.head.repo.full_name == github.repository
|
|
93
|
+
permissions:
|
|
94
|
+
issues: write
|
|
95
|
+
pull-requests: write
|
|
96
|
+
contents: read
|
|
97
|
+
steps:
|
|
98
|
+
- uses: actions/labeler@v5
|
|
99
|
+
with:
|
|
100
|
+
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
101
|
+
prevention:
|
|
102
|
+
- 'Always include `issues: write` and `pull-requests: write` when using actions/labeler, even if the labeler config only applies existing labels — it still needs write to apply labels to PRs/issues.'
|
|
103
|
+
- 'Pre-create all labels defined in `.github/labeler.yml` in the repository settings so the action never needs to create them, reducing the permission surface needed (though issues:write is still needed for applying labels to issues/PRs).'
|
|
104
|
+
- 'When using `pull_request` trigger (not `pull_request_target`), fork PRs receive a read-only GITHUB_TOKEN by design; switch to `pull_request_target` or handle fork PRs with a separate read-only path.'
|
|
105
|
+
- 'Use the permissions checker in your CI review process: verify labeler workflows include explicit `permissions:` blocks before merging.'
|
|
106
|
+
docs:
|
|
107
|
+
- url: 'https://github.com/actions/labeler/issues/870'
|
|
108
|
+
label: 'actions/labeler#870 — HttpError: You do not have permission to create labels on this repository'
|
|
109
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token'
|
|
110
|
+
label: 'GitHub Docs — Controlling permissions for GITHUB_TOKEN'
|
|
111
|
+
- url: 'https://github.com/actions/labeler#token'
|
|
112
|
+
label: 'actions/labeler — Token and permissions requirements'
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
id: permissions-auth-073
|
|
2
|
+
title: 'GraphQL "refusing to allow a GitHub App to create or update workflow without `workflows` permission" — misleading error, actual fix is actions: write or App workflow scope'
|
|
3
|
+
category: permissions-auth
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- GitHub-App
|
|
7
|
+
- workflows
|
|
8
|
+
- actions-write
|
|
9
|
+
- GraphQL
|
|
10
|
+
- pull-request
|
|
11
|
+
- misleading-error
|
|
12
|
+
- OAuth-scope
|
|
13
|
+
- enablePullRequestAutoMerge
|
|
14
|
+
patterns:
|
|
15
|
+
- regex: "refusing to allow a GitHub App to create or update workflow .+ without .workflows. permission"
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: 'GraphQL.+Pull request.+workflow.+without.+workflows.*permission'
|
|
18
|
+
flags: 'i'
|
|
19
|
+
error_messages:
|
|
20
|
+
- "GraphQL: Pull request refusing to allow a GitHub App to create or update workflow `.github/workflows/release.yml` without `workflows` permission (enablePullRequestAutoMerge)"
|
|
21
|
+
- "refusing to allow a GitHub App to create or update workflow `.github/workflows/ci.yml` without `workflows` permission"
|
|
22
|
+
root_cause: |
|
|
23
|
+
When a GitHub App or the `GITHUB_TOKEN` attempts to enable auto-merge,
|
|
24
|
+
create a pull request that modifies workflow files, or perform certain
|
|
25
|
+
pull-request GraphQL mutations (`enablePullRequestAutoMerge`,
|
|
26
|
+
`createPullRequest`, etc.) on a branch that touches `.github/workflows/`,
|
|
27
|
+
GitHub's API returns a misleading error:
|
|
28
|
+
|
|
29
|
+
`GraphQL: Pull request refusing to allow a GitHub App to create or update
|
|
30
|
+
workflow '...' without 'workflows' permission`
|
|
31
|
+
|
|
32
|
+
The error message references `workflows` as if it were a value you can set
|
|
33
|
+
in the `permissions:` block of a GitHub Actions workflow. **It is not.**
|
|
34
|
+
The word `workflows` here refers to the **GitHub App OAuth scope** (which
|
|
35
|
+
grants the App permission to edit workflow files), not the `actions: write`
|
|
36
|
+
or any standard GITHUB_TOKEN permission key.
|
|
37
|
+
|
|
38
|
+
There are two distinct situations that produce this error:
|
|
39
|
+
|
|
40
|
+
1. **GitHub App missing the Workflows permission:** If your GitHub App does
|
|
41
|
+
not have the "Workflows" repository permission (a GitHub App installation
|
|
42
|
+
permission distinct from all the `permissions:` block keys), any operation
|
|
43
|
+
that modifies `.github/workflows/` through the App will be rejected with
|
|
44
|
+
this message.
|
|
45
|
+
|
|
46
|
+
2. **GITHUB_TOKEN used for auto-merge enabling on workflow-touching PRs:**
|
|
47
|
+
When a workflow uses `gh pr merge --auto` (or the GraphQL
|
|
48
|
+
`enablePullRequestAutoMerge` mutation) on a PR that modifies workflow
|
|
49
|
+
files, the GITHUB_TOKEN may lack the necessary scope even with
|
|
50
|
+
`contents: write`, because enabling auto-merge on workflow-modifying PRs
|
|
51
|
+
requires the workflows OAuth scope which GITHUB_TOKEN cannot hold.
|
|
52
|
+
|
|
53
|
+
The error message's reference to `workflows` is confusing because it is not
|
|
54
|
+
a recognized key in the YAML `permissions:` block. Developers who try to
|
|
55
|
+
add `permissions: workflows: write` get a YAML validation error ("Unknown
|
|
56
|
+
property 'workflows'"), leading to frustration when neither the permissions
|
|
57
|
+
block nor the token can be directly granted this scope.
|
|
58
|
+
fix: |
|
|
59
|
+
**For GitHub Apps:**
|
|
60
|
+
Go to your GitHub App's settings → Permissions & events → Repository
|
|
61
|
+
permissions → and enable **"Workflows" permission** (set to Read & Write).
|
|
62
|
+
Then re-install the app on the repository/organization so the new permission
|
|
63
|
+
takes effect.
|
|
64
|
+
|
|
65
|
+
**For GITHUB_TOKEN on auto-merge of workflow-touching PRs:**
|
|
66
|
+
The GITHUB_TOKEN cannot hold the `workflows` OAuth scope. You must use a
|
|
67
|
+
Personal Access Token (classic, with the `workflow` scope) or a GitHub App
|
|
68
|
+
with the Workflows permission. Store either as a repository secret and use it
|
|
69
|
+
instead of `GITHUB_TOKEN` for the auto-merge step:
|
|
70
|
+
|
|
71
|
+
```yaml
|
|
72
|
+
- name: Enable auto-merge
|
|
73
|
+
env:
|
|
74
|
+
GH_TOKEN: ${{ secrets.MY_PAT_WITH_WORKFLOW_SCOPE }}
|
|
75
|
+
run: gh pr merge --auto --squash ${{ github.event.pull_request.number }}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**For `actions: write` confusion:**
|
|
79
|
+
Adding `actions: write` to the `permissions:` block does NOT fix this error.
|
|
80
|
+
`actions: write` governs artifacts, caches, and workflow runs — NOT the
|
|
81
|
+
ability to create or modify workflow files.
|
|
82
|
+
fix_code:
|
|
83
|
+
- language: yaml
|
|
84
|
+
label: 'Use a PAT with the workflow scope instead of GITHUB_TOKEN for auto-merge on workflow-touching PRs'
|
|
85
|
+
code: |
|
|
86
|
+
jobs:
|
|
87
|
+
auto-merge:
|
|
88
|
+
runs-on: ubuntu-latest
|
|
89
|
+
steps:
|
|
90
|
+
- name: Enable auto-merge
|
|
91
|
+
# GITHUB_TOKEN cannot hold the 'workflow' OAuth scope.
|
|
92
|
+
# Use a PAT (classic) with the 'workflow' scope stored as a secret.
|
|
93
|
+
env:
|
|
94
|
+
GH_TOKEN: ${{ secrets.PAT_WITH_WORKFLOW_SCOPE }}
|
|
95
|
+
run: |
|
|
96
|
+
gh pr merge --auto --squash "${{ github.event.pull_request.number }}"
|
|
97
|
+
- language: yaml
|
|
98
|
+
label: 'Use create-github-app-token with Workflows permission to create PRs that modify workflows'
|
|
99
|
+
code: |
|
|
100
|
+
jobs:
|
|
101
|
+
create-update-pr:
|
|
102
|
+
runs-on: ubuntu-latest
|
|
103
|
+
steps:
|
|
104
|
+
- name: Generate App token (App must have Workflows read+write permission)
|
|
105
|
+
id: app-token
|
|
106
|
+
uses: actions/create-github-app-token@v1
|
|
107
|
+
with:
|
|
108
|
+
app-id: ${{ vars.MY_APP_ID }}
|
|
109
|
+
private-key: ${{ secrets.MY_APP_PRIVATE_KEY }}
|
|
110
|
+
|
|
111
|
+
- name: Create PR modifying a workflow file
|
|
112
|
+
env:
|
|
113
|
+
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
|
114
|
+
run: |
|
|
115
|
+
gh pr create --title "Update workflow" --body "..." --base main
|
|
116
|
+
prevention:
|
|
117
|
+
- 'When your GitHub App or automation needs to create PRs that touch `.github/workflows/`, verify the App installation has the "Workflows" repository permission enabled (App settings → Permissions → Workflows: Read & Write).'
|
|
118
|
+
- 'Do NOT attempt `permissions: workflows: write` in your workflow YAML — "workflows" is not a valid permission key and will cause a YAML validation error; it is an App-level OAuth scope, not a token permission.'
|
|
119
|
+
- 'For auto-merge automation on PRs that may modify workflow files, use a classic PAT with the `workflow` scope or a GitHub App with Workflows permission rather than GITHUB_TOKEN.'
|
|
120
|
+
- 'When debugging this error, the key question is: "Does the token/App have the `workflows` OAuth scope?" — not "Does the job have the right permissions: block?"'
|
|
121
|
+
docs:
|
|
122
|
+
- url: 'https://github.com/cli/cli/issues/11493'
|
|
123
|
+
label: 'cli/cli#11493 — Misleading GraphQL error: "without workflows permission" when using enablePullRequestAutoMerge'
|
|
124
|
+
- url: 'https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/choosing-permissions-for-a-github-app'
|
|
125
|
+
label: 'GitHub Docs — Choosing permissions for a GitHub App (Workflows permission)'
|
|
126
|
+
- url: 'https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens'
|
|
127
|
+
label: 'GitHub Docs — Classic PAT workflow scope for modifying workflow files'
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
id: permissions-auth-074
|
|
2
|
+
title: 'Composer leaks new-format GITHUB_TOKEN (ghs_APPID_JWT) to stderr in CI logs — CVE-2026-45793 / GHSA-f9f8-rm49-7jv2'
|
|
3
|
+
category: permissions-auth
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- composer
|
|
7
|
+
- GITHUB_TOKEN
|
|
8
|
+
- token-disclosure
|
|
9
|
+
- ghs-token
|
|
10
|
+
- php
|
|
11
|
+
- setup-php
|
|
12
|
+
- CVE-2026-45793
|
|
13
|
+
- security
|
|
14
|
+
- token-format-rollout
|
|
15
|
+
patterns:
|
|
16
|
+
- regex: 'Your github oauth token for .+ contains invalid characters'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
- regex: 'UnexpectedValueException.+github oauth token.+invalid characters'
|
|
19
|
+
flags: 'i'
|
|
20
|
+
- regex: 'contains invalid characters: "ghs_'
|
|
21
|
+
flags: 'i'
|
|
22
|
+
error_messages:
|
|
23
|
+
- 'Your github oauth token for github.com contains invalid characters: "ghs_AppID_eyJhbGc..."'
|
|
24
|
+
- '[InvalidArgumentException] Your github oauth token for github.com contains invalid characters: "ghs_..."'
|
|
25
|
+
root_cause: |
|
|
26
|
+
Starting April 27, 2026, GitHub began rolling out a new stateless token format for
|
|
27
|
+
GITHUB_TOKEN and GitHub App installation tokens. The new format is `ghs_<AppID>_<JWT>`,
|
|
28
|
+
approximately 520 characters long, and uses base64url encoding which includes hyphens (`-`)
|
|
29
|
+
and underscores.
|
|
30
|
+
|
|
31
|
+
Composer versions >=2.3.0 <2.9.8 (and >=1.0 <1.10.28, >=2.0.0 <2.2.28) validate GitHub OAuth
|
|
32
|
+
tokens with the regex `^[.A-Za-z0-9_]+$`. This regex does not permit hyphens. The new
|
|
33
|
+
`ghs_APPID_JWT` token format routinely contains hyphens (base64url RFC 4648 §5 uses `-` and `_`
|
|
34
|
+
as URL-safe replacements for `+` and `/`).
|
|
35
|
+
|
|
36
|
+
When the token fails this validation, Composer throws an `UnexpectedValueException` that
|
|
37
|
+
interpolates the raw token verbatim into the error message:
|
|
38
|
+
|
|
39
|
+
`Your github oauth token for github.com contains invalid characters: "ghs_<full-token>"`
|
|
40
|
+
|
|
41
|
+
Symfony Console then prints this exception to stderr. GitHub Actions' built-in secret masker
|
|
42
|
+
matches registered values as exact substrings, but Symfony Console may wrap the message, embed
|
|
43
|
+
it in framing text (`In BaseIO.php line N:`), or interleave ANSI control sequences. As a result,
|
|
44
|
+
the masker does not redact the token, and the plaintext credential reaches the CI log.
|
|
45
|
+
|
|
46
|
+
This affects any PHP workflow that uses Composer with GITHUB_TOKEN registered as a GitHub OAuth
|
|
47
|
+
credential. Many widely-used Actions — including `shivammathur/setup-php` — automatically
|
|
48
|
+
register `GITHUB_TOKEN` into Composer's global `auth.json`, so the leak triggers without
|
|
49
|
+
any explicit user configuration.
|
|
50
|
+
|
|
51
|
+
CVSS score: 7.5 (High). CVE-2026-45793 / GHSA-f9f8-rm49-7jv2.
|
|
52
|
+
fix: |
|
|
53
|
+
**Primary fix: Upgrade Composer to a patched version.**
|
|
54
|
+
- Composer 2.x (mainline): upgrade to >=2.9.8
|
|
55
|
+
- Composer 2.2.x (LTS): upgrade to >=2.2.28
|
|
56
|
+
- Composer 1.x: upgrade to >=1.10.28
|
|
57
|
+
|
|
58
|
+
The patched versions update the token validation regex to accept hyphens, preventing the
|
|
59
|
+
disclosure.
|
|
60
|
+
|
|
61
|
+
**Secondary workaround (if upgrading is not immediately possible):**
|
|
62
|
+
Explicitly unset the GitHub token from Composer's auth config before running Composer, then
|
|
63
|
+
set it via a token-safe mechanism, or use a classic `ghp_` PAT which uses the old format
|
|
64
|
+
unaffected by this regression:
|
|
65
|
+
|
|
66
|
+
```yaml
|
|
67
|
+
- name: Remove GITHUB_TOKEN from Composer auth (workaround)
|
|
68
|
+
run: composer config --global --unset github-oauth.github.com
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**If using `shivammathur/setup-php`:** The action pins a Composer version; ensure you're on
|
|
72
|
+
a version that ships Composer >=2.9.8.
|
|
73
|
+
fix_code:
|
|
74
|
+
- language: yaml
|
|
75
|
+
label: 'Pin Composer to patched version in GitHub Actions workflow'
|
|
76
|
+
code: |
|
|
77
|
+
- name: Install dependencies
|
|
78
|
+
run: |
|
|
79
|
+
# Ensure Composer is on a patched version before running install.
|
|
80
|
+
# Composer 2.9.8+ fixes CVE-2026-45793 (GITHUB_TOKEN disclosure with new ghs_ format)
|
|
81
|
+
composer self-update --2 2.9.8
|
|
82
|
+
composer install --no-interaction --prefer-dist
|
|
83
|
+
- language: yaml
|
|
84
|
+
label: 'Use shivammathur/setup-php with Composer version pinned to patched release'
|
|
85
|
+
code: |
|
|
86
|
+
- name: Set up PHP and Composer
|
|
87
|
+
uses: shivammathur/setup-php@v2
|
|
88
|
+
with:
|
|
89
|
+
php-version: '8.3'
|
|
90
|
+
tools: composer:2.9.8 # Pin to patched version fixing CVE-2026-45793
|
|
91
|
+
env:
|
|
92
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
93
|
+
prevention:
|
|
94
|
+
- 'Always pin Composer to a specific patched version in CI (e.g., `composer:2.9.8` in setup-php tools). Do not rely on "latest" which may ship a vulnerable version during the rollout window.'
|
|
95
|
+
- 'Audit your workflow logs for lines matching `contains invalid characters` — these indicate a credential has been disclosed to the log.'
|
|
96
|
+
- 'Be aware that `shivammathur/setup-php` auto-registers `GITHUB_TOKEN` into Composer auth by default; upgrading to a patched Composer is the only reliable mitigation.'
|
|
97
|
+
- 'For repositories that do not need Composer to make authenticated GitHub API calls, you can disable auto-registration: `COMPOSER_AUTH: ''{}''` in the env block prevents auto-injection.'
|
|
98
|
+
docs:
|
|
99
|
+
- url: 'https://github.com/advisories/GHSA-f9f8-rm49-7jv2'
|
|
100
|
+
label: 'GHSA-f9f8-rm49-7jv2 — Composer leaks GITHUB_TOKEN in CI logs (CVE-2026-45793)'
|
|
101
|
+
- url: 'https://github.com/composer/composer/security/advisories/GHSA-f9f8-rm49-7jv2'
|
|
102
|
+
label: 'composer/composer security advisory — GHSA-f9f8-rm49-7jv2 details and affected versions'
|
|
103
|
+
- url: 'https://github.blog/changelog/2026-04-24-notice-about-upcoming-new-format-for-github-app-installation-tokens/'
|
|
104
|
+
label: 'GitHub Changelog — Notice about new format for GitHub App installation tokens (April 2026)'
|
|
105
|
+
- url: 'https://github.com/composer/composer/issues/12849'
|
|
106
|
+
label: 'composer/composer#12849 — New format for GitHub Tokens (upstream issue report)'
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
id: permissions-auth-075
|
|
2
|
+
title: 'OIDC token missing `repository_custom_property_*` claim — custom property must be defined at org level, not just repo level'
|
|
3
|
+
category: permissions-auth
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- OIDC
|
|
7
|
+
- custom-properties
|
|
8
|
+
- trust-policy
|
|
9
|
+
- AWS
|
|
10
|
+
- Azure
|
|
11
|
+
- claim-missing
|
|
12
|
+
- org-level
|
|
13
|
+
- AccessDenied
|
|
14
|
+
- cloud-auth
|
|
15
|
+
patterns:
|
|
16
|
+
- regex: 'repository_custom_property'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
- regex: '(?:AccessDenied|is not authorized).+sts:AssumeRoleWithWebIdentity'
|
|
19
|
+
flags: 'i'
|
|
20
|
+
- regex: 'OpenIDConnectTokenVerificationFailed|sub.*claim.*condition.*failed|conditions.*not.*met'
|
|
21
|
+
flags: 'i'
|
|
22
|
+
error_messages:
|
|
23
|
+
- 'Error: User: arn:aws:sts::ACCOUNT:assumed-role/... is not authorized to perform: sts:AssumeRoleWithWebIdentity'
|
|
24
|
+
- 'Could not assume role with OIDC: Not authorized to perform sts:AssumeRoleWithWebIdentity'
|
|
25
|
+
- 'ClientAssertionCredential authentication failed: AADSTS70021'
|
|
26
|
+
- 'Error: No federated identity credential with issuer https://token.actions.githubusercontent.com matches'
|
|
27
|
+
root_cause: |
|
|
28
|
+
GitHub Actions OIDC tokens gained support for `repository_custom_property_*` claims in
|
|
29
|
+
March 2026 (GA April 2, 2026 changelog). These claims allow trust policies on AWS, Azure,
|
|
30
|
+
and other cloud providers to filter access based on how a repository is classified within
|
|
31
|
+
an organization (e.g., `repository_custom_property_environment: production`).
|
|
32
|
+
|
|
33
|
+
However, there is a critical prerequisite that is not prominently documented:
|
|
34
|
+
**custom property definitions must be created at the organization level** — not just at the
|
|
35
|
+
repository level — for the corresponding claims to appear in OIDC tokens.
|
|
36
|
+
|
|
37
|
+
Specifically:
|
|
38
|
+
1. The custom property must be defined in the organization's custom properties schema
|
|
39
|
+
(Settings → Custom properties at the org level).
|
|
40
|
+
2. The property must be set/assigned a value for the repository in question.
|
|
41
|
+
|
|
42
|
+
When a property is created only at the **repository level** (via repo-specific custom
|
|
43
|
+
properties without an org-level schema entry), or when the property exists at the org
|
|
44
|
+
level but has no value set for the specific repository, the `repository_custom_property_*`
|
|
45
|
+
claim is simply **absent** from the OIDC token rather than being set to null or an empty
|
|
46
|
+
string.
|
|
47
|
+
|
|
48
|
+
Trust policies that include a condition requiring a specific `repository_custom_property_*`
|
|
49
|
+
claim evaluate to no-match and deny authentication. The cloud provider returns a generic
|
|
50
|
+
`AccessDenied` / `is not authorized` error with no indication that the claim is missing.
|
|
51
|
+
The workflow author sees a cloud authentication failure with no clear link to the OIDC
|
|
52
|
+
token contents.
|
|
53
|
+
|
|
54
|
+
This is a silent configuration error: the workflow appears to run normally until the
|
|
55
|
+
authentication step fails, and there is no warning during workflow setup or YAML validation
|
|
56
|
+
that the property is misconfigured.
|
|
57
|
+
fix: |
|
|
58
|
+
**Step 1: Verify the OIDC token contents.**
|
|
59
|
+
Add a debug step to print the OIDC token claims before the cloud auth step:
|
|
60
|
+
|
|
61
|
+
```yaml
|
|
62
|
+
- name: Debug OIDC claims
|
|
63
|
+
run: |
|
|
64
|
+
TOKEN=$(curl -sS -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
|
|
65
|
+
"$ACTIONS_ID_TOKEN_REQUEST_URL" | jq -r '.value')
|
|
66
|
+
echo "$TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq .
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
If `repository_custom_property_*` claims are absent, the property is not defined at the
|
|
70
|
+
org level or has no value for this repository.
|
|
71
|
+
|
|
72
|
+
**Step 2: Define the custom property at the organization level.**
|
|
73
|
+
Navigate to the GitHub organization → Settings → Custom properties and create the property
|
|
74
|
+
definition there. Repository-level-only properties do NOT produce OIDC claims.
|
|
75
|
+
|
|
76
|
+
**Step 3: Assign a value to the property for the target repository.**
|
|
77
|
+
After creating the org-level property definition, explicitly set the value for each
|
|
78
|
+
repository that needs the claim by going to the repository's Settings → Custom properties
|
|
79
|
+
or using the REST API.
|
|
80
|
+
|
|
81
|
+
**If you cannot use org-level properties:** Fall back to other OIDC sub-claim conditions
|
|
82
|
+
such as `repository`, `ref`, `environment`, or `job_workflow_ref` which are always present
|
|
83
|
+
in Actions OIDC tokens.
|
|
84
|
+
fix_code:
|
|
85
|
+
- language: yaml
|
|
86
|
+
label: 'Add OIDC debug step to inspect claims before cloud auth'
|
|
87
|
+
code: |
|
|
88
|
+
jobs:
|
|
89
|
+
deploy:
|
|
90
|
+
runs-on: ubuntu-latest
|
|
91
|
+
permissions:
|
|
92
|
+
id-token: write
|
|
93
|
+
contents: read
|
|
94
|
+
steps:
|
|
95
|
+
- name: Debug OIDC token claims (remove after debugging)
|
|
96
|
+
run: |
|
|
97
|
+
TOKEN=$(curl -sS \
|
|
98
|
+
-H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
|
|
99
|
+
"$ACTIONS_ID_TOKEN_REQUEST_URL" | jq -r '.value')
|
|
100
|
+
# Print decoded payload (base64url decode the second segment)
|
|
101
|
+
echo "$TOKEN" | cut -d. -f2 | \
|
|
102
|
+
python3 -c "import sys,base64,json; data=sys.stdin.read().strip(); \
|
|
103
|
+
padded=data+'=='*((-len(data))%4); \
|
|
104
|
+
print(json.dumps(json.loads(base64.urlsafe_b64decode(padded)), indent=2))"
|
|
105
|
+
|
|
106
|
+
- name: Configure AWS credentials via OIDC
|
|
107
|
+
uses: aws-actions/configure-aws-credentials@v4
|
|
108
|
+
with:
|
|
109
|
+
role-to-assume: arn:aws:iam::ACCOUNT:role/my-role
|
|
110
|
+
aws-region: us-east-1
|
|
111
|
+
- language: yaml
|
|
112
|
+
label: 'AWS trust policy condition using repository_custom_property_* (requires org-level property)'
|
|
113
|
+
code: |
|
|
114
|
+
# AWS IAM trust policy condition requiring a custom property claim.
|
|
115
|
+
# PREREQUISITE: The property must be defined at org level AND set on the repository.
|
|
116
|
+
# If the claim is absent, AWS returns AccessDenied with no indication of missing claim.
|
|
117
|
+
{
|
|
118
|
+
"Condition": {
|
|
119
|
+
"StringEquals": {
|
|
120
|
+
"token.actions.githubusercontent.com:repository_custom_property_environment": "production"
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
prevention:
|
|
125
|
+
- 'Always create custom property definitions at the **organization level** (Org Settings → Custom properties), not just at the repository level. Repo-level-only properties do NOT appear in OIDC tokens.'
|
|
126
|
+
- 'After creating an org-level property, explicitly set a value for each target repository. A property defined but not assigned a value for a repo is also absent from the OIDC token.'
|
|
127
|
+
- 'Before deploying trust policies that use `repository_custom_property_*` conditions, verify the claim is present in the OIDC token by printing decoded token claims in a debug step.'
|
|
128
|
+
- 'When trust policy conditions reference `repository_custom_property_*`, always have a fallback monitoring alert for `AccessDenied` / `is not authorized` errors to catch misconfigured or unset properties quickly.'
|
|
129
|
+
docs:
|
|
130
|
+
- url: 'https://github.com/github/docs/issues/43779'
|
|
131
|
+
label: 'github/docs#43779 — custom properties docs gap: org-level definition required for OIDC claims'
|
|
132
|
+
- url: 'https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/about-security-hardening-with-openid-connect#defining-trust-conditions-on-cloud-roles-using-oidc-claims'
|
|
133
|
+
label: 'GitHub Docs — About security hardening with OIDC: defining trust conditions using claims'
|
|
134
|
+
- url: 'https://github.blog/changelog/2026-04-02-github-actions-early-april-2026-updates/'
|
|
135
|
+
label: 'GitHub Changelog — April 2026: Actions OIDC tokens now support repository custom properties'
|
|
136
|
+
- url: 'https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization'
|
|
137
|
+
label: 'GitHub Docs — Managing custom properties for repositories in your organization'
|