Skip to content

shoulderdev-demos/github-actions

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 

Repository files navigation

Shoulder CLI — GitHub Actions demo repo

A collection of deliberately-vulnerable GitHub Actions workflows used to demonstrate the Shoulder CLI github-actions-* detection rules.

Each .yml in .github/workflows/ is a self-contained example that triggers one primary rule. The matching .md next to it explains the issue, links to the relevant research, and shows the fixed version.

View the online rendered scan

A live, web-rendered view of what shoulder trust produces on this repo. Useful for skimming the catch list, sharing a link in review, or seeing the findings without installing the CLI locally.

The "malicious" run commands and exfil URLs in these workflows are inert — base64 strings decode to echos, webhook URLs point at example.com. Every workflow uses workflow_dispatch or another non-auto trigger to avoid accidentally running.

Quick start

# Scan everything
shoulder trust

# Scan one rule's example
shoulder trust .github/workflows/shell-injection.yml

Rules covered

24 demos, one workflow per rule. Shoulder catches every one of them on the current dev-4c679890 build.

Core rules (single-line or single-step patterns)

# Rule Severity Workflow
1 ai-agent-untrusted-input CRITICAL ai-agent-untrusted-input.yml
2 secrets-exposure CRITICAL secrets-exposure.yml
3 unsafe-checkout CRITICAL unsafe-checkout.yml
4 malicious-run-commands CRITICAL malicious-run-commands.yml
5 ai-agent-yolo-mode HIGH ai-agent-yolo-mode.yml
6 bot-condition-spoof HIGH bot-condition-spoof.yml
7 deprecated-node-version HIGH deprecated-node-version.yml
8 insecure-commands HIGH insecure-commands.yml
9 shell-injection HIGH shell-injection.yml
10 unpinned-action HIGH unpinned-action.yml
11 unredacted-secrets HIGH unredacted-secrets.yml
12 workflow-dispatch-attacker-ref HIGH workflow-dispatch-attacker-ref.yml
13 cache-poisoning MEDIUM cache-poisoning.yml
14 checkout-persist-credentials MEDIUM checkout-persist-credentials.yml
15 excessive-permissions MEDIUM excessive-permissions.yml
16 missing-top-level-permissions MEDIUM missing-top-level-permissions.yml
17 secret-without-environment MEDIUM secret-without-environment.yml
18 secrets-inherit MEDIUM secrets-inherit.yml
19 unpinned-image MEDIUM unpinned-image.yml
20 unpinned-tools MEDIUM unpinned-tools.yml

Cross-boundary trust rules (taint-flow with named sinks)

State introduced by a less-trusted step flows into a privileged operation. Each row has a distinct sink so the remediation advice is specific.

# Rule Severity Workflow
21 ai-agent-untrusted-workspace CRITICAL ai-agent-untrusted-workspace.yml
22 local-action-from-untrusted-ref HIGH local-action-from-untrusted-ref.yml
23 untrusted-build-scripts-in-release HIGH untrusted-build-scripts-in-release.yml
24 workflow-run-untrusted-artifact HIGH workflow-run-untrusted-artifact.yml

PR demo — main..v2

The headline demo. The v2 branch is a single PR off main that adds one new AI-generated-looking workflow, .github/workflows/ai-pr-reviewer.yml. Run the diff:

shoulder trust diff main..v2

Shoulder reports 9 new risks on the one changed file — 2 critical (unsafe-checkout, ai-agent-untrusted-input), 2 high (shell-injection), 5 medium. Nothing is reported on files the PR doesn't touch.

Per-rule regression branches

The five highest-impact rules also have secure-baseline branches so you can demo what a "good PR that quietly turns bad" looks like for a single rule:

  • secure-<rule> — same as main, but with only that one workflow fixed. The "safe" starting point.
  • regression-<rule> — branched from secure-<rule> and reintroduces the vulnerability in a single commit.

Diff one against the other — no checkout required:

shoulder trust diff secure-shell-injection..regression-shell-injection
Rule Diff command
shell-injection shoulder trust diff secure-shell-injection..regression-shell-injection
unsafe-checkout shoulder trust diff secure-unsafe-checkout..regression-unsafe-checkout
unpinned-action shoulder trust diff secure-unpinned-action..regression-unpinned-action
excessive-permissions shoulder trust diff secure-excessive-permissions..regression-excessive-permissions
secrets-exposure shoulder trust diff secure-secrets-exposure..regression-secrets-exposure

How Shoulder compares

Scored against this repo's 24 demos (full point for catching the intended rule, half for a generic/weaker match, zero for a miss):

Tool Score Notes
Shoulder 24.0 / 24 Only tool catching every demo. Unique on the AI-agent rule family, CVE/advisory enrichment, container-image pinning, curl | bash detection, EOL-runtime warnings, and workflow_run taint-source modelling.
Zizmor 11.5 / 24 Strong on line precision (every ${{ }} flagged), good coarse dangerous-triggers net. No AI-agent rules, no CVE enrichment, no malware-pattern detection.
Poutine 8.0 / 24 Smallest ruleset but the deepest taint-flow modelling of the OSS tools. Its untrusted_checkout_exec rule emits named sinks (npm, setup-node, ./.github/actions/build) with sink-specific remediation. No AI-agent or workflow_run coverage.
Semgrep OSS 3.5 / 24 Two GHA rules ship by default. Not really competing on this surface — Semgrep's focus is app-code SAST.

Each tool has a different sweet spot. Shoulder leads on coverage breadth and AI-era patterns; Poutine has the closest architectural match on cross-boundary trust; Zizmor is the best free per-line linter for the common patterns it does cover.

Background reading

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors