From c8a8f40399f2952fdb0a97ab22e987f0242d6ba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Sj=C3=B6gren?= Date: Fri, 22 May 2026 15:56:00 +0000 Subject: [PATCH 1/9] Add recommendation regarding runner groups and labels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Sjögren --- .../recommendations/actions-security/index.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/content/library/application-security/recommendations/actions-security/index.md b/content/library/application-security/recommendations/actions-security/index.md index 8e3a85f..9090ce5 100644 --- a/content/library/application-security/recommendations/actions-security/index.md +++ b/content/library/application-security/recommendations/actions-security/index.md @@ -1,11 +1,11 @@ --- # SPDX-FileCopyrightText: GitHub and The Project Authors # SPDX-License-Identifier: MIT -draft: false # Set to false when ready to publish +draft: true # Set to false when ready to publish title: 'Securing GitHub Actions Workflows' publishDate: 2024-08-16 params: - authors: [{ name: 'Greg Mohler', handle: 'callmegreg' }, { name: 'Kitty Chiu', handle: 'kittychiu' }] + authors: [{ name: 'Greg Mohler', handle: 'callmegreg' }, { name: 'Kitty Chiu', handle: 'kittychiu' }, { name: 'Thomas Sjögren', handle: 'konstruktoid' }] # Classifications of the framework to drive key concepts, design principles, and architectural best practices pillars: @@ -90,6 +90,7 @@ To secure GitHub Actions workflows, consider the following strategies: 10. **Use `head.sha` instead of `head.ref`**: Where possible, reference by commit SHA instead of a user-provided branch name or tag (ref), especially in sensitive contexts (such as `run` steps). If require, use environment variable to store `head.ref` and reference it to prevent injection attack. 11. **Use caution with public repositories**: Anyone can suggest changes to public repositories. Review workflow triggers, and never use self-hosted runners with public repositories. 12. **Restrict allowed actions**: Use the [*Allow enterprise, and select non-enterprise, actions and reusable workflows*](https://docs.github.com/en/enterprise-cloud@latest/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-github-actions-in-your-enterprise#controlling-access-to-public-actions-and-reusable-workflows) setting to control which actions can run. +13. **Segregate runners**: Use organizational runner groups and labels to separate high-privilege runners (with access to secrets, sensitive resources or host access) from low-privilege runners. ## Assumptions and preconditions @@ -126,6 +127,7 @@ Repository rulesets provide a strong defensive layer that complements workflow-l - [Require status checks to pass before merging](https://docs.github.com/en/enterprise-cloud@latest/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets#require-status-checks-to-pass-before-merging): Ensure automated validation checks pass before merging. - [Require code scanning results](https://docs.github.com/en/enterprise-cloud@latest/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets#require-code-scanning-results): Identify security vulnerabilities before merge. - [Require signed commits](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets#require-signed-commits): Ensure all commits are signed to prove who authored them and that they haven't been modified. +- [Require workflows to pass before merging](https://docs.github.com/en/enterprise-cloud@latest/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets#require-workflows-to-pass-before-merging): Ensure organizational or enterprise-level requirements for workflows are met before merging. This could be a workflow that checks for required labels, validates commit messages, or performs other organizational policy checks. - Restrict bypass permissions: Limit bypass capabilities to emergencies and monitor via audit logs. ### Implement least privilege for workflow permissions @@ -257,6 +259,10 @@ The [allowed actions and reusable workflows setting](https://docs.github.com/en/ Consider defining the list of allowed actions using policy as code (e.g., via Terraform or the REST API) to establish a request/approval process, track changes for audit purposes, and improve visibility into which actions are allowed. +### Segregate runners + +Use [runner groups](https://docs.github.com/en/actions/concepts/runners/runner-groups) and [labels](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/apply-labels) to separate high-privilege runners (with access to sensitive resources or direct host access) from low-privilege runners. This segregation allows for more granular control over [which repositories can access different runners](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/manage-access#changing-which-repositories-can-access-a-runner-group) and which [jobs can access specific runners](https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/choose-the-runner-for-a-job), reducing the risk of a compromised or misconfigured workflow gaining access to sensitive resources. For example, create a runner group for container image build runners or a runner group with runners having access to restricted networks and restrict its members to only the repositories that require those privileges, place unprivileged tasks such as linting and static analysis in a separate runner group with no access to secrets or sensitive resources. + ## Additional solution detail and trade-offs to consider ### Pinning actions based on a version tag From b9746225bfb1ca51d6a7c44fa93c5688b6795d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Sj=C3=B6gren?= Date: Fri, 22 May 2026 16:06:21 +0000 Subject: [PATCH 2/9] adjust to documentation terminology MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Sjögren --- .../recommendations/actions-security/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/library/application-security/recommendations/actions-security/index.md b/content/library/application-security/recommendations/actions-security/index.md index 9090ce5..b1c57d3 100644 --- a/content/library/application-security/recommendations/actions-security/index.md +++ b/content/library/application-security/recommendations/actions-security/index.md @@ -90,7 +90,7 @@ To secure GitHub Actions workflows, consider the following strategies: 10. **Use `head.sha` instead of `head.ref`**: Where possible, reference by commit SHA instead of a user-provided branch name or tag (ref), especially in sensitive contexts (such as `run` steps). If require, use environment variable to store `head.ref` and reference it to prevent injection attack. 11. **Use caution with public repositories**: Anyone can suggest changes to public repositories. Review workflow triggers, and never use self-hosted runners with public repositories. 12. **Restrict allowed actions**: Use the [*Allow enterprise, and select non-enterprise, actions and reusable workflows*](https://docs.github.com/en/enterprise-cloud@latest/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-github-actions-in-your-enterprise#controlling-access-to-public-actions-and-reusable-workflows) setting to control which actions can run. -13. **Segregate runners**: Use organizational runner groups and labels to separate high-privilege runners (with access to secrets, sensitive resources or host access) from low-privilege runners. +13. **Segregate runners**: Use runner groups and labels to separate high-privilege runners (with access to secrets, sensitive resources or host access) from low-privilege runners. ## Assumptions and preconditions From 72c1fa77c175e4b742fddff7af8e75321cecc124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Sj=C3=B6gren?= Date: Fri, 22 May 2026 16:15:54 +0000 Subject: [PATCH 3/9] split into shorter sentences MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Sjögren --- .../recommendations/actions-security/index.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/content/library/application-security/recommendations/actions-security/index.md b/content/library/application-security/recommendations/actions-security/index.md index b1c57d3..20af5f4 100644 --- a/content/library/application-security/recommendations/actions-security/index.md +++ b/content/library/application-security/recommendations/actions-security/index.md @@ -261,7 +261,15 @@ Consider defining the list of allowed actions using policy as code (e.g., via Te ### Segregate runners -Use [runner groups](https://docs.github.com/en/actions/concepts/runners/runner-groups) and [labels](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/apply-labels) to separate high-privilege runners (with access to sensitive resources or direct host access) from low-privilege runners. This segregation allows for more granular control over [which repositories can access different runners](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/manage-access#changing-which-repositories-can-access-a-runner-group) and which [jobs can access specific runners](https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/choose-the-runner-for-a-job), reducing the risk of a compromised or misconfigured workflow gaining access to sensitive resources. For example, create a runner group for container image build runners or a runner group with runners having access to restricted networks and restrict its members to only the repositories that require those privileges, place unprivileged tasks such as linting and static analysis in a separate runner group with no access to secrets or sensitive resources. +Use [runner groups](https://docs.github.com/en/actions/concepts/runners/runner-groups) and [labels](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/apply-labels) to separate high-privilege runners from low-privilege runners. High-privilege runners may have access to sensitive resources or direct host access, while low-privilege runners should not. + +This separation provides more granular control over [which repositories can access different runners](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/manage-access#changing-which-repositories-can-access-a-runner-group) and which [jobs can access specific runners](https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/choose-the-runner-for-a-job). It also reduces the risk that a compromised or misconfigured workflow could gain access to sensitive resources. + +For example, you could create: + +- A runner group for container image build runners, limited to only the repositories that require those privileges. +- A runner group for runners with access to restricted networks. +- A separate low-privilege runner group for tasks such as linting and static analysis, with no access to secrets or sensitive resources. ## Additional solution detail and trade-offs to consider From d0109d78d432826660e215f1cdf3c243618851c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Sj=C3=B6gren?= Date: Wed, 27 May 2026 08:48:22 +0000 Subject: [PATCH 4/9] set draft: false MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Sjögren --- .../recommendations/actions-security/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/library/application-security/recommendations/actions-security/index.md b/content/library/application-security/recommendations/actions-security/index.md index 20af5f4..ccd4f77 100644 --- a/content/library/application-security/recommendations/actions-security/index.md +++ b/content/library/application-security/recommendations/actions-security/index.md @@ -1,7 +1,7 @@ --- # SPDX-FileCopyrightText: GitHub and The Project Authors # SPDX-License-Identifier: MIT -draft: true # Set to false when ready to publish +draft: false # Set to false when ready to publish title: 'Securing GitHub Actions Workflows' publishDate: 2024-08-16 params: From 2a3e165669aa756e4925be02a3831ea072fd14cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Sj=C3=B6gren?= Date: Wed, 27 May 2026 13:03:46 +0000 Subject: [PATCH 5/9] replace and with or MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Sjögren --- .../recommendations/actions-security/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/library/application-security/recommendations/actions-security/index.md b/content/library/application-security/recommendations/actions-security/index.md index ccd4f77..f833ab4 100644 --- a/content/library/application-security/recommendations/actions-security/index.md +++ b/content/library/application-security/recommendations/actions-security/index.md @@ -261,7 +261,7 @@ Consider defining the list of allowed actions using policy as code (e.g., via Te ### Segregate runners -Use [runner groups](https://docs.github.com/en/actions/concepts/runners/runner-groups) and [labels](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/apply-labels) to separate high-privilege runners from low-privilege runners. High-privilege runners may have access to sensitive resources or direct host access, while low-privilege runners should not. +Use [runner groups](https://docs.github.com/en/actions/concepts/runners/runner-groups) or [labels](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/apply-labels) to separate high-privilege runners from low-privilege runners. High-privilege runners may have access to sensitive resources or direct host access, while low-privilege runners should not. This separation provides more granular control over [which repositories can access different runners](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/manage-access#changing-which-repositories-can-access-a-runner-group) and which [jobs can access specific runners](https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/choose-the-runner-for-a-job). It also reduces the risk that a compromised or misconfigured workflow could gain access to sensitive resources. From 114a9e605156a67ec725dd1409fdba4bf345b61f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Sj=C3=B6gren?= Date: Wed, 27 May 2026 16:29:50 +0200 Subject: [PATCH 6/9] Update content/library/application-security/recommendations/actions-security/index.md Co-authored-by: Ken Muse --- .../recommendations/actions-security/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/library/application-security/recommendations/actions-security/index.md b/content/library/application-security/recommendations/actions-security/index.md index f833ab4..aabe133 100644 --- a/content/library/application-security/recommendations/actions-security/index.md +++ b/content/library/application-security/recommendations/actions-security/index.md @@ -87,7 +87,7 @@ To secure GitHub Actions workflows, consider the following strategies: 7. **Avoid workflow injection**: Sanitize user input and avoid using expression values in sensitive contexts (such as `run` steps) to prevent injection attacks. 8. **Avoid `pull_request_target`**: This event runs workflows in the base repository context with elevated permissions. This can enable malicious execution using pull requests from forks. 9. **Secure `workflow_run` workflows**: Treat all artifacts, code, and data from triggering workflows as untrusted. Use [branch filters](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#limiting-your-workflow-to-run-based-on-branches) and validate all inputs. -10. **Use `head.sha` instead of `head.ref`**: Where possible, reference by commit SHA instead of a user-provided branch name or tag (ref), especially in sensitive contexts (such as `run` steps). If require, use environment variable to store `head.ref` and reference it to prevent injection attack. +10. **Use `head.sha` instead of `head.ref`**: Where possible, reference by commit SHA instead of a user-provided branch name or tag (ref), especially in sensitive contexts (such as `run` steps). If required, use environment variable to store `head.ref` and reference it to prevent injection attack. 11. **Use caution with public repositories**: Anyone can suggest changes to public repositories. Review workflow triggers, and never use self-hosted runners with public repositories. 12. **Restrict allowed actions**: Use the [*Allow enterprise, and select non-enterprise, actions and reusable workflows*](https://docs.github.com/en/enterprise-cloud@latest/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-github-actions-in-your-enterprise#controlling-access-to-public-actions-and-reusable-workflows) setting to control which actions can run. 13. **Segregate runners**: Use runner groups and labels to separate high-privilege runners (with access to secrets, sensitive resources or host access) from low-privilege runners. From 1c1845d07fd7b326ed06b0eab9995decc0f1d824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Sj=C3=B6gren?= Date: Thu, 28 May 2026 08:48:51 +0000 Subject: [PATCH 7/9] rewording regarding secrets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Sjögren --- .../recommendations/actions-security/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/library/application-security/recommendations/actions-security/index.md b/content/library/application-security/recommendations/actions-security/index.md index aabe133..f8ddadd 100644 --- a/content/library/application-security/recommendations/actions-security/index.md +++ b/content/library/application-security/recommendations/actions-security/index.md @@ -90,7 +90,7 @@ To secure GitHub Actions workflows, consider the following strategies: 10. **Use `head.sha` instead of `head.ref`**: Where possible, reference by commit SHA instead of a user-provided branch name or tag (ref), especially in sensitive contexts (such as `run` steps). If required, use environment variable to store `head.ref` and reference it to prevent injection attack. 11. **Use caution with public repositories**: Anyone can suggest changes to public repositories. Review workflow triggers, and never use self-hosted runners with public repositories. 12. **Restrict allowed actions**: Use the [*Allow enterprise, and select non-enterprise, actions and reusable workflows*](https://docs.github.com/en/enterprise-cloud@latest/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-github-actions-in-your-enterprise#controlling-access-to-public-actions-and-reusable-workflows) setting to control which actions can run. -13. **Segregate runners**: Use runner groups and labels to separate high-privilege runners (with access to secrets, sensitive resources or host access) from low-privilege runners. +13. **Segregate runners**: Use runner groups and labels to separate high-privilege runners from low-privilege runners, and restrict high-privilege runner groups to selected repositories or workflows to reduce exposure to secrets and sensitive resources. ## Assumptions and preconditions From ed08520c64ae68a06237cc36ba31278899c2dfa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Sj=C3=B6gren?= Date: Thu, 28 May 2026 08:56:30 +0000 Subject: [PATCH 8/9] reword secret access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Sjögren --- .../recommendations/actions-security/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/library/application-security/recommendations/actions-security/index.md b/content/library/application-security/recommendations/actions-security/index.md index f8ddadd..5a0868b 100644 --- a/content/library/application-security/recommendations/actions-security/index.md +++ b/content/library/application-security/recommendations/actions-security/index.md @@ -269,7 +269,7 @@ For example, you could create: - A runner group for container image build runners, limited to only the repositories that require those privileges. - A runner group for runners with access to restricted networks. -- A separate low-privilege runner group for tasks such as linting and static analysis, with no access to secrets or sensitive resources. +- A separate runner group for low-privilege tasks such as linting and static analysis, used in repositories where secrets are either absent entirely or isolated in separate environments. ## Additional solution detail and trade-offs to consider From 7df4b2b961668ac9fe1b8f99a92c41a3d8950d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Sj=C3=B6gren?= Date: Thu, 28 May 2026 09:04:21 +0000 Subject: [PATCH 9/9] just mention sensitive resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Sjögren --- .../recommendations/actions-security/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/library/application-security/recommendations/actions-security/index.md b/content/library/application-security/recommendations/actions-security/index.md index 5a0868b..e901057 100644 --- a/content/library/application-security/recommendations/actions-security/index.md +++ b/content/library/application-security/recommendations/actions-security/index.md @@ -90,7 +90,7 @@ To secure GitHub Actions workflows, consider the following strategies: 10. **Use `head.sha` instead of `head.ref`**: Where possible, reference by commit SHA instead of a user-provided branch name or tag (ref), especially in sensitive contexts (such as `run` steps). If required, use environment variable to store `head.ref` and reference it to prevent injection attack. 11. **Use caution with public repositories**: Anyone can suggest changes to public repositories. Review workflow triggers, and never use self-hosted runners with public repositories. 12. **Restrict allowed actions**: Use the [*Allow enterprise, and select non-enterprise, actions and reusable workflows*](https://docs.github.com/en/enterprise-cloud@latest/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-github-actions-in-your-enterprise#controlling-access-to-public-actions-and-reusable-workflows) setting to control which actions can run. -13. **Segregate runners**: Use runner groups and labels to separate high-privilege runners from low-privilege runners, and restrict high-privilege runner groups to selected repositories or workflows to reduce exposure to secrets and sensitive resources. +13. **Segregate runners**: Use runner groups and labels to separate high-privilege runners from low-privilege runners, and restrict high-privilege runner groups to selected repositories or workflows to reduce exposure to sensitive resources. ## Assumptions and preconditions @@ -261,7 +261,7 @@ Consider defining the list of allowed actions using policy as code (e.g., via Te ### Segregate runners -Use [runner groups](https://docs.github.com/en/actions/concepts/runners/runner-groups) or [labels](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/apply-labels) to separate high-privilege runners from low-privilege runners. High-privilege runners may have access to sensitive resources or direct host access, while low-privilege runners should not. +Use [runner groups](https://docs.github.com/en/actions/concepts/runners/runner-groups) or [labels](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/apply-labels) to separate high-privilege runners from low-privilege runners. High-privilege runners may have access to sensitive resources, while low-privilege runners should not. This separation provides more granular control over [which repositories can access different runners](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/manage-access#changing-which-repositories-can-access-a-runner-group) and which [jobs can access specific runners](https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/choose-the-runner-for-a-job). It also reduces the risk that a compromised or misconfigured workflow could gain access to sensitive resources.