GitHub Actions is a powerful tool to automate your CI/CD pipelines like creating builds, code quality checks, or deployments. However, it might contain sensitive data like API keys or cloud admin credentials, making them vulnerable to CI/CD malware injection threats.
Thus, it’s crucial to implement security best practices like pinning GitHub Actions using version tags or commit SHAs in your workflows to avoid code compromises.
Before we move ahead, check out our previous blogs in GitHub Actions security series:
- 7 GitHub Actions Security Best Practices (With Checklist)
- 8 GitHub Actions Secrets Management Best Practices to Follow Practices
- 5 Effective Third-Party GitHub Actions Governance Best Practices
- GITHUB_TOKEN: How It Works and How to Secure Automatic GitHub Action Tokens
Now let’s explore all things GitHub Actions pinning in this blog.
What is GitHub Actions Pinning?
Action pinning in GitHub Actions is the practice of pointing to a specific version of an action used in a workflow, allowing the execution of the same code every time the GitHub Actions workflow is pulled, irrespective of any updates made to the action itself.
Pinning to a Full-Length Commit SHA
With this method, you can point to the specific commit SHA for the desired version of the action. This guarantees that the exact code you've pinned is used, even if the version tag or the action's code is modified later. Commit SHA offers the highest level of security as it tags to a specific point in time within the action's codebase using a unique identifier (the commit SHA). For example, it could look like "actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332".
Why Pin GitHub Actions?
Supply chain attacks commonly target dependencies within projects. Malicious actors might attack a seemingly trusted action repository and inject malicious code. Pinning actions ensures you're using a specific version of the code that you've previously audited and trusted. Even if the GitHub action gets somehow compromised later, the attacker won’t be able to tamper with the code that you've already pinned.
Action pinning with specific commit hash SHAs leverages the concept of immutability. Once a commit SHA is pinned, it guarantees that the specific code version cannot be altered. This offers significant security benefits compared to relying on version tags, which can be changed to point to different code versions.
Example of Vulnerable Workflow and Attack Scenario
To further understand why pinning actions is crucial for securing workflows, let’s explore a vulnerable workflow with unpinned actions and how it behaves in an attack scenario:
Workflow file (vulnerable.yml):
Attack Scenario in the Absence of a Pinned GitHub Actions
We have a workflow that is not pinned to a specific commit SHA (having unintended information). An attacker gains access to the user/build-action repository and injects malicious code into the build-action that steals confidential information from the codebase during the build process. The attacker then updates all existing version tags to point to the Action code with their malicious code.
During workflow execution, the injected malicious code within the build-action can steal sensitive secrets (like API keys or access tokens). The author re-tags the action as “anotheruser/deploy-action@v1.2.3,” causing everyone to use “user/deploy-action@v1.2.3” to run the malicious code. This helps the attacker to gain access and steal secrets to further compromise other systems or accounts.
However, if the vulnerable.yml workflow had pinned the someuser/build-action to a secure commit SHA beforehand (i.e. anotheruser/deploy-action@<commit-SHA>), the workflow would have been immune to this attack. The workflow would further continue to use the trusted, pre-compromised version, preventing malicious code injection and protecting secrets.
How to Pin GitHub Actions
Now that we know why pinning is crucial for GitHub Action workflows, let’s learn how to pin GitHub Actions. Here's a step-by-step guide on how you can pin GitHub Actions to specific commit SHAs:
1. Finding the Commit SHA
- Identify the release version you want to pin to and find the corresponding commit. To do this, click on the Releases link in the repository and find the commit corresponding to the git tag.
- Navigate to the action repository you want to pin. You can find this on the GitHub Marketplace or using the action name. For example, the repository for the action actions/checkout is https://github.com/actions/checkout
- Copy the SHA of the commit you want to pin to. The specific commit hash SHA is a long alphanumeric string next to each commit. This will display the details of that specific code version.
2. Updating Your Workflow to Use the Commit SHA
- Open your workflow YAML file within your GitHub repos.
- Locate the "uses" statement for the action you want to pin. It typically follows this format:
- Replace the <version> part with the commit SHA you obtained in step 1. The final line should look similar to this:
Example with Code Snippets
Scenario: You want to pin the actions/checkout@v3 action to the commit SHA example “378343a27a77b2cfc354f4e84b1b4b29b34f08c2”.
Original Workflow (Unpinned GitHub Action):
Updated Workflow (Pinned GitHub Action):
Best Practices for Pinning GitHub Actions
Now that you know how to manually pin GitHub Actions, let’s explore best practices to follow while pinning to ensure maximum effectiveness:
1. Prioritize High-Risk Actions with commit SHAs
- Start with identifying actions (falling under "high-risk" actions) that handle sensitive data or have access to vital resources within your workflows. To perform risk analysis on a GitHub actions security, consider using StepSecurity’s GitHub Action Advisor hosted here: https://app.stepsecurity.io/action-advisor
- Maximum control and immutability can be assured by always pinning high-risk third-party actions (developed by external maintainers) to specific commit hash SHAs.
- Also, if you manage multiple GitHub Action workflows across multiple repositories, use reusable workflows to centrally manage pinned action SHAs. This promotes consistency and simplifies updates.
2. Enable Dependabot/ Renovatebot updates for pinned Actions
i. Pinning with Dependabot
- Create dependabot.yml file.
- Place this file in the .github directory of your repository.
- Configure Dependabot: Add the following configuration to the dependabot.yml file:
ii. Pinning with Renovatebot:
- Create renovate.json file.
- Place this file in the root of your repository.
- Configure Renovatebot: Add the following configuration to the renovate.json file as the frequency schedule:
iii. Automated Updates using Comments (Best Practice):
When using these configurations, you might also want to include comments in your GitHub Actions workflows folder to clarify that dependencies are tracked by commit SHAs.
3. Use Version Tags for Trustworthy Organizations
- For actions maintained by well-known organizations with a strong security track record in the GitHub community, you may consider using version tags for pinning. With this practice, you can take advantage of minor bug fixes and enhancements in updated tagged versions.
- A balance between security and flexibility is the key to a streamlined CI/CD. That’s why, prioritize pinning high-risk actions and choosing trusted sources only for version tags.
- Regularly keep an eye on these trusted actions for any reported vulnerabilities and update the pinned version tag accordingly.
4. Regular Review and Updates
Update pinned commit SHAs whenever possible to ensure you're using secure and up-to-date code. Consider using automation tools for efficiency in this process for large workflows.
Challenges and Solutions with Pinning GitHub Action
While action pinning offers significant security benefits, it does not come without its challenges. Here's a glance at common issues and potential solutions:
Common Challenges in Pinning Actions
- Manual Updates: Keeping track of numerous pinned commit SHAs and updating them manually can be time-consuming and error-prone, especially for complex workflows with many actions.
- Challenges in maintaining pinned actions in allowlist: If you use GitHub actions Allowlist feature to only allow specific actions versions in your organization. You would have to update the allowlist every time you update the pinned hash for an allowed action.
Solutions and Automation Tools
Fortunately, there are some solutions and tools to tackle these challenges:
- Automated Updates: Tools like Dependabot and Renovate can integrate with GitHub repos and automate the process of identifying secure updates for pinned actions in your dependencies. These tools suggest updates based on security vulnerabilities or new tagged versions released by trusted maintainers.
- Reusable Workflows: Utilize reusable workflows to manage pinned actions centrally across multiple repositories. This streamlines updates and ensures consistency.
- Security Review: Leverage StepSecurity Action Advisor to reduce time to review each action.
Automating GitHub Actions Pinning with StepSecurity
Keeping your GitHub Actions workflows secure can be a time-consuming task, especially with the need to manually review and pin actions. StepSecurity simplifies this process by automating various security best practices, including setting minimum token permissions, integrating Dependabot, action pinning, and more, through its integration with your GitHub repository.
StepSecurity automates action pinning by scanning workflows and generating pull requests that suggest any sort of security compliances, including pinning actions to secure commit SHAs, hence eliminating manual configuration.
Benefits of Automating Action Pinning with StepSecurity
- Save Time and Effort: StepSecurity analyzes your workflows and automatically generates pull requests suggesting security improvements. This eliminates the need for manual review and configuration of action pinning.
- Reduced Risk: StepSecurity ensures your workflows adhere to security best practices, minimizing the chance of vulnerabilities and attacks.
- Improved Consistency: Automated pinning ensures all workflows use secure, pinned actions, leading to consistent and reliable workflow execution.
How does StepSecurity Automate Action Pinning?
1. Integrate the StepSecurity App: Visit the GitHub Marketplace and install the StepSecurity App. After installing and granting access, StepSecurity will scan your repository for workflow files, typically named “.yml”. It analyzes the actions used within these workflows, identifying potential vulnerabilities like unpinned actions.
2. Dashboard: StepSecurity scans your workflows and identifies potential security vulnerabilities including unpinned actions to SHA commit hash. You can find the list of unpinned GitHub Action workflows in your dashboard.
3. Automated Pull Requests:
If StepSecurity detects unpinned actions, it automatically generates a pull request for your repository. This pull request will pin action to secure commit SHA, ensuring your workflows always use a trusted and immutable version of the code.
4. Review and Merge: You can quickly review the suggested changes within the pull request and merge them to apply the security improvements.
Experience the benefits of automated action pinning and improved workflow security with StepSecurity. Try it for seamless action pinning and get started today!
Conclusion
Pinning GitHub Actions can help mitigate the risk of supply chain attacks, ensure consistency across workflows, and ultimately enhance GitHub Actions security!
For an automated approach to pinning and overall CI/CD pipeline security, try StepSecurity for free today!
Frequently Asked Questions
1. What are the differences between pinning to a tag vs. a commit SHA?
Pinning to a tag, such as v1.0, refers to a named version of the action that can be updated by the author. This means the underlying code can be updated to introduce new features or fixes. The possibility of code update in the pinned version to a tag leaves a gap for possible vulnerabilities or virus injections. However, pinning to a specific commit SHA enables your workflow to use an exact, immutable version of the action's code. A commit SHA uniquely identifies a specific state of the repository, catering to higher security and consistency as the code version cannot be altered once pinned.
2. How often should you update pinned actions?
Updating pinned actions should be done periodically to benefit from new features, bug fixes, and security patches. However, the frequency also depends on the type of criticality of the action and your project's security dependencies. Regular reviews are good GitHub Actions security practice. Not to mention, we recommend testing updated actions prior to deployment to production to ensure compatibility and stability.
3. Are there any tools to help manage pinned actions?
Yes, tools like StepSecurity can automate the management of pinned actions. StepSecurity scans your workflows, identifies unpinned actions, and generates pull requests with recommendations to pin actions to secure commit SHAs. This reduces manual effort and helps maintain a secure and consistent workflow environment.
4. Other than Action pinning, are there any other GitHub Actions security best practices I should implement to enhance the security of my GitHub Actions workflow?
Yes, other than pinning GitHub Actions, you must set minimum token permissions, integrate Dependabot, integrate Harden-Runner for runtime security and much more. For a comprehensive guide on GitHub Actions security best practices, check out our blog: 7 GitHub Actions Security Best Practices (With Checklist)