Detection Rules
59 rules across 8 attack classes
Each rule maps to a specific attack pattern against GitHub Actions workflows, ordered by severity within each category.
10
19
16
7
Injection
6 rulesShell command injection via expression interpolation in run blocks and reusable workflow inputs.
Attacker-controlled GitHub context expressions interpolated in run: blocks allow arbitrary command injection.
- WRD-110Source variant: composite action inputs
- WRD-111Source variant: dispatch inputs
- WRD-113Source variant: reusable workflow inputs
- WRD-130Source variant: tainted step outputs
Composite action inputs interpolated directly in run: blocks allow injection when the action is consumed with attacker-controlled values.
- WRD-101Family: expression injection (composite action source)
workflow_dispatch or repository_dispatch inputs interpolated in run: blocks can be controlled by any user with push access, enabling command injection.
- WRD-101Family: expression injection (dispatch input source)
Writing attacker-controllable values to GITHUB_ENV or GITHUB_PATH allows environment variable or PATH manipulation in subsequent steps.
Attacker-controlled values passed as inputs to reusable workflows can cause injection if the called workflow interpolates them unsafely.
- WRD-101Family: expression injection (reusable workflow source)
Step outputs interpolated in run: blocks may carry attacker-controlled data if a prior step set the output from tainted input.
- WRD-101Family: expression injection (tainted step output source)
Triggers
3 rulesDangerous trigger configurations that allow fork-based code execution with elevated privileges.
pull_request_target with actions/checkout referencing the PR head checks out untrusted fork code in a privileged context.
pull_request_target workflow checks out fork code and executes build tools, allowing arbitrary code execution with write permissions.
A workflow_run workflow with write permissions watching a pull_request workflow can be exploited via artifact poisoning for privilege escalation.
Supply Chain
12 rulesUnpinned dependencies, mutable references, and compromised upstream actions.
id-token: write permission with external triggers (pull_request_target, workflow_run, issue_comment) can allow attackers to obtain OIDC tokens and access cloud resources.
Workflow uses a GitHub Action with known security vulnerabilities or that was involved in a supply chain compromise.
- WRD-313Companion: incident-driven hardcoded denylist (this rule is the CVE-database-driven counterpart)
Actions pinned to commit SHAs that appear suspicious. Impostor commits can be pushed to a repository via its fork and may not belong to any branch or tag in the original repository.
Uses an action reference that is on warden's hardcoded denylist due to a known security incident or EOL status.
- WRD-302Companion: CVE-database-driven check, this rule is the policy/incident-driven counterpart
A composite or Docker action used by this workflow has unpinned action references inside its own action.yml. SHA-pinning the top-level action does not protect against tag mutation in its internal dependencies, so a compromise of those inner refs still propagates into your workflow.
- WRD-311Extends: 311 catches unpinned outer uses, 314 descends into pinned composites and flags their unpinned internals
Third-party actions pinned to mutable tags instead of commit SHAs can be silently replaced with malicious code via tag mutation.
- WRD-324Companion: pinned to ambiguous branch name
- WRD-313Companion: action is on a known-bad denylist
- WRD-332Companion: SHA pinned but no version comment
- WRD-333Companion: SHA pin with mismatched version comment
Detects actions pinned to branch names (main, master, develop, etc.) that are ambiguous and mutable.
- WRD-311Family: action pinning hygiene
Detects references to GitHub Actions from known archived or deprecated repositories
Detects actions pinned to a SHA without a version comment, suggesting the pin may be stale or untracked.
- WRD-311Family: action pinning hygiene
- WRD-333Family: SHA pin with mismatched comment
Detects actions where the SHA pin comment version disagrees with the version tag in the uses: reference.
- WRD-311Family: action pinning hygiene
- WRD-332Family: SHA pin missing comment
Flags uses: steps whose creator is not on warden's allowlist of well-known-safe publishers (GitHub-first-party, major cloud vendors, common language toolchains, vetted OSS). Signal to cross-check and SHA-pin, not evidence of malice.
Detects actions known to download external binaries at runtime. SHA-pinning the action does not protect against compromised upstream binaries or install scripts fetched during execution. Demoted to Info in v2.0.0: the scanner cannot reliably distinguish a legitimate setup action (setup-go, setup-python) from a compromised one by static analysis, so this rule inventories the risk surface rather than asserting an exploit. A future revision will rework this into an allowlist plus suspicious-behavior split.
Permissions
4 rulesOverly broad permissions, exposed secrets, and insecure credential handling.
curl or wget commands in run: blocks that also reference secrets may indicate credential exfiltration.
ACTIONS_RUNNER_DEBUG or ACTIONS_STEP_DEBUG is enabled. Debug logging can expose secrets and sensitive information in workflow logs.
A job references secrets (other than GITHUB_TOKEN) without declaring an `environment:`, so no required-reviewers or deployment protection rules gate the secret access.
Inventories where repository secrets are referenced across workflows so reviewers can audit secret reach and exposure.
AI Security
8 rulesAI tool configuration poisoning, MCP config injection, Dependabot security, and trusted publishing best practices.
Privileged-context workflow (pull_request_target, workflow_run, or issue_comment) checks out fork code that may contain poisoned AI assistant configuration. Tracks 30+ verified file paths across Claude Code (CLAUDE.md, .claude/rules/), Cursor (.cursorrules, .cursor/rules/), GitHub Copilot (.github/copilot-instructions.md, .github/instructions/), Aider (.aider.conf.yml, CONVENTIONS.md), Continue (.continue/rules/), Windsurf (.windsurf/rules/), Cline (.clinerules/), Gemini CLI (GEMINI.md, .gemini/), OpenAI Codex CLI (.codex/, AGENTS.md), and the cross-tool AGENTS.md standard.
- WRD-511Family: AI tooling supply-chain (MCP server config variant)
Privileged-context workflow (pull_request_target, workflow_run, or issue_comment) checks out fork code that may contain malicious Model Context Protocol (MCP) configuration. Tracks 16 verified file paths spanning .mcp.json, mcp_servers.json, .vscode/mcp.json, .cursor/mcp.json, .claude/mcp.json, .claude/mcp_servers.json, claude_desktop_config.json, .continue/mcpServers/, cline_mcp_settings.json and more, enabling detection of tool-server hijacking, secret exfiltration, and silent backdoor injection into AI-generated code.
- WRD-510Family: AI tooling supply-chain (CLAUDE.md / .cursorrules variant)
Detects run: blocks that spawn an AI coding-agent CLI (claude, cursor-agent, gemini, codex, aider, continue, cline) with a permission-bypass flag (--dangerously-skip-permissions, --yolo, --trust-all-tools, --full-auto, -y, --unsafe, --no-confirm). Escalates to HIGH on pull_request_target / workflow_run / issue_comment. The exact pivot used by the Nx s1ngularity supply-chain attack in August 2025 to enumerate dev secrets.
Detects Dependabot-related workflows that may execute untrusted code from pull requests via pull_request_target
Detects PyPI/npm publish workflows using stored API tokens instead of OIDC trusted publishing
Detects actions/create-github-app-token calls that skip revocation, leave repositories unspecified, or leave permissions unspecified
Complements WRD-525 (PyPI/npm) by flagging long-lived Cargo (CARGO_REGISTRY_TOKEN) and RubyGems (GEM_HOST_API_KEY) publish tokens. Both registries now support OIDC trusted publishing.
Detects Dependabot configurations with daily update schedules and no grouping, which can flood PRs
Steganography
2 rulesHidden malicious content using Unicode invisible characters and obfuscation patterns.
Suspicious patterns that may indicate malicious activity, including obfuscated payloads, reverse shells, and C2 communication.
Invisible Unicode characters detected in workflow file. These can hide malicious commands, alter string comparisons, or use bidirectional text overrides to disguise code.
Integrity
8 rulesCredential persistence, secret inheritance, insecure commands, and remote script execution.
Detects toJSON(secrets) or secrets.* patterns that expose the entire secrets context, potentially leaking all repository secrets
Detects ACTIONS_ALLOW_UNSECURE_COMMANDS set to true, which re-enables deprecated set-env and add-path workflow commands
Detects curl|bash, wget|sh, and similar patterns that execute remote scripts without verification
Detects ACTIONS_STEP_DEBUG / ACTIONS_RUNNER_DEBUG enabled in the same job as actions/upload-artifact. The debug dump includes every runner env var (GITHUB_TOKEN included), so anyone with repo read can download the artifact and extract a live token. CodeQLEAKED pattern, CVE-2025-24362.
Detects 'secrets: inherit' in reusable workflow calls, which passes all repository secrets to the called workflow
Detects hardcoded username or password values in container/services credentials blocks instead of using secrets. Warden checks both username and password fields; some other tools only check password.
Detects container or services image references that are not pinned to a specific @sha256: digest
Detects actions/checkout without persist-credentials: false. By default, actions/checkout persists the GITHUB_TOKEN on disk after cloning (.git/config below v6, $RUNNER_TEMP for v6+). The fix is one line: add persist-credentials: false to the checkout step. warden fix --apply does this automatically.
- WRD-840Companion: both rules drive `warden fix --apply` to harden default-unsafe primitives
Logic
16 rulesConditional logic flaws, self-hosted runner exposure, auto-merge bypasses, and cache poisoning.
Detects pull_request triggers combined with self-hosted runners, allowing untrusted PR code to execute on your infrastructure
Detects workflows that register or start a self-hosted runner from inside a run: block (config.sh --token, ./run.sh, RUNNER_ALLOW_RUNASROOT=1, or the SHA1HULUD Shai-Hulud 2.0 IOC). This is a persistence primitive used by the 2025-11 npm worm to compromise 25k+ repositories.
Detects auto-merge or auto-approve patterns without proper authorization checks
Detects workflow_run triggers that download artifacts without verifying the triggering workflow's conclusion
Workflow uses a risky trigger (pull_request_target, workflow_run, issue_comment, discussion_comment) without an explicit top-level permissions: block, inheriting the repo default which may grant write access.
- WRD-824Escalation of: 824 fires medium when any workflow lacks a permissions block, this rule escalates to high when the missing block is paired with a risky trigger
Detects patterns that bypass GitHub Actions secret redaction: base64 encoding, character splitting, or file write then cat of secrets
Detects contains() checks on user-controlled input used as authorization gates, which can be trivially bypassed.
- WRD-830Family: gating-condition flaw (always-true logic)
- WRD-825Family: gating-condition flaw (spoofable identity)
Detects base64-encoded strings, hex-encoded strings, or decode operations in non-run contexts (env blocks, with: inputs)
Detects actions/cache usage in release or elevated-permission workflows where a poisoned cache could compromise builds
Detects write-all permissions, missing permissions blocks, or unnecessary write grants.
- WRD-812Escalates to high when paired with a risky trigger
- WRD-840Companion: undocumented permissions entries
Detects if-conditions checking github.actor against bot names (dependabot[bot], renovate[bot], github-actions[bot]), which can be spoofed by renaming a user account.
- WRD-830Family: gating-condition flaw (always-true logic)
- WRD-816Family: gating-condition flaw (substring match abuse)
- WRD-810Companion: confused-deputy on auto-merge often relies on this same spoofable check
Detects if: conditions whose value is constant at parse time: always-true (if: true, if: always(), 1==1), always-false (if: false, 1==0), and tautological or contradictory calls to contains(), startsWith(), or endsWith() over two string literals. Also unwraps ${{ ... }} wrappers.
- WRD-816Family: gating-condition flaw (substring match abuse)
- WRD-825Family: gating-condition flaw (spoofable identity)
Detects permissions entries that lack an explanatory comment
Detects setup actions that may be unnecessary because the tool is already pre-installed on GitHub-hosted runners
Detects workflows triggered by push or pull_request that lack a concurrency block, which can lead to resource exhaustion
Detects workflow files missing a top-level 'name:' key