Skip to main content

02 - Security in CI/CD Pipelines

security-in-ci/cd-pipelines', 'appsec', 'security', 'compliance']

02 - Security in CI/CD Pipelines

A mature DevSecOps pipeline automates various security checks. This chapter covers the core scanners and provides a complete GitHub Actions example.

Core Pipeline Integrations

1. Secret Scanning (e.g., TruffleHog, Gitleaks)

Goal: Prevent hardcoded passwords, API keys, and tokens from entering the codebase.

  • When to run: Pre-commit hooks (locally) and on every Push/PR.
  • Action: Break the build immediately if a secret is found.

2. Static Application Security Testing (SAST) (e.g., Semgrep, CodeQL)

Goal: Analyze source code for security vulnerabilities (e.g., SQLi, XSS) without executing it.

  • When to run: On Pull Requests.
  • Action: Comment on the PR with findings. Break the build for High/Critical issues.

3. Software Composition Analysis (SCA) (e.g., Trivy, Snyk, Dependabot)

Goal: Detect known vulnerabilities (CVEs) in third-party open-source dependencies and container images.

  • When to run: On Pull Requests and daily on the default branch.
  • Action: Generate a Software Bill of Materials (SBOM) and block builds introducing new Critical CVEs.

4. Dynamic Application Security Testing (DAST) (e.g., OWASP ZAP, Nuclei)

Goal: Interact with a running application from the outside to find runtime vulnerabilities (e.g., misconfigurations, authentication bypass).

  • When to run: After deployment to a staging or QA environment.
  • Action: Alert the security team; rarely breaks the build automatically due to longer run times and potential false positives.

💻 GitHub Actions DevSecOps Pipeline Example

Below is a production-ready GitHub Actions workflow (.github/workflows/devsecops.yml) that integrates Secret Scanning, SAST, and SCA for a Dockerized Node.js application.

name: DevSecOps Pipeline

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
secret-scanning:
name: Secret Scanning (TruffleHog)
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0 # TruffleHog needs history

- name: Run TruffleHog
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD
extra_args: --only-verified

sast-semgrep:
name: SAST (Semgrep)
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4

- name: Run Semgrep CI
uses: returntocorp/semgrep-action@v1
with:
config: "p/default"
generateSarif: "1"

- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: semgrep.sarif

sca-container-scan:
name: SCA & Container Scan (Trivy)
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4

- name: Build Docker Image
run: docker build -t my-app:${{ github.sha }} .

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'my-app:${{ github.sha }}'
format: 'table'
exit-code: '1'
ignore-unfixed: true
vuln-type: 'os,library'
severity: 'CRITICAL,HIGH'

[!TIP] Pro Tip: Always automate your security and compliance checks early in the pipeline to reduce manual overhead and ensure continuous compliance.

Share this guide