10 GitHub Actions Mistakes That Will Burn You (And How to Avoid Them)
I've spent the last year auditing and fixing GitHub Actions across 17+ repositories. Some mistakes are embarrassing. Some are dangerous. Most are avoidable.
Here are the ten I see over and over—and exactly how to fix them.
1. Logging Secrets (The Classic)
You're debugging a failed workflow. The obvious thing to do is echo your environment variables. So you do:
- name: Debug
run: echo "Token is: ${{ secrets.GITHUB_TOKEN }}"
The logs are public. Everyone sees it. Congratulations, your secret is now on the internet.
The fix:
- Never echo secrets in plain text
- Use
::add-mask::to mask values:
- name: Debug
run: |
echo "::add-mask::$(echo 'sensitive-value')"
echo "Processing: $(echo 'sensitive-value')"
Workflow Guardian catches this by analyzing your workflow YAML for secret exposure patterns. Set it up once, sleep better.
2. Using Always-Green Credentials (No Secret Rotation)
You created a Personal Access Token (PAT) in 2023 for a GitHub Actions workflow. It's still there. It's never been rotated. It has full repo access. If compromised, the attacker has the same permissions you do.
The fix:
- Use fine-grained PATs with minimal scopes
- Set expiration dates (90-180 days)
- Rotate before expiry
- For CI/CD, prefer GitHub's built-in
${{ secrets.GITHUB_TOKEN }}(auto-scoped, auto-rotated)
3. Running Untrusted Code from pull_request Events
A user forks your repo, adds a malicious GitHub Action to their fork, opens a PR. Your workflow runs that action. They exfiltrate your secrets.
The fix: Use pull_request_target for workflows that need access to secrets, but check out the base branch. Or require approval before untrusted code runs.
4. No Timeout on Long-Running Jobs
A workflow gets stuck. No one notices. It runs for 6 hours. You burn free tier minutes for nothing.
The fix: Set timeout-minutes globally and per-job to kill stuck workflows automatically.
5. Hardcoding Environment Values (Config in Code)
You put API endpoints, database hosts, and feature flags directly in your workflow YAML. Now config is versioned, visible in diffs, and mixed with logic.
The fix: Use secrets for anything environment-specific, or repository variables for non-sensitive config.
6. No Artifact Cleanup (Storage Bloat)
You upload test results, build artifacts, and logs every run. You've never deleted them. Your storage bill is climbing.
The fix: Set explicit retention-days on artifact uploads to clean up automatically after a week or month.
7. Ignoring Exit Codes (Always Succeeding)
A step fails (exit code 1), but your workflow keeps running and marks the job as successful with || true.
The fix: Remove || true unless you really mean it. Use explicit error handling with continue-on-error: true when needed.
8. No Concurrency Control (Race Conditions in Deployments)
Two PRs merge simultaneously. Both trigger deployment workflows. Both write to production. Chaos.
The fix: Use concurrency to serialize sensitive jobs. For PR workflows, cancel previous runs on new push.
9. Large Monorepo, No Change Detection
You have 20 microservices in one repo. Every push runs tests for all services, even if you only changed one. Slow, expensive, unnecessary.
The fix: Use path filters to only run workflows for changed services. Or use tools like Nx or Turborepo to detect affected packages.
10. No Notifications on Failure (Silent Failures)
Your workflow fails. No one knows. Days pass. You merge something that depends on a broken workflow.
The fix: Notify on failure with Slack, email, or GitHub issues. Or set branch protection rules to require passing checks and enable notifications.
The Pattern
All ten of these mistakes stem from the same root cause: treating workflows like one-off scripts instead of production infrastructure.
Workflows run on every commit. They have access to your secrets. They can deploy to production. They touch customer data. Treat them accordingly.
Three things to do right now:
- Audit your workflows — look for secrets in logs, overpermissioned tokens, and race conditions
- Use Workflow Guardian — it catches most of these patterns automatically
- Version your workflow logic — don't inline deployment scripts; reference tested, reviewed code
Toolkit Links:
- Workflow Guardian — Detects security issues in your GitHub Actions YAML before production
- GitHub Actions Security Toolkit — Everything to secure your workflows
- PR Size Checker — Catch big PRs before they ship
- Test Result Aggregator — All test results in one place
Have you hit any of these? What's your biggest workflow mistake? Hit reply.
Top comments (0)