Security can no longer be bolted on at the end of your pipeline — it must be integrated throughout. That’s the promise of DevSecOps: infuse security practices directly into your CI/CD process.
In this article, we’ll break down practical steps to embed security in your pipelines, with examples you can adapt to your own workflow.
Why DevSecOps Matters
Modern applications ship fast, sometimes several times per day. If you wait until a separate “security team” does its review, you’ll either slow down or ship insecure code.
DevSecOps means:
- Security testing is automated
- Security scanning happens early
- Security issues block bad builds
Let’s see what this looks like in practice.
DevSecOps in a CI/CD Pipeline: Step by Step
We’ll use GitHub Actions as an example, but these patterns apply to any pipeline (GitLab CI, Jenkins, etc.)
Static Application Security Testing (SAST)
Goal: Find code-level vulnerabilities early.
You can integrate open-source SAST tools like CodeQL or SonarQube.
GitHub Actions with CodeQL Example:
# .github/workflows/codeql.yml
name: "CodeQL"
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
- Finds common security bugs at pull request time
- Prevents vulnerable code from merging
Dependency Scanning
Goal: Stop using vulnerable dependencies.
You can automate checks with tools like:
npm audit
yarn audit
safety
for Pythontrivy
for containers
GitHub Actions npm audit example:
# .github/workflows/audit.yml
name: Audit dependencies
on: [push]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install
run: npm ci
- name: Audit
run: npm audit --audit-level=high
- Fails the build if high vulnerabilities are detected.
Secret Scanning
Goal: Detect secrets in your code before they reach production.
Tools:
Gitleaks example:
# .github/workflows/gitleaks.yml
name: Secrets Scan
on: [push]
jobs:
secrets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Gitleaks
uses: gitleaks/gitleaks-action@v2
with:
args: --verbose
- Blocks accidental commits of API keys, passwords, or tokens.
Container Vulnerability Scanning
If you build Docker images, scan them before pushing to a registry.
Trivy example:
# .github/workflows/trivy.yml
name: Container scan
on: [push]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build container
run: docker build -t myapp:latest .
- name: Run Trivy vulnerability scan
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:latest
Prevents known CVEs from reaching production images.
Infrastructure as Code (IaC) Security
If you use Terraform, CloudFormation, or Kubernetes manifests, you can scan them with:
- Checkov
- tfsec
- kube-score
Checkov example for Terraform:
# .github/workflows/checkov.yml
name: IaC Security
on: [push]
jobs:
checkov:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Checkov
uses: bridgecrewio/checkov-action@master
with:
directory: .
- Finds misconfigurations in security groups, S3 buckets, IAM roles, etc.
Putting It All Together
With these tools, your CI/CD becomes a security gate instead of a security afterthought. A typical DevSecOps pipeline will:
- run SAST for code bugs
- scan dependencies for CVEs
- check for secrets
- scan Docker images
- validate Infrastructure as Code
This way, insecure code is caught before it ever hits production.