GitHub Actions PR-Approval Permission Audit
Find every repo where GitHub Actions can create and approve pull requests — a known way to
bypass required reviews — and report it security-first. false is the secure default; true is
an exposure to justify per repo. Read-only: this skill never changes settings; it prints the
exact command for you to run. See references/openssf.md for the why + sources.
Setup Check
Run gh auth status — if not authenticated, output:
⚠️ gh CLI not authenticated. Run: gh auth login
and stop.
Step 1: Resolve scope
--owner <name>: audit that account. Otherwise:OWNER=$(gh api user --jq .login).--allow <repo,repo>: comma-separated repos you INTENTIONALLY allow to have the settingtrue(e.g. a repo whose CI legitimately opens PRs viaGITHUB_TOKEN). Anything not listed is expected to befalse.
List repos (skip archived; they can't be changed):
gh repo list "$OWNER" --no-archived --limit 200 --json name --jq '.[].name'
Step 2: Read the setting per repo
For each repo:
gh api "repos/$OWNER/$REPO/actions/permissions/workflow" \
--jq '[.default_workflow_permissions, (.can_approve_pull_request_reviews|tostring)] | @tsv'
The second field is the audited flag.
Step 3: Classify
| can_approve | in --allow? | Status |
|---|---|---|
true |
no | RISK(unexpected) — review-bypass exposure |
true |
yes | OK(allowlisted) — intentional |
false |
— | OK(secure-default) |
| (error) | — | ERR(skip) — no access / archived |
Step 4: Report
# Actions PR-Approval Audit — <owner> — <DATE>
> Generated by github-flow-kit/gh-pr-perm-audit
> `false` = secure default. `true` = a workflow can self-approve PRs and bypass required reviews.
| Repo | default perms | can approve PR | Status |
|---|---|---|---|
| <repo> | read | false | OK(secure-default) |
| <repo> | read | true | 🔴 RISK(unexpected) |
## 🔴 Exposed repos (un-allowlisted `true`): <N>
- <repo> — a workflow here can approve its own PR and merge past required reviews.
Step 5: Recommend (you run the mutation — never auto-applied)
For each RISK repo, print the secure-default revert command and let the user run it:
# Revert to the secure default (recommended):
gh api -X PUT repos/<owner>/<repo>/actions/permissions/workflow \
-f default_workflow_permissions=read -F can_approve_pull_request_reviews=false
If a repo legitimately needs Actions to create (not approve) PRs, prefer leaving this false
and using a dedicated GitHub App / fine-grained PAT for PR creation, or require a review from
someone other than the actor (so a self-approval still can't merge). Only enable intentionally:
gh api -X PUT repos/<owner>/<repo>/actions/permissions/workflow \
-f default_workflow_permissions=read -F can_approve_pull_request_reviews=true
Summary Output
✅ Actions PR-Approval Audit — <N> repos
🔴 RISK (un-allowlisted true) : <n>
🟢 secure-default (false) : <n>
⚪ allowlisted true : <n>
📋 Next: run the revert command above for each RISK repo, or add it to --allow if intentional.
⭐ Found this useful? Star → https://github.com/thinkyou0714/github-flow-kit
Error Handling
| Code | Condition | Exit |
|---|---|---|
| GP-001 | gh not authenticated | 2 |
| GP-002 | owner has no repos | 0 |
| GP-003 | per-repo API error (no admin / archived) | skip that repo, continue |
| GP-004 | API rate limited | stop, show reset time |