← Back to blog

Blocking Unsafe Code: Security Audits in GitHub Actions

Published September 1, 2025 · Updated September 17, 2025
6 min read
GitHub Actions
Ruby
Security
Supply Chain
DevSecOps

The Problem: When a Deploy Becomes a Risk

Tests are green, code is merged to main, deploy ships — and a week later a critical CVE drops for one of your gems. It’s already exploited in the wild. You learn about it from X or Hacker News. If that story rings a bell, this guide is for you.

The Solution: Security-First CI/CD

Add automated checks that fail the build when vulnerabilities or license issues are detected. If the audit is red, the deploy simply won’t start. That’s the whole point: make the safe path the default path.

What We Check (and With What)

  • Dependency vulnerabilitiesbundler-audit (RubySec database).
  • Licenseslicense_finder (e.g., block GPL in commercial apps).
  • Multi-ecosystem scan — Google OSV Scanner (great for polyglot repos).
1# Install tools locally (example)
2gem install bundler-audit license_finder
3
4# Vulnerability check
5bundle audit check --update
6
7# License check
8license_finder --quiet

Option 1: All-in-One Workflow (Recommended)

If your deploy.yml isn’t huge, add an audit job there and make the deploy depend on it.

1name: Deploy
2
3on:
4  push:
5    branches: [ main ]
6  pull_request:
7    paths: ['Gemfile*', '*.gemspec']
8  schedule:
9    - cron: '0 8 * * MON'  # Weekly security check
10
11jobs:
12  audit:
13    name: Security & License Audit
14    runs-on: ubuntu-latest
15    steps:
16      - name: Checkout code
17        uses: actions/checkout@v4
18
19      - name: Setup Ruby
20        uses: ruby/setup-ruby@v1
21        with:
22          ruby-version: .ruby-version
23          bundler-cache: true
24
25      - name: Install audit tools
26        run: |
27          gem install bundler-audit license_finder
28
29      - name: Vulnerability scan
30        run: bundle audit check --update
31
32      - name: License compliance
33        run: license_finder --quiet
34
35      # --- OSV: way 1 (via action) ---
36      - name: OSV scan (action)
37        uses: google/osv-scanner-action@v1
38        with:
39          scan-args: '--recursive --skip-git .'
40
41      # --- OSV: way 2 (fallback, without action) ---
42      # - name: OSV scan (binary)
43      #   run: |
44      #     curl -sSL https://raw.githubusercontent.com/google/osv-scanner/main/scripts/install.sh | sh -s -- -b /usr/local/bin
45      #     osv-scanner --recursive --skip-git .
46
47  deploy:
48    needs: [audit] # ← deploy won't start until audit is green
49    runs-on: ubuntu-latest
50    steps:
51      - uses: actions/checkout@v4
52      # ... your deploy steps
53

“Unresolved action/workflow reference” in CI?

Use a valid action ref from the action’s README. If the marketplace action is unavailable, install OSV as a binary (fallback in the snippet) — reliable and vendor-neutral.

Option 2: Split Audit and Deploy (For Larger Repos)

Put the audit in a dedicated workflow and trigger deploy only after it completes successfully.

1# .github/workflows/audit.yml
2name: Security Audit
3
4on:
5  pull_request:
6    paths: ['Gemfile*', '*.gemspec']
7  push:
8    branches: [ main ]
9  schedule:
10    - cron: '0 8 * * MON'
11
12jobs:
13  audit:
14    runs-on: ubuntu-latest
15    steps:
16      - uses: actions/checkout@v4
17      - uses: ruby/setup-ruby@v1
18        with:
19          ruby-version: .ruby-version
20          bundler-cache: true
21      - name: Install tools
22        run: gem install bundler-audit license_finder
23      - name: Vulnerability scan
24        run: bundle audit check --update
25      - name: License compliance
26        run: license_finder --quiet
27      - name: OSV scan
28        uses: google/osv-scanner-action@v1
29        with:
30          scan-args: '--recursive --skip-git .'
31
1# .github/workflows/deploy.yml
2name: Deploy
3
4on:
5  workflow_run:
6    workflows: ["Security Audit"]
7    types: [completed]
8
9jobs:
10  deploy:
11    if: ${{ github.event.workflow_run.conclusion == 'success' }}
12    runs-on: ubuntu-latest
13    steps:
14      - uses: actions/checkout@v4
15      # ... your deploy steps
16

When to Run It

Run audits where they matter most, and add a weekly check to catch new advisories:

1pull_request:
2  paths: ['Gemfile*', '*.gemspec']  # audit only when dependencies change
3
4schedule:
5  - cron: '0 8 * * MON'             # Monday morning security check
6
7push:
8  branches: [ main ]                 # for the split audit.yml approach
9

What Happens When Issues Appear

  1. Vulnerability found: audit fails → deploy doesn’t start → production stays safe.
  2. License conflict: license_finder flags GPL, etc. → deploy is blocked → team is notified.
  3. All clear: everything is green → deploy starts automatically.

Quick PR checklist

  • New dependency: why this one? Are there safer alternatives?
  • Is it actively maintained (recent releases, downloads)?
  • Supply-chain hygiene: pinned versions, trusted source, commit SHA for git dependencies?
  • Did the PR pass bundle audit and license checks?

Helpful Bundler Settings & OSV Alternatives

Bundler settings

1# Protect against mixed sources (source substitution)
2bundle config set disable_multisource true
3
4# Cache and cleanup
5bundle config set cache_all true
6bundle config set clean 'true'

Alternatives & add-ons

  • Snyk / Trivy as an extra layer alongside OSV.
  • If the OSV action is unavailable, install the CLI binary and run it.
  • Schedule a quarterly “dependency hygiene day” with your team.

About gem signatures

Signed releases are great but still uncommon. Keep defense-in-depth: audits + process + version pinning.

Wrap-up

Adding a mandatory audit step dramatically reduces the chance that vulnerable dependencies reach production. If anything goes red, the release doesn’t ship until it’s fixed — simple, predictable, safe.

My baseline: enable GitHub alerts, automate bundle audit and license checks, add OSV as a second layer, and run regular dependency hygiene with the team.

Want to strengthen your Ruby project’s supply-chain security?
Need help rolling out DevSecOps practices and dependency audits? I can set up CI, processes, and train the team.