CI/CD supply chain security scanner for GitHub Actions
Runner Guard detects pipeline injection vulnerabilities, unpinned supply chain dependencies, AI configuration poisoning, and invisible steganographic payloads in GitHub Actions workflows. It checks your installed packages against known compromised versions, scans multiple repos in parallel, and auto-fixes what it finds.
┌───────────────────────────┐
│ Workflow YAML / Repos │
│ Lock files / Remote URL │
└─────────────┬─────────────┘
│
┌─────────────┬───────┼───────┬─────────────┐
▼ ▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Workflow │ │ check │ │ audit │ │ Batch │
│ Scan │ │ -deps │ │ -deps │ │ Scan │
│ │ │ │ │ │ │ │
│ Taint │ │ Lock │ │ Resolve │ │ Multi- │
│ Perms │ │ files │ │ deps to │ │ repo │
│ IOCs │ │ Known │ │ repos │ │ Parallel │
│ │ │ bad vers │ │ Scan CI │ │ Scoring │
└────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │ │
└────────────┴─────┬──────┴────────────┘
▼
┌───────────────────────────┐
│ Runner Guard Score │
│ 0-100 / Letter grade │
│ Pinning / Permissions / │
│ Injection / Triggers / │
│ IOCs │
└─────────────┬─────────────┘
│
┌──────────────────┼──────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Report │ │ Auto-Fix │ │ CI Gate │
│ │ │ │ │ │
│ Console/JSON │ │ Pin actions │ │ Pass / Fail │
│ SARIF / CSV │ │ Extract envs │ │ SARIF upload │
└──────────────┘ └──────────────┘ └──────────────┘
# Homebrew (macOS/Linux)
brew install Vigilant-LLC/tap/runner-guard
# One-liner (macOS/Linux)
curl -sSfL https://raw.githubusercontent.com/Vigilant-LLC/runner-guard/main/install.sh | bash
# From source
go install github.com/Vigilant-LLC/runner-guard/cmd/runner-guard@latestPre-built binaries for Linux, macOS, and Windows (amd64/arm64) on the Releases page.
- 18 detection rules covering fork checkout exploits, expression injection, secret exfiltration, unpinned actions, AI config injection, and supply chain steganography with permissions-aware severity
- 41 compromised package versions across 13 confirmed supply chain attack campaigns (UNC1069/Axios, TeamPCP, npm debug/chalk, Solana web3.js, and more)
- 31 threat signatures across 6 campaign files -- GlassWorm, TeamPCP, UNC1069/Axios, Telnyx, and general supply chain IOCs
- Upstream pipeline audit --
audit-depsresolves your dependencies to source repos and scans each repo's CI/CD pipeline, answering "are my dependencies' build pipelines secure?" - Batch scanning -- scan multiple repos from a file or stdin with
--repos, parallel scanning with--concurrency, output as console summary table, JSON, or CSV - Runner Guard Score -- CI/CD security score (0-100) with letter grade and category breakdown (Pinning, Permissions, Injection, Triggers, IOCs)
- AI config injection detection across Claude, GitHub Copilot, Cursor, and MCP tooling -- the first scanner to cover this attack surface
- Auto-fix -- pin unpinned third-party actions to immutable commit SHAs, extract unsafe expressions from
run:blocks intoenv:mappings - Interactive CLI menu -- run
runner-guardwith no arguments for a guided experience - SARIF output for native GitHub Code Scanning integration
- Remote scanning -- scan any public GitHub repo by URL without cloning
- Single binary -- zero dependencies, all rules embedded, runs anywhere Go compiles
runner-guard scan . # local repo
runner-guard scan github.com/owner/repo # remote repo
runner-guard scan . --format sarif --output r.sarif # SARIF for GitHub Security tab
runner-guard scan . --fail-on high # CI gaterunner-guard audit-deps . # scan upstream CI/CD pipelines
runner-guard audit-deps . --format json # JSON output
runner-guard audit-deps . --concurrency 10 # parallel scanningrunner-guard check-deps . # scan lock files
runner-guard check-deps . --format json # JSON outputrunner-guard scan --repos repos.txt # from file
runner-guard scan --repos repos.txt --concurrency 10 --format csv
cat repos.txt | runner-guard scan --repos - # from stdinrunner-guard fix . # pin actions + extract expressions
runner-guard fix . --dry-run # preview changesrunner-guard # no args = guided menu| ID | Name | Severity | Description |
|---|---|---|---|
| RGS-001 | pull_request_target with Fork Code Checkout | Critical | Workflow checks out fork code in privileged base repo context with secret access |
| RGS-002 | Expression Injection via Untrusted Input | Critical | Attacker-controlled input interpolated directly in shell run: block |
| RGS-003 | Dynamic Command Construction from Step Outputs | High | Step outputs combined with git diff/find/ls to construct shell commands |
| RGS-004 | Privileged Trigger with No Author Check | High | issue_comment trigger with secrets and no authorization check |
| RGS-005 | Excessive Permissions on Untrusted Trigger | Medium | Write permissions on workflows triggered by external users |
| RGS-006 | Dangerous Sink in Run Block | High | Remote script piped to shell (curl pipe bash) |
| RGS-007 | Unpinned Third-Party Action | Medium/Low | Mutable tag instead of commit SHA. Low when job has read-only permissions. |
| RGS-008 | Secrets Exposure in Run Block | Medium | Secret interpolated in run: block instead of env: mapping |
| RGS-009 | Fork Code Execution via Build Tools | Critical | Build tools execute attacker code from fork checkout |
| RGS-010 | AI Agent Config Poisoning via Fork PR | High | CLAUDE.md or AI config loaded from fork checkout |
| RGS-011 | MCP Config Injection via Fork Checkout | High | .mcp.json read from fork-controlled checkout |
| RGS-012 | External Network Access with Secrets | Medium | Outbound HTTP with secrets in privileged context |
| RGS-014 | Expression Injection via workflow_dispatch | High | Dispatch input interpolated in shell run: block |
| RGS-015 | Actions Runner Debug Logging Enabled | Medium | Debug env vars exposing secrets in logs |
| RGS-016 | Unicode Steganography in Workflow File | Critical | Invisible Unicode in YAML -- active compromise indicator |
| RGS-017 | Unicode Steganography in Referenced Script | High | Invisible Unicode in files executed by workflows |
| RGS-018 | Suspicious Payload Execution Pattern | High | Eval+decode chains, known IOCs, C2 patterns |
| RGS-019 | Step Output Interpolated in run Block | Medium | Step output may carry attacker-controlled data |
RGS-010 and RGS-011 are unique to Runner Guard. No other CI/CD scanner detects AI configuration injection attacks.
name: Runner Guard Security Scan
on:
pull_request:
paths:
- '.github/workflows/**'
- 'CLAUDE.md'
- '.claude/**'
- '.mcp.json'
permissions:
contents: read
security-events: write
jobs:
runner-guard:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: Vigilant-LLC/runner-guard@43f4b50e628910a5ed9ffbd6f88cec980a0744d5 # v2.9.0
with:
fail-on: high
sarif-upload: 'true'Findings appear in the GitHub Security tab under Code Scanning alerts.
pull_request_target checks out fork code with full secret access. Detects RGS-001 (checkout), RGS-007 (unpinned actions), RGS-009 (build tool execution), RGS-012 (exfiltration).
runner-guard demo --scenario fork-checkoutissue_comment trigger interpolates attacker data into shell. Detects RGS-002 (injection), RGS-004 (no auth check), RGS-006 (curl pipe bash), RGS-008 (secrets in args).
runner-guard demo --scenario microsoftFork PR modifies CLAUDE.md/copilot-instructions.md to hijack AI agents in privileged CI. Detects RGS-010 (AI config) and RGS-011 (MCP config).
runner-guard demo --scenario ai-injectionInvisible Unicode steganography, known IOC variables, eval+decode patterns. Detects RGS-016 (Unicode), RGS-018 (IOC patterns).
runner-guard demo --scenario glasswormrunner-guard scan . --group steganography # scan only steganography rules
runner-guard scan . --rules RGS-016,RGS-018 # specific rules
runner-guard scan . --group ai-config --rules RGS-001 # combineGroups: injection, permissions, secrets, supply-chain, ai-config, steganography, debug
The fix engine:
- Pins actions to immutable commit SHAs with version comments
- Extracts Tier-1 expressions from
run:blocks intoenv:mappings - Extracts secrets from
run:blocks intoenv:mappings - Shell-aware --
${VAR}for bash,$env:VARfor PowerShell,%VAR%for cmd - Handles single-quoted contexts and skips brace expansions
runner-guard baseline create # generate baseline
runner-guard scan . --baseline .runner-guard-baseline.json # suppress known
runner-guard baseline update # update after triage- uses: some-org/action@v1 # runner-guard:ignoreA coordinated attack campaign escalated through multiple phases:
- Phase 1-2 (March 12): reviewdog and tj-actions/changed-files compromised, harvesting CI/CD credentials from 23,000+ repositories
- Phase 3 (March 19-27): Trivy, Checkmarx, LiteLLM, and Telnyx compromised by TeamPCP. Cisco lost 300+ source code repos.
- Phase 4 (March 30): Axios (100M weekly downloads) compromised with a RAT. Attributed to North Korean threat actor UNC1069.
Runner Guard includes IOC signatures for all confirmed phases organized in rules/signatures/ by campaign.
Workflows triggered by pull_request_target run with the base repository's secrets. When combined with actions/checkout pointing at fork code, an attacker's build scripts execute with full credentials. In documented incidents, attackers exfiltrated PATs and pushed malicious commits to main branches within minutes, fully automated by AI agents.
The GlassWorm campaign compromised 433+ components using invisible Unicode characters that encode executable payloads invisible to code review. Runner Guard detects this at the byte level (RGS-016/017/018).
When pull_request_target workflows check out fork code, attackers can modify CLAUDE.md, copilot-instructions.md, .cursorrules, or .mcp.json to hijack AI code review agents. Runner Guard is the first scanner to detect this attack surface (RGS-010/011).
Runner Guard welcomes contributions, especially new detection rules:
- Create a YAML rule file in
rules/(seerules/RGS-001-prt-fork-checkout.yaml) - Add detection logic in
internal/rules/if needed - Add a test case in
internal/taint/ - Submit a PR describing the real-world attack pattern
To add threat signatures without writing Go code, add a YAML file to rules/signatures/ and rebuild. See existing files for format.
Report false positives. Accuracy is critical -- a scanner that cries wolf gets disabled.
Vigilant is a cybersecurity company who stands between organizations and the threats that want to destroy them. We don't believe in passive defense -- we operate with a warfare mindset, hunting threats before they become breaches.
We built Runner Guard because we've weaponized these exact attack chains against banks, government agencies, and critical infrastructure in red team engagements. When autonomous AI agents started exploiting them at scale, we built the scanner we wished existed.
- ThreatCert -- attack surface intelligence platform mapping full kill chains with audit-ready evidence
- CyberDNA -- analysis workspace with Vigilant's zero-breach guarantee
Vigilant donates 25% of profit to organizations combating human trafficking and supporting orphan care worldwide.
For enterprise support, custom rule development, or security assessments, visit vigilantdefense.com.
AGPL-3.0. See LICENSE for the full text.
Copyright 2026 Vigilant.







