Skip to content
ComplianceFebruary 28, 20266 min read

DevSecOps for Startups: How to Embed Security into Your CI/CD Pipeline

Security reviews at startups typically happen after something goes wrong. DevSecOps moves security earlier - into the CI pipeline, not the post-incident review. Here's a practical setup that catches vulnerabilities before they reach production.

The standard startup security posture: ship fast, do a security review before Series B, discover that base images have 40 critical CVEs, secrets are in .env files, and the database is publicly accessible. Then spend two weeks doing emergency remediation.

DevSecOps is the discipline of moving that security work left - into the development and CI process, not the fundraising process. Done right, it adds 5–10 minutes to a CI pipeline and catches 80% of the problems that show up in penetration tests.

The Four Gates

Security in CI/CD works as four gates. Each gate runs in the pipeline and blocks a deploy if it fails above a threshold.

Gate 1: Static Analysis (SAST)

SAST tools scan your source code for security vulnerabilities - SQL injection patterns, hardcoded credentials, insecure cryptography, missing input validation.

Semgrep is the best open-source option. Fast, extensible, and free:

yaml
# .github/workflows/security.yaml name: Security on: [push, pull_request] jobs: sast: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run Semgrep SAST uses: semgrep/semgrep-action@v1 with: config: >- p/owasp-top-ten p/nodejs p/secrets auditOn: push env: SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}

Semgrep runs rules against your source code and fails the pipeline if it finds critical issues. The p/secrets ruleset catches hardcoded API keys, passwords, and tokens in code. The p/owasp-top-ten ruleset catches injection, XSS, and other common vulnerabilities.

Gate 2: Dependency Scanning (SCA)

Software Composition Analysis scans your package dependencies for known CVEs. The average Node.js application has 700+ transitive dependencies - most developers have no idea what CVEs are in there.

yaml
dependency-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run Trivy dependency scan uses: aquasecurity/trivy-action@master with: scan-type: fs scan-ref: . format: table exit-code: 1 severity: CRITICAL,HIGH ignore-unfixed: true # skip CVEs with no fix available

Trivy scans package.json, requirements.txt, go.mod, Gemfile, etc. and fails the pipeline on HIGH or CRITICAL CVEs that have available fixes. The ignore-unfixed flag prevents noise from CVEs the maintainers have not patched yet.

Gate 3: Container Image Scanning

Your application code might be clean. Your base image might not be. Alpine 3.14 and Ubuntu 20.04 base images have hundreds of known CVEs by now.

yaml
image-scan: runs-on: ubuntu-latest needs: [build] steps: - name: Run Trivy image scan uses: aquasecurity/trivy-action@master with: image-ref: ${{ secrets.ECR_REGISTRY }}/api:${{ github.sha }} format: sarif output: trivy-results.sarif exit-code: 1 severity: CRITICAL ignore-unfixed: true - name: Upload scan results to GitHub Security uses: github/codeql-action/upload-sarif@v3 with: sarif_file: trivy-results.sarif

Use minimal base images. The fewer packages, the fewer vulnerabilities:

dockerfile
# Before: fat image, 200+ CVEs FROM node:18 # After: minimal image, <10 CVEs FROM node:18-alpine # Even better: distroless FROM gcr.io/distroless/nodejs18-debian12

Gate 4: Infrastructure as Code Scanning

Your Terraform, Helm charts, and Kubernetes manifests may have security misconfigurations - public S3 buckets, overly permissive IAM policies, missing pod security contexts.

yaml
iac-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run Checkov IaC scan uses: bridgecrewio/checkov-action@master with: directory: . framework: terraform,kubernetes,helm soft_fail: false check: CKV_K8S_8,CKV_K8S_9,CKV_K8S_11,CKV_K8S_14,CKV_K8S_20

Key checks for Kubernetes:

  • CKV_K8S_8 - liveness probe defined
  • CKV_K8S_9 - readiness probe defined
  • CKV_K8S_11 - no privileged containers
  • CKV_K8S_14 - image not using latest tag
  • CKV_K8S_20 - containers not running as root

Runtime Security with Falco

The CI pipeline catches issues before deployment. Falco catches suspicious behaviour at runtime - in production.

bash
helm repo add falcosecurity https://falcosecurity.github.io/charts helm upgrade --install falco falcosecurity/falco \ --namespace falco \ --create-namespace \ --set falco.json_output=true \ --set falcosidekick.enabled=true \ --set falcosidekick.config.slack.webhookurl=$SLACK_WEBHOOK

Falco rules that matter:

yaml
# Alert when a container writes to /etc - rule: Write below etc desc: Container wrote to /etc directory condition: > open_write and container and fd.name startswith /etc output: > Write to /etc in container (user=%user.name command=%proc.cmdline container=%container.id image=%container.image.repository) priority: WARNING # Alert when a shell is spawned in a container - rule: Terminal shell in container desc: A shell was used as the entrypoint or dropped condition: > spawned_process and container and shell_procs and proc.tty != 0 output: > Shell spawned in container (user=%user.name container=%container.id image=%container.image.repository shell=%proc.name parent=%proc.pname) priority: NOTICE

These rules detect common attack patterns: an attacker who gains code execution in your container will typically spawn a shell.

Secret Scanning

Before secrets reach the pipeline, catch them at commit time with pre-commit hooks:

bash
# Install gitleaks brew install gitleaks # Add to .pre-commit-config.yaml repos: - repo: https://github.com/gitleaks/gitleaks rev: v8.18.0 hooks: - id: gitleaks

And scan the repository history for already-committed secrets:

bash
gitleaks detect --source . --verbose

If secrets are found in history, rotate them immediately. Then use git filter-repo (not git filter-branch) to remove them from history. Assume they are already compromised.

The SOC2 / ISO 27001 Connection

These four gates map directly to SOC2 and ISO 27001 controls:

GateSOC2 CCISO 27001
SASTCC6.1 - Logical and Physical AccessA.14.2 - Security in development
Dependency scanCC6.1 - Vulnerability managementA.12.6 - Management of technical vulnerabilities
Image scanCC6.1 - Change managementA.12.6 - Technical vulnerability management
IaC scanCC6.6 - Network securityA.13.1 - Network controls
Runtime (Falco)CC7.2 - Anomaly detectionA.12.4 - Logging and monitoring

When your auditor asks "how do you detect vulnerabilities in your software?", your answer is a CI pipeline that blocks deploys on critical CVEs, documented and provable.

Getting Started

If you are starting from zero: implement in this order.

Week 1: Add Trivy dependency scanning to CI. Fix CRITICAL CVEs in your dependencies. Update your base images to current Alpine or Debian slim.

Week 2: Add Semgrep SAST with the secrets ruleset. Remediate any hardcoded credentials. Set up gitleaks pre-commit hook.

Week 3: Add IaC scanning (Checkov). Fix pod security contexts - drop root, add readOnlyRootFilesystem, set resource limits.

Week 4: Add container image scanning. Set up Falco for runtime.

Each week is independent. Week 1 alone eliminates most of what shows up in penetration tests.


Preparing for SOC2 or ISO 27001? Book a free audit - we will assess your current security posture and give you a gap analysis against the controls you need.

RK
RKSSH LLP
DevOps Engineer · rkssh.com

I help funded startups fix their CI/CD pipelines and Kubernetes infrastructure. If this post was useful and you want to talk through your specific situation, book a free 30-minute audit.

Related Articles