|
| 1 | +# GitHub Actions Security Best Practices (NHSDigital) |
| 2 | + |
| 3 | +This file is a direct copy of the guidance from the NHSDigital Software Engineering Quality Framework: [NHSDigital Actions Best Practices](https://github.com/NHSDigital/software-engineering-quality-framework/blob/main/practices/actions-best-practices.md) |
| 4 | +Last updated: 27 April 2026 |
| 5 | + |
| 6 | +--- |
| 7 | + |
| 8 | +## Introduction |
| 9 | + |
| 10 | +GitHub Actions is a powerful automation tool that enables CI/CD workflows directly within your GitHub repository. Securing your GitHub Actions workflows is crucial to protect your code, secrets, and infrastructure from potential security threats. |
| 11 | +This guide outlines best practices for securing your GitHub Actions workflows and minimizing security risks. All actions used in committed workflow definitions must be pinned to a full-length commit SHA. |
| 12 | + |
| 13 | +## Table of Contents |
| 14 | + |
| 15 | +- Secrets Management |
| 16 | +- Limiting Permissions |
| 17 | +- Third-Party Actions |
| 18 | +- Dependency Management |
| 19 | +- Runner Security |
| 20 | +- Pull Request Workflows |
| 21 | +- OIDC Integration |
| 22 | +- Audit and Monitoring |
| 23 | + |
| 24 | +## Secrets Management |
| 25 | + |
| 26 | +- Store sensitive data (API tokens, credentials, etc.) as GitHub Secrets |
| 27 | +- Never hard-code sensitive values in your workflow files |
| 28 | +- Do not use structured data as a secret - this can cause GitHub's secret redaction in logs to fail |
| 29 | +- Rotate secrets regularly |
| 30 | +- Use environment-specific secrets when possible |
| 31 | +- Ensure a secret scanner is deployed as part of your workflows |
| 32 | +- Public repositories should enable GitHub Secret Scanner and Push Protection |
| 33 | +- Minimize secret scope (limit to specific environments/jobs) |
| 34 | +- Avoid exposing secrets in logs (don't echo/print secrets, set debug to false, use masking for dynamic secrets) |
| 35 | +- Use robust secrets management tools (Azure Key Vault, AWS Secrets Manager) |
| 36 | + |
| 37 | +## Limiting Permissions |
| 38 | + |
| 39 | +- Use least privilege principle for GITHUB_TOKEN |
| 40 | +- Use fine-grained tokens only if GITHUB_TOKEN cannot be used |
| 41 | +- Create custom GitHub Apps with limited scopes when possible |
| 42 | +- Use repository-scoped tokens instead of org-wide tokens |
| 43 | + |
| 44 | +## Third-Party Actions |
| 45 | + |
| 46 | +- Pin all actions to a commit SHA (with inline tag/version comment) |
| 47 | +- Do not use tags or branch references in committed workflow definitions |
| 48 | +- Review third-party actions before adoption |
| 49 | +- Minimize use of third-party actions; prefer native/reusable/org actions |
| 50 | +- Document rationale for third-party actions in docs/ADRs.md or similar |
| 51 | +- Prefer actions with clear maintenance history, minimal permissions, and narrow scope |
| 52 | +- Only use trusted actions from the GitHub Marketplace |
| 53 | +- Consider forking/maintaining your own copy of critical actions |
| 54 | +- Keep a record of approval/version reviewed |
| 55 | +- Enable Dependabot alerts for GitHub Actions |
| 56 | +- Set up a workflow to check for outdated actions |
| 57 | + |
| 58 | +## Dependency Management |
| 59 | + |
| 60 | +- Use dependency scanning tools (e.g., Dependabot) |
| 61 | +- Implement automated dependency updates |
| 62 | +- Regularly review and update dependencies with security patches |
| 63 | + |
| 64 | +## Runner Security |
| 65 | + |
| 66 | +- Self-hosted runners: use only with private repos, run in isolated environments, update/patch regularly, use network isolation, prefer ephemeral runners |
| 67 | +- GitHub-hosted runners: be aware they are reset after each job, clean up sensitive data before job completion, don't store persistent sensitive data in runner environment |
| 68 | + |
| 69 | +## Pull Request Workflows |
| 70 | + |
| 71 | +- Don't expose secrets to PR workflows from forks |
| 72 | +- Use pull_request_target carefully with read-only permissions |
| 73 | +- Enforce branch protection rules |
| 74 | +- Require code reviews before merging |
| 75 | +- Use status checks to enforce security scans |
| 76 | + |
| 77 | +## OIDC Integration |
| 78 | + |
| 79 | +- Use OpenID Connect for cloud providers instead of long-lived credentials |
| 80 | +- Limit OIDC token claims (set specific subject claims, implement additional claim conditions) |
| 81 | + |
| 82 | +## Audit and Monitoring |
| 83 | + |
| 84 | +- Enable audit logging for GitHub Actions usage |
| 85 | +- Set up alerts for suspicious activity |
| 86 | +- Enforce code reviews for workflow file changes |
| 87 | +- Use CODEOWNERS to restrict workflow file modification |
| 88 | +- Conduct regular reviews of all workflows |
| 89 | +- Update security practices based on emerging threats |
| 90 | +- Monitor GitHub security advisories |
| 91 | + |
| 92 | +## Additional Resources |
| 93 | + |
| 94 | +- [GitHub Actions Security Hardening Guide](https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions) |
| 95 | +- [GitHub Security Lab](https://securitylab.github.com/) |
| 96 | +- [GitHub Actions Documentation](https://docs.github.com/en/actions) |
| 97 | +- [Security for GitHub Actions](https://docs.github.com/en/actions/security-for-github-actions) |
| 98 | + |
| 99 | +## Conclusion |
| 100 | + |
| 101 | +Securing GitHub Actions requires a multi-layered approach focusing on secrets management, permissions, third-party action vetting, and proper configuration. By following these best practices, you can significantly reduce security risks while still enjoying the full benefits of GitHub Actions automation. |
| 102 | +Security is an ongoing process—regularly review and update your security practices to adapt to new threats and challenges. |
0 commit comments