Repository navigation
Open
13 / 1613 of 16 issues completedOpen
Check affect of changing default workflow permissions to match GitHub's security recommendations#8178
13 / 1613 of 16 issues completed
Copy link
Labels
Complexity: LargeFeature: Refactor GHARefactoring GitHub actions to fit latest architectural normsRefactoring GitHub actions to fit latest architectural normsLang: GHAGitHub ActionsGitHub Actionsepicrole: back end/devOpsTasks for back-end developersTasks for back-end developerssize: 5ptCan be done in 19-30 hoursCan be done in 19-30 hours
Milestone
Description
Overview
We need to change the permissions for the default GITHUB_TOKEN from read/write to read only per GitHub's recommendation for security best practice.
Details
Before proceeding, read the explainer below.
We need to audit each of our workflows to identify exactly what permissions are needed at each level of the workflow, i.e. overall, job-level, and step-level.
This issue has three objectives:
- First, we will reduce the permissions of the default
GITHUB_TOKEN.- At the top level of each workflow's YAML explicitly state the default token's permissions:
# Set defaults for GITHUB_TOKEN permissions: contents: read issues: read
- Next, we will analyze and test each workflow to check whether additional permissions are required at the step-level to ensure each workflow functions as expected, and note whether the permission requires a PAT.
- At the top level of each workflow's YAML explicitly state the default token's permissions:
- This information will be itemized on a spreadsheet for each step of each workflow.
- see additional comments and "Permissions audit" following
TODO
- after completion of all, reduce default permissions at bottom of https://github.com/hackforla/website/settings/actions
- three action items from Security audit
- admin:org_hook on HACKFORLA_BOT_PA_TOKEN and HACKFORLA_ADMIN_TOKEN — No workflow creates, updates, or deletes webhooks. This scope appears unused on both tokens and can likely be removed after testing.
- repo vs public_repo on HACKFORLA_GRAPHQL_TOKEN — repo grants full access including private repos. If all targeted repos are public, this could be narrowed to public_repo. Requires testing to confirm no operation depends on the broader scope.
- pr-verification.yml — pull_request_target without a repository guard — This is the only pull_request_target workflow and has no if: github.repository == 'hackforla/website' guard. Practical risk is low (HACKFORLA_ADMIN_TOKEN is not available in fork secret stores), but the pattern is inconsistent with other workflows.
Action Items
- Bug fixes to "Member Activity Trigger" workflow- unexpected/ edge cases #8323
- Review Permissions for the "Issue Trigger" workflow #8336
- Review permissions for "Add Update Label Weekly" workflow #8576
- Specify default permissions for
check-closed-issue-for-linked-pr.yml#8579 - Specify default permissions for
codeql-create-issues.yml#8580 - Specify default permissions for
codeql.yml#8581 - Specify default permissions for
flag-issues-unlabeled-after-deletion.yml#8582 - Specify default permissions for
lint-scss.yml#8583 - Specify default permissions for
move-closed-issues.yaml#8584 - Specify default permissions for
pr-verification.yml#8585 - Specify default permissions for
schedule-daily-1100.yml#8586 - Specify default permissions for
update-label-directory.ymlandflag-issues-unlabeled-after-deletion.yml#8587 - Specify default permissions for
vrms-data.yml#8588 - Specify default permissions for
pr-instructions.ymlandwr-pr-instructions.yml#8589 - Specify default permissions for
pull-request-trigger.ymlandwr-pull-request-trigger.yml#8590 - Specify default permissions for
schedule-monthly.ymlandwr-schedule-monthly.yml#8591 - Specify default permissions for
set-pr-labels.yamlandwr-set-pr-labels.yaml#8592
Resources/Instructions
Metadata
Metadata
Assignees
Labels
Complexity: LargeFeature: Refactor GHARefactoring GitHub actions to fit latest architectural normsRefactoring GitHub actions to fit latest architectural normsLang: GHAGitHub ActionsGitHub Actionsepicrole: back end/devOpsTasks for back-end developersTasks for back-end developerssize: 5ptCan be done in 19-30 hoursCan be done in 19-30 hours
Type
Projects
- StatusShow more project fieldsIn progress (actively working)
Activity
HackforLABot commentedon Jun 10, 2025
Hi @t-will-gillis, thank you for taking up this issue! Hfla appreciates you :)
Do let fellow developers know about your:-
i. Availability: (When are you available to work on the issue/answer questions other programmers might have about your issue?)
ii. ETA: (When do you expect this issue to be completed?)
You're awesome!
P.S. - You may not take up another issue until this issue gets merged (or closed). Thanks again :)
t-will-gillis commentedon Sep 20, 2025
Tokens, Secrets, Scopes, & Permissions
Explanation of terms
GITHUB_TOKENand Personal Access Tokens (PATs). PATs themselves are either 'classic' and have broad scopes, or are 'fine-grained' and have targeted scopes. HfLA currently uses the classic PATs, though GitHub recommends that we transition to using fine-grained PATs for better security through "Least Privilege".GITHUB_TOKENalways exists by default in a workflow unless it is preempted bypermissions:(see "Permissions" following) or by a PAT.read:org, which means that a workflow using this token (via a secret) is given a specific permission. In the case of theread:orgscope, the workflow is permitted to "Read org and team membership, read org projects".GITHUB_TOKEN.permissions:to the workflow's YAML.To summarize then:
GITHUB_TOKENor a PAT).GITHUB_TOKENis permitted at different stages of the workflow.Additional notes
GITHUB_TOKEN. These permissions apply by default unless overridden or disabled in the workflow itself.GITHUB_TOKEN, orcontentsandpackages.GITHUB_TOKENusing thepermissions:entry in the workflow's YML. In these cases, each workflow step doing one of these activities must explicitly declare a PAT that is scoped with 'extended' permissions.GITHUB_TOKENapply if no other permissions are declared. Otherwise,permissions:defined at the workflow level override the default repo/org defaults,permissions:defined at the workflow level preempt those at the workflow level (or the default repo/org), and PATs referenced at the step level preempt all others.permissions: contents: read, then during that workflow run theGITHUB_TOKENwill only havecontents:readpermission, even if the default was broader.github-token: ${{ secrets.github.token }}to a step- but this can be done for clarity and/or to avoid ambiguity if a PAT is not used.permissions:if these permissions only repeat the default "Workflow permissions"- but again explicitly stating these permissions can be done for clarity and/or to avoid ambiguity. (And arguably should be done for self-documentation)GITHUB_TOKENpermissions to read only.permissions: contents: read. This statement disables the write permission by omitting it.5 remaining items
t-will-gillis commentedon Mar 28, 2026
Workflow
permissions:auditAlready has a
permissions:blockactivity-trigger.yml— no change neededcodeql-scan-job.yml— no change needed (set at job level)Needs a
permissions:block addedadd-update-label-weekly.ymlAll meaningful operations use a GitHub App token. Default token is only exposed at checkout.
check-closed-issue-for-linked-pr.ymlDefault token runs
check-issue-labels-and-linked-prs.js, which calls the GraphQL API viaclosedByPullRequestsReferenceson an Issue — reads issue and linked PR data only. Reopen, label, and comment operations useHACKFORLA_GRAPHQL_TOKEN.codeql-create-issues.ymlGITHUB_TOKENis used forGET /repos/{owner}/{repo}/code-scanning/alerts(security-events: read) andGET /search/issues(issues: read). Issue creation usesHACKFORLA_ADMIN_TOKEN.codeql.ymlDelegates entirely to
codeql-scan-job.ymlviauses:. The caller's token is what the reusable workflow receives — it must grant at least what the reusable workflow needs.flag-issues-unlabeled-after-deletion.ymlAll operations use
HACKFORLA_GRAPHQL_TOKENandHACKFORLA_BOT_PA_TOKEN. Default token is only exposed at checkout.issue-trigger.ymlDefault token is used by:
check-labels.js—issues.setLabelspost-labels-comment.js—issues.createCommentadd-feature-branch-comment.js—issues.createCommenthide-feature-branch-comment.js— GraphQLminimizeCommentmutationAll require
issues: write.check-label-preliminary-update.jsmakes no API calls (reads only from the event context payload). Team membership check and preliminary comment useHACKFORLA_GRAPHQL_TOKEN.lint-scss.ymlGITHUB_TOKENis passed to super-linter v4, which posts commit status checks. If PR-level annotations fail in future,checks: writemay also be required.move-closed-issues.yamlDefault token runs
sort-closed-issues.js, which reads only from the event context payload — no API calls. Project card operations useHACKFORLA_GRAPHQL_TOKEN.pr-instructions.ymlDefault token runs
create-instruction.js, which callspulls.listFilesto determine which files were modified. No writes — the instruction is saved to an artifact.pr-verification.ymlAll verification logic uses
HACKFORLA_ADMIN_TOKEN. Default token is only exposed at checkout.pull-request-trigger.ymlDefault token runs
check-linked-issue.js, which callsissues.getto verify the linked issue exists and conditionally callsissues.createComment(viapost-issue-comment.js) to notify the PR author. Both use the Issues API;issues: writecovers both.schedule-daily-1100.ymlGITHUB_TOKENis passed asenv.tokentoget-project-data.js, which reads public data only: repo search, repo languages, commit contributors, issue comment contributors. Push operations useHACKFORLA_BOT_PA_TOKENvia checkout.schedule-monthly.ymlAll operations (checkout, contributor queries, team membership changes, auto-commit) use
HACKFORLA_ADMIN_TOKEN. Default token has no meaningful exposure.set-pr-labels.yamlDefault token runs
listIssuesFromPRBody(no API calls — parsescontext.payload.pull_request.body) andlistLabelsFromIssues(issues.listLabelsOnIssue). Labels are written to an artifact, not to the repo.update-label-directory.ymlAll operations (label directory update, Google Sheets POST, auto-commit) use
HACKFORLA_BOT_PA_TOKEN. Default token has no meaningful exposure.vrms-data.ymlData is fetched from
vrms.iovia curl — no GitHub API calls use the default token. Push usesHACKFORLA_BOT_PA_TOKENvia checkout.wr-pr-instructions.ymlDefault token calls
actions.listWorkflowRunArtifactsandactions.downloadArtifactto retrieve the artifact from the triggering workflow run (actions: read), then callsissues.createComment(viapost-issue-comment.js) to post the PR instructions (issues: write).wr-pull-request-trigger.ymlOnly echoes a string. No GitHub API calls.
wr-schedule-monthly.ymlDefault token calls
issues.listForRepoto retrieve the latest issue number (issues: read). Issue creation and closing both useHACKFORLA_BOT_PA_TOKEN.wr-set-pr-labels.yamlDefault token calls
actions.listWorkflowRunArtifactsandactions.downloadArtifact(actions: read), then callsissues.setLabelson the PR number (issues: write— GitHub's Labels API uses the Issues endpoint for both issues and PRs).Secondary flags (PAT scopes)
admin:org_hookonHACKFORLA_BOT_PA_TOKENandHACKFORLA_ADMIN_TOKEN— No workflow creates, updates, or deletes webhooks. This scope appears unused on both tokens and can likely be removed after testing.repovspublic_repoonHACKFORLA_GRAPHQL_TOKEN—repogrants full access including private repos. If all targeted repos are public, this could be narrowed topublic_repo. Requires testing to confirm no operation depends on the broader scope.pr-verification.yml—pull_request_targetwithout a repository guard — This is the onlypull_request_targetworkflow and has noif: github.repository == 'hackforla/website'guard. Practical risk is low (HACKFORLA_ADMIN_TOKENis not available in fork secret stores), but the pattern is inconsistent with other workflows.check-closed-issue-for-linked-pr.yml#8579codeql-create-issues.yml#8580codeql.yml#8581flag-issues-unlabeled-after-deletion.yml#8582lint-scss.yml#8583move-closed-issues.yaml#8584pr-verification.yml#8585schedule-daily-1100.yml#8586update-label-directory.ymlandflag-issues-unlabeled-after-deletion.yml#8587vrms-data.yml#8588pr-instructions.ymlandwr-pr-instructions.yml#8589pull-request-trigger.ymlandwr-pull-request-trigger.yml#8590schedule-monthly.ymlandwr-schedule-monthly.yml#8591set-pr-labels.yamlandwr-set-pr-labels.yaml#8592