DevSecOps Pipeline Implementation: My Standard Stack
When I join a project as a Fractional Security Lead, the first technical thing I do is fix the CI/CD pipeline.
Most startups either have zero security checks or they've turned on every possible scanner, flooded their logs with false positives, and then ignored everything.
Here is the standard "paved road" pipeline I implement. It's designed to catch 80% of low-hanging fruit (secrets, old dependencies, critical vulnerabilities) without adding more than 3 minutes to build time.
The Philosophy: Fail Fast, Scan Deep Later #
Developers hate security tools that block PRs for minor issues. My rule is simple: Block on Critical, Warn on High, Ignore the rest.
If a vulnerability isn't exploitable or critical, it goes into the backlog, not the blocker list.
The Toolchain #
I stick to open-source and standard industry tools. No proprietary vendor lock-in unless necessary.
- Secrets:
gitleaks(The best secret scanner, period). - SCA (Dependencies):
trivyordependabot(GitHub native). - SAST (Code Quality):
semgrep(Faster and more customizable than SonarQube for most modern stacks). - Container Scanning:
trivy.
The Pipeline (GitHub Actions) #
Here is a production-ready workflow. Copy-paste this into .github/workflows/security.yml.
name: Security Audit
on:
pull_request:
branches: [ "main" ]
push:
branches: [ "main" ]
schedule:
- cron: '0 0 * * 0' # Weekly scan
jobs:
security-scan:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v4
# 1. Secret Scanning (Blocker)
# If this fails, someone committed a key. Stop immediately.
- name: Detect Secrets
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# 2. Dependency Scanning (SCA)
# We use Trivy here for speed.
- name: Scan Dependencies
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
trivy-config: trivy.yaml
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
# 3. Static Analysis (SAST)
# Semgrep scans your actual code logic.
- name: Semgrep Security Scan
uses: returntocorp/semgrep-action@v1
with:
config: >-
p/security-audit
p/secrets
p/owasp-top-ten
# 4. Upload Results to GitHub Security Tab
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'trivy-results.sarif'
Configuration Details #
Gitleaks (.gitleaks.toml) #
Don't rely on defaults. You likely have test keys or legacy strings that will trigger alerts. Use a .gitleaksignore file to whitelist known false positives, rather than disabling the rule entirely.
Semgrep #
I prefer Semgrep over SonarQube for startups because it's lightweight. The p/owasp-top-ten ruleset is usually enough to catch:
- SQL Injection
- Hardcoded secrets (as a backup)
- Unsafe deserialization
- Disabled CSRF tokens
Deployment Gating #
The scan above runs on PRs. But should it block deployment?
My recommendation:
- Secrets: YES. Block deployment immediately.
- Critical Vulnerabilities: YES. Block, unless explicitly overridden by a senior engineer.
- High/Medium: NO. Alert on Slack, create a Jira ticket, but let the deploy go through. Velocity is life for a startup.
Beyond the Pipeline #
This pipeline is the baseline. Once this is running, I typically look at:
- Runtime Security: Implementing
Falcoin Kubernetes to detect if a container starts behaving strangely (e.g., spawning a shell). - Cloud Security: using
ProwlerorCheckovto scan Terraform/AWS configs.
If you're building this yourself, start with just Gitleaks. If you want someone to set this up, tune the noise, and train your team on how to read the reports, get in touch.
Nikita Mosievskiy
Security Engineer & AI Researcher