DEV Community

Olivier Buitelaar
Olivier Buitelaar

Posted on

I Built a Free GitHub Action That Catches Workflow Security Issues Before Production

The Problem

My team spent an afternoon debugging why our deploy workflow wasn't triggering on certain PRs. Turns out a paths filter had a glob pattern that looked right but matched nothing due to how GitHub evaluates path filters.

The YAML was valid. CI was "passing." We just weren't running the jobs we thought we were.

That's the kind of bug that's invisible until it isn't.

The Solution: workflow-guardian

I made workflow-guardian to catch that entire class of problem. Add it to your workflows and it statically analyzes all your .github/workflows/*.yml files on every PR.

Quick Start

- uses: ollieb89/workflow-guardian@v1
Enter fullscreen mode Exit fullscreen mode

That's it. One line.

What It Catches

🔒 Unpinned Actions (Supply Chain Risk)

Using actions/setup-node@v4 means you're trusting that the tag hasn't been moved to malicious code. workflow-guardian flags these and suggests the exact SHA pin:

❌ deploy.yml:14
   Action 'actions/setup-node@v4' is not pinned to a SHA.
   Fix: actions/setup-node@1a4442cacd436585916779262731d1f68189e2a8
Enter fullscreen mode Exit fullscreen mode

🛡️ Security Footguns

pull_request_target with actions/checkout using the PR head SHA is a well-known exploit vector. workflow-guardian catches it:

❌ pr-checks.yml:8
   'pull_request_target' trigger with 'actions/checkout' using
   github.event.pull_request.head.sha is exploitable.
Enter fullscreen mode Exit fullscreen mode

⚠️ Deprecated Commands

Still using set-output? GitHub deprecated it months ago:

⚠️ ci.yml:31
   Deprecated command 'set-output' detected.
   Fix: Use $GITHUB_OUTPUT instead.
Enter fullscreen mode Exit fullscreen mode

🐛 Path Filter Bugs

Glob patterns that look correct but silently match nothing — the exact bug that cost us an afternoon.

📊 Matrix Config Errors

Bad include/exclude combos that create unexpected job matrices.

How It Works

  • Pure static analysis — no external API calls
  • Everything runs in your own runner
  • Posts a clear comment on every PR
  • Zero config needed, just add the action

What's Next

I'm planning to add:

  • Custom rule definitions
  • SARIF output for GitHub Security tab integration
  • Auto-fix PRs for simple issues

Links

Feedback, feature requests, and edge cases welcome — open an issue!


Also just shipped test-results-reporter — aggregates JUnit/Jest/pytest results into clean PR comments with flaky test detection. Check it out if you're drowning in test output.

Top comments (0)