GitHub/Repository Security/GitHub Workflows & Actions: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
(formatting fix)
(add a guideline about caching)
 
(17 intermediate revisions by 3 users not shown)
Line 10: Line 10:


# Protect all workflows by requiring code reviews from folks who have familiarized themselves with the security issues of workflows.
# Protect all workflows by requiring code reviews from folks who have familiarized themselves with the security issues of workflows.
# Perform a code review for any additional scripts that you run in the workflows, not only the commands which are directly included in the workflow file. Look for any commands vulnerable to code injection
# Use scanning to detect problems and lack of best practices.
# Use scanning to detect problems and lack of best practices.
# Treat GitHub actions as you would any 3rd party library shipped with your product.
# Treat GitHub actions as you would any 3rd party library shipped with your product.
Line 15: Line 16:
#* Use mitigations where appropriate.
#* Use mitigations where appropriate.
# As always, enforce “least privilege” wherever possible.
# As always, enforce “least privilege” wherever possible.
#* Explicitly set "<code>persist-credentials: false</code>" when using the "<code>actions/checkout</code>" action. (Prevent hidden state.)
#* Explicitly unset <tt>GITHUB_TOKEN</tt> when not needed at the workflow or job level with "<code>permissions: {}</code>".
# When configuring automatic merging or making exceptions in the workflow for Dependabot, make sure to validate the user and not the actor in the Github action.
#* Use the check "<code>github.event.pull_request.user.login == 'dependabot[bot]'</code>" instead of "<code>github.actor == 'dependabot[bot]'</code>"
'''Additionally''', following a recent supply-chain attack involving the '''reviewdog/action-setup''' GitHub Action (March 2025), it is strongly recommended to:
* Always pin third-party GitHub Actions to specific, immutable commit SHAs rather than mutable tags such as ("<code>@v1</code>" or "<code>@latest</code>") to avoid executing malicious code introduced via compromised tags.
* Regularly audit workflow files and execution logs for suspicious or unexpected behavior, particularly encoded or obfuscated outputs that may indicate secret leakage.
* Immediately rotate any credentials (such as Personal Access Tokens, API keys, or other secrets) if you suspect exposure.
* Promptly update any third-party actions to their latest patched versions, and verify their integrity before use.


== Resources and tools ==
== Resources and tools ==
Line 23: Line 35:


