← Back to blog
2026-07-22 · VulnLedger

"Python CI/CD Security: GitHub Actions for Python Projects"

Complete guide to setting up security scanning in GitHub Actions for Python projects. Covers dependency scanning, secret detection, SAST, SBOM generation, and security gates.

Python CI/CD GitHub Actions Security DevSecOps Automation SBOM

You've secured your Python code, scanned your dependencies, and hardened your containers. But none of that matters if an insecure commit slips through to production. CI/CD security gates are the final defense.

This guide shows you how to set up a complete Python security pipeline in GitHub Actions — from dependency scanning to SBOM generation, in one YAML file.

Why Python CI/CD Security Matters

Without automated security checks in CI/CD:

- A developer pushes code with a known CVE → nobody catches it

- A dependency gets updated → new vulnerability introduced

- A secret gets committed → leaked to the public

- An urgent hotfix skips security review → ships with issues

With CI/CD security gates:

- Every commit is scanned automatically

- Critical vulnerabilities fail the build

- SBOMs are generated for every release

- Security becomes part of the development process

The Complete Python Security Pipeline

name: Python Security Gate

on:
  pull_request:
    branches: [main, master]
  push:
    branches: [main, master]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Install security tools
        run: pip install vulnledger detect-secrets bandit

      - name: Scan dependencies
        run: vulnledger scan . --ci

      - name: Scan for secrets
        run: detect-secrets scan --all-files

      - name: Run security linter
        run: bandit -r . --severity-level medium --exit-zero

      - name: Run tests
        run: pytest --cov

      - name: Generate SBOM
        run: vulnledger scan . --json --output sbom.json

      - name: Upload SBOM
        uses: actions/upload-artifact@v4
        if: github.event_name == 'push'
        with:
          name: sbom-${{ github.sha }}
          path: sbom.json

What Each Step Does

1. Dependency Scanning

- name: Scan dependencies
  run: vulnledger scan . --ci

Checks every dependency (direct + transitive) against OSV.dev. The --ci flag fails the build if critical/high CVEs are found.

2. Secret Detection

- name: Scan for secrets
  run: detect-secrets scan --all-files

Scans every file for hardcoded API keys, passwords, and tokens. Prevents secrets from reaching production.

3. Security Linting

- name: Run security linter
  run: bandit -r . --severity-level medium --exit-zero

Python-specific security linting. Catches injection risks, insecure functions, and common security mistakes. --exit-zero means it reports but doesn't fail the build (you can remove this flag to make it a gate).

4. Tests

- name: Run tests
  run: pytest --cov

Tests catch regressions. If a dependency upgrade breaks something, the tests catch it.

5. SBOM Generation

- name: Generate SBOM
  run: vulnledger scan . --json --output sbom.json

Generates a CycloneDX SBOM for every build. Attach to releases for compliance.

Making It a Security Gate

To fail the build on security issues, remove --exit-zero from bandit and keep --ci on VulnLedger:

- name: Security gate
  run: |
    vulnledger scan . --ci  # Fails on critical/high CVEs
    bandit -r . --severity-level high  # Fails on high severity issues

Adding to Pull Request Checks

Configure branch protection to require the security job:

1. Go to repo Settings → Branches → main

2. Enable "Require status checks to pass"

3. Add "security" as a required check

Now no PR can merge without passing security scans.

Scheduled Security Scans

Scan weekly for new CVEs:

on:
  schedule:
    - cron: '0 8 * * 1'  # Monday at 8 AM
  workflow_dispatch:

jobs:
  weekly-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pip install vulnledger
      - run: vulnledger scan . --json --output weekly-scan.json
      - uses: actions/upload-artifact@v4
        with:
          name: weekly-scan
          path: weekly-scan.json

Best Practices

1. Scan on every PR — not just main

2. Fail the build — critical CVEs must block merges

3. Generate SBOMs — attach to every release

4. Schedule scans — catch new CVEs weekly

5. Keep tools updatedpip install --upgrade vulnledger

6. Cache dependencies — speed up CI runs

Python-Specific CI/CD Tips

Cache pip packages

- name: Cache pip
  uses: actions/cache@v4
  with:
    path: ~/.cache/pip
    key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}

Use matrix testing

strategy:
  matrix:
    python-version: ["3.10", "3.11", "3.12"]

Publish SBOM to releases

- name: Upload SBOM to release
  uses: softprops/action-gh-release@v2
  if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
  with:
    files: sbom.json

How VulnLedger Fits In

VulnLedger provides the core security scanning for your Python CI/CD pipeline:

- Dependency scanning — catches CVEs before they reach production

- SBOM generation — compliance-ready dependency inventory for every build

- CI gate — fails builds on critical/high CVEs

- Works with all Python package managers — pip, Poetry, pipenv, conda

- name: Security scan
  run: |
    pip install vulnledger
    vulnledger scan . --ci
    vulnledger scan . --json --output sbom.json

Conclusion

Python CI/CD security is the final defense against vulnerable code reaching production. One YAML file adds dependency scanning, secret detection, security linting, testing, and SBOM generation. The setup takes 10 minutes. The protection is permanent.

This is the final post in the "Python Security Handbook" series. Here's the complete list:

1. Python Security Best Practices 2026 — Overview

2. Securing Your Python Dependencies — Dependency security

3. Python Web App Security: Flask, FastAPI, Django — Web hardening

4. Python Container Security: Docker + Python — Container security

5. This post — CI/CD automation

Together with all other series, you now have 27 blog posts covering:

- How to Write Safe Software (5 posts)

- Open Source Security (4 posts)

- The SBOM Handbook (6 posts)

- Vibe Coding (3 posts)

- Python Security Handbook (5 posts)

- Standalone: Dependabot, Container Scanning, CI/CD

That's 27 posts forming a comprehensive security knowledge base, all linking to each other and to VulnLedger.

Try VulnLedger

Generate SBOMs and scan for vulnerabilities in one command.

Start Free