* Read GitHub’s [https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions security hardening for actions].
* Read GitHub’s [https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions security hardening for actions].
* Always reduce permissions to the minimum needed, using the [https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#defining-access-for-the-github_token-scopes <code>permissions</code> parameter]
* Always reduce permissions to the minimum needed, using the [https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#defining-access-for-the-github_token-scopes <code>permissions</code> parameter]. ([https://github.blog/changelog/2021-04-20-github-actions-control-permissions-for-github_token/ more info])
* More details on how those vulnerabilities work, in a 3 part section from github:
* More details on how those vulnerabilities work, in a 3 part section from github:
** [https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ Part 1] - Preventing Pwn requests
** [https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ Part 1] - Preventing Pwn requests
Line 29: Line 41:
** [https://securitylab.github.com/research/github-actions-building-blocks/ Part 3] - Understanding the GitHub Action Supply Chain
** [https://securitylab.github.com/research/github-actions-building-blocks/ Part 3] - Understanding the GitHub Action Supply Chain
* Understand implications of running workflows on the [https://docs.github.com/en/enterprise-cloud@latest/actions/using-workflows/events-that-trigger-workflows#pull_request_target <code>pull_request_target</code> event] (read the <code>Warning</code> section).
* Understand implications of running workflows on the [https://docs.github.com/en/enterprise-cloud@latest/actions/using-workflows/events-that-trigger-workflows#pull_request_target <code>pull_request_target</code> event] (read the <code>Warning</code> section).
* [https://www.synacktiv.com/publications/github-actions-exploitation-untrusted-input Real Life Misconfiguration] examples (2024-07-02)
* [https://www.synacktiv.com/publications/github-actions-exploitation-dependabot Exploiting Dependabot] (2024-08-06)
* [https://openssf.org/blog/2024/08/12/mitigating-attack-vectors-in-github-workflows/ Mitigating Attack Vectors in GitHub Workflows] (2024-08-12)


=== Scanning Tools ===
=== Scanning Tools ===
Line 36: Line 51:
** “Must correct” findings as of 2024-06-12 include
** “Must correct” findings as of 2024-06-12 include
*** [https://github.com/ossf/scorecard/blob/main/docs/checks.md#dangerous-workflow Dangerous Workflow]
*** [https://github.com/ossf/scorecard/blob/main/docs/checks.md#dangerous-workflow Dangerous Workflow]
** '''''Note:''''' While the action has been approved for use in all organizations, it may not yet have been added to an organization you are working in. If you receive a message that the action is not available, please follow [[GitHub#github_actions|these instructions]] to have it added.
** '''''Note:''''' While the <code>ossf/scorecard-action</code> (and [https://github.com/ossf/scorecard-action?tab=readme-ov-file#restrictions-on-the-job-containing-ossfscorecard-action its dependency] <code>step-security/harden-runner</code>) been approved for use in all organizations, it may not yet have been added to an organization you are working in. If you receive a message that the action is not available, please follow [[GitHub#github_actions|these instructions]] to have it added.
* [https://github.com/synacktiv/octoscan Synacktiv's octoscan], which can check workflows on all branches locally.


=== Supply Chain Hygiene ===
=== Supply Chain Hygiene ===
Line 57: Line 73:
** Don’t forget to audit dependencies
** Don’t forget to audit dependencies
** Consider permitting only a specific revision (instead of relying on a version tag)
** Consider permitting only a specific revision (instead of relying on a version tag)
== Recommendations ==
=== Manage Sensitive Data Securely ===
Prevent sensitive information from inadvertently being included in your Docker images:
* '''Exclude Environment Files''': Add <code>.env</code> files to your <code>.dockerignore</code> to ensure environment-specific configurations and secrets are not part of the Docker image.
<syntaxhighlight lang="bash">
.env
</syntaxhighlight>
* '''Use Docker Secrets''': Leverage Docker's secret management tools to handle sensitive data such as passwords, tokens, and SSH keys. This approach ensures sensitive information is not exposed within Docker images or runtime commands.
=== Set Appropriate Permissions for <code>GITHUB_TOKEN</code> ===
When using GitHub Actions to build Docker images, manage the <code>GITHUB_TOKEN</code> permissions carefully to prevent unauthorized access:
* '''Restrict Token Permissions''': Always enforce the principle of least privilege when configuring <code>GITHUB_TOKEN</code> permissions. 
Configure the <code>GITHUB_TOKEN</code> with only the minimum permissions required (e.g., <code>read-all</code>) to limit its access scope, minimizing security risks associated with token misuse. 
You can set this under '''Settings → Actions → General''', then under '''Workflow permissions''' select '''Read repository contents and packages permissions'''.
* Explicitly set <code>persist-credentials: false</code> when using the <code>actions/checkout</code> action to prevent credentials from persisting unintentionally and avoid hidden state within workflows:
<syntaxhighlight lang="yaml">
- uses: actions/checkout@v4
  with:
    persist-credentials: false
</syntaxhighlight>
* Explicitly unset <code>GITHUB_TOKEN</code> permissions when not required at the workflow or job level by specifying:
<syntaxhighlight lang="yaml">
permissions: {}
</syntaxhighlight>
If some permissions are required, set them to the minimum necessary.
=== Implement Secure Configuration ===
* '''Perform Secure dependabot Validation''': When configuring workflows for automated merging or handling Dependabot pull requests, always validate the user initiating the request instead of the actor. For example, use:
<syntaxhighlight lang="yaml">
github.event.pull_request.user.login == 'dependabot[bot]'
</syntaxhighlight>
rather than:
<syntaxhighlight lang="yaml">
github.actor == 'dependabot[bot]'
</syntaxhighlight>
This ensures the action reliably authenticates the intended user, reducing the risk of impersonation or malicious actions.
* '''Disable Unnecessary Jobs''': If certain GitHub Actions jobs, such as those publishing Docker images, are not required, disable them to reduce the attack surface and prevent unintended operations.
* '''Avoid Storing Tokens in Git''': Ensure tokens are not stored in your Git repository by adding relevant patterns to your <code>.gitignore</code> file and using GitHub Actions secrets to securely manage sensitive information.
*'''Avoid Using Caching for Privileged Jobs''': Caching in Github Actions is vulnerable to [https://adnanthekhan.com/2024/05/06/the-monsters-in-your-build-cache-github-actions-cache-poisoning/ cache poisoning]. If a code injection vulnerability is present in any of the workflows (whether they run in a privileged context or not), and you use caching in a higher privileged workflow, then code injection can be exploited to poison the cache and steal higher value secrets and credentials.
=== Docker Security Best Practices ===
To enhance the security and efficiency of your Docker workflows, consider implementing the following best practices:
==== Utilize a <code>.dockerignore</code> File ====
A well-configured <code>.dockerignore</code> file is essential for optimizing your Docker build process. It functions similarly to a <code>.gitignore</code> file by specifying which files and directories should be excluded from the build context. This practice reduces the build size, leading to faster builds, and prevents sensitive or unnecessary files from being included in your Docker images.
* '''Exclude Version Control Directories''': Add <code>.git/</code> to your <code>.dockerignore</code> file to prevent the inclusion of Git configuration which could include the authentication token, history and metadata in your Docker image, thereby reducing image size and avoiding potential exposure of sensitive information.
<syntaxhighlight lang="bash">
.git/
</syntaxhighlight>
* '''Exclude Node Modules''': For Node.js projects, exclude the <code>node_modules/</code> directory to prevent unnecessary files from being added to the Docker image.
<syntaxhighlight lang="bash">
node_modules/
</syntaxhighlight>
* '''Exclude Temporary and Log Files''': Prevent temporary files and logs from being included in the image by adding patterns like:
<syntaxhighlight lang="bash">
*.log
*.tmp
</syntaxhighlight>
* '''Exclude GitHub Actions Credential Files''': Exclude credential JSON files (<code>gha-creds-*.json</code>) used in GitHub Actions workflows to avoid inadvertently including authentication data in Docker images. Alternatively, build Docker images before running the <code>google-github-actions/auth@v2</code> step in your GitHub workflow, ensuring these credentials aren't present in your build context.
<syntaxhighlight lang="bash">
gha-creds-*.json
</syntaxhighlight>
===== Sample <code>.dockerignore</code> file =====
<syntaxhighlight lang="bash">
.git/
node_modules/
*.log
*.tmp
gha-creds-*.json
</syntaxhighlight>

Latest revision as of 09:41, 19 May 2025

GitHub Workflows and Actions

GitHub Workflows and Actions provide tremendous value, but also are subject to non-obvious abuse. They:

  • are a “hybrid language”
  • have non-obvious variable expansion semantics
  • inherit (invisible) global state

As such, they take a bit of learning to utilize in a secure manner. The following steps are part of “best practices” for using GitHub Workflows, and are strongly recommended for all sensitive repos.

  1. Protect all workflows by requiring code reviews from folks who have familiarized themselves with the security issues of workflows.
  2. Perform a code review for any additional scripts that you run in the workflows, not only the commands which are directly included in the workflow file. Look for any commands vulnerable to code injection
  3. Use scanning to detect problems and lack of best practices.
  4. Treat GitHub actions as you would any 3rd party library shipped with your product.
    • Examine the supply chain!
    • Use mitigations where appropriate.
  5. As always, enforce “least privilege” wherever possible.
    • Explicitly set "persist-credentials: false" when using the "actions/checkout" action. (Prevent hidden state.)
    • Explicitly unset GITHUB_TOKEN when not needed at the workflow or job level with "permissions: {}".
  6. When configuring automatic merging or making exceptions in the workflow for Dependabot, make sure to validate the user and not the actor in the Github action.
    • Use the check "github.event.pull_request.user.login == 'dependabot[bot]'" instead of "github.actor == 'dependabot[bot]'"

Additionally, following a recent supply-chain attack involving the reviewdog/action-setup GitHub Action (March 2025), it is strongly recommended to:

  • Always pin third-party GitHub Actions to specific, immutable commit SHAs rather than mutable tags such as ("@v1" or "@latest") to avoid executing malicious code introduced via compromised tags.
  • Regularly audit workflow files and execution logs for suspicious or unexpected behavior, particularly encoded or obfuscated outputs that may indicate secret leakage.
  • Immediately rotate any credentials (such as Personal Access Tokens, API keys, or other secrets) if you suspect exposure.
  • Promptly update any third-party actions to their latest patched versions, and verify their integrity before use.

Resources and tools

There are a number of ways to implement the recommendations above. Here are some suggestions - other tools may be available and a better fit. (See requesting installations for more information.)

Learning about Workflow security issues

Scanning Tools

  • OSSF Scorecard action will detected unsafe workflows. Note that some findings are “stricter” than our recommendations. Please evaluate the benefit before adopting a “get to zero reported findings”. Recommendations:
    • Set publish_results to false. This is a manual step if you follow the installation instructions.
    • “Must correct” findings as of 2024-06-12 include
    • Note: While the ossf/scorecard-action (and its dependency step-security/harden-runner) been approved for use in all organizations, it may not yet have been added to an organization you are working in. If you receive a message that the action is not available, please follow these instructions to have it added.
  • Synacktiv's octoscan, which can check workflows on all branches locally.

Supply Chain Hygiene

How much effort to put into supply chain checks for 3rd party actions is directly related to how much you can trust the providers. And that includes trusting the process of the providers to ensure that level of trust continues to be warranted over time.

Some indications that an action deserves some trust include:

Unless you have some sort of contractual protection, you probably want to do the following for any action:

  • Enforce least privilege – only provide a token that can do what the action should require to perform the advertised function.
  • Harden the execution environment.
    • use tooling to block internet access, unless specifically needed
    • refactor jobs to minimize access to unneeded tokens, resources, and services
  • Audit the code for reasonableness before first time use
    • Audit the changes before taking a version update
    • Don’t forget to audit dependencies
    • Consider permitting only a specific revision (instead of relying on a version tag)

Recommendations

Manage Sensitive Data Securely

Prevent sensitive information from inadvertently being included in your Docker images:

  • Exclude Environment Files: Add .env files to your .dockerignore to ensure environment-specific configurations and secrets are not part of the Docker image.
.env
  • Use Docker Secrets: Leverage Docker's secret management tools to handle sensitive data such as passwords, tokens, and SSH keys. This approach ensures sensitive information is not exposed within Docker images or runtime commands.

Set Appropriate Permissions for GITHUB_TOKEN

When using GitHub Actions to build Docker images, manage the GITHUB_TOKEN permissions carefully to prevent unauthorized access:

  • Restrict Token Permissions: Always enforce the principle of least privilege when configuring GITHUB_TOKEN permissions.

Configure the GITHUB_TOKEN with only the minimum permissions required (e.g., read-all) to limit its access scope, minimizing security risks associated with token misuse. You can set this under Settings → Actions → General, then under Workflow permissions select Read repository contents and packages permissions.

  • Explicitly set persist-credentials: false when using the actions/checkout action to prevent credentials from persisting unintentionally and avoid hidden state within workflows:
- uses: actions/checkout@v4
  with:
    persist-credentials: false
  • Explicitly unset GITHUB_TOKEN permissions when not required at the workflow or job level by specifying:
permissions: {}

If some permissions are required, set them to the minimum necessary.

Implement Secure Configuration

  • Perform Secure dependabot Validation: When configuring workflows for automated merging or handling Dependabot pull requests, always validate the user initiating the request instead of the actor. For example, use:
github.event.pull_request.user.login == 'dependabot[bot]'

rather than:

github.actor == 'dependabot[bot]'

This ensures the action reliably authenticates the intended user, reducing the risk of impersonation or malicious actions.

  • Disable Unnecessary Jobs: If certain GitHub Actions jobs, such as those publishing Docker images, are not required, disable them to reduce the attack surface and prevent unintended operations.
  • Avoid Storing Tokens in Git: Ensure tokens are not stored in your Git repository by adding relevant patterns to your .gitignore file and using GitHub Actions secrets to securely manage sensitive information.
  • Avoid Using Caching for Privileged Jobs: Caching in Github Actions is vulnerable to cache poisoning. If a code injection vulnerability is present in any of the workflows (whether they run in a privileged context or not), and you use caching in a higher privileged workflow, then code injection can be exploited to poison the cache and steal higher value secrets and credentials.

Docker Security Best Practices

To enhance the security and efficiency of your Docker workflows, consider implementing the following best practices:

Utilize a .dockerignore File

A well-configured .dockerignore file is essential for optimizing your Docker build process. It functions similarly to a .gitignore file by specifying which files and directories should be excluded from the build context. This practice reduces the build size, leading to faster builds, and prevents sensitive or unnecessary files from being included in your Docker images.


  • Exclude Version Control Directories: Add .git/ to your .dockerignore file to prevent the inclusion of Git configuration which could include the authentication token, history and metadata in your Docker image, thereby reducing image size and avoiding potential exposure of sensitive information.
.git/
  • Exclude Node Modules: For Node.js projects, exclude the node_modules/ directory to prevent unnecessary files from being added to the Docker image.
node_modules/
  • Exclude Temporary and Log Files: Prevent temporary files and logs from being included in the image by adding patterns like:
*.log
*.tmp
  • Exclude GitHub Actions Credential Files: Exclude credential JSON files (gha-creds-*.json) used in GitHub Actions workflows to avoid inadvertently including authentication data in Docker images. Alternatively, build Docker images before running the google-github-actions/auth@v2 step in your GitHub workflow, ensuring these credentials aren't present in your build context.
gha-creds-*.json
Sample .dockerignore file
.git/

node_modules/
*.log
*.tmp

gha-creds-*.json