All articles
DevSecOpsCI/CDWeb Security

Catching Security Issues Before Production: CI/CD Scanning That Works

Practical patterns for automated security scanning for deployment pipelines — what to run, when to run it, and how to avoid breaking velocity.

WebSentry TeamJune 8, 20266 min read

Deploying a misconfigured Content-Security-Policy or a missing Strict-Transport-Security header on a Friday afternoon is the kind of mistake nobody notices until a pen-tester (or a customer's CISO) files a report weeks later. Automated security scanning for deployment pipelines exists precisely to catch these silent regressions before they reach users — but most teams either bolt on scanners that produce noise no one reads, or skip the step entirely because it slows builds down.

This post lays out a concrete approach: which scans belong at which pipeline stage, how to wire them in without wrecking deploy times, and how to handle the inevitable flood of findings on day one.

Why pipeline-stage scanning beats periodic audits

Quarterly audits find issues months after they shipped. By that point, the developer who introduced the regression has context-switched four times, and rolling back is rarely an option. Pipeline scanning shifts the feedback loop from weeks to minutes:

  • Issues are tied to a specific commit and author
  • Fixes happen while the code is still in working memory
  • Security becomes a build signal, not a separate workflow
  • Compliance evidence (SOC 2, ISO 27001) is generated automatically

The tradeoff is that you need to be deliberate about what runs where, or your 90-second build becomes a 25-minute slog.

The four scan layers every pipeline needs

1. Dependency and SBOM scanning (pre-commit / PR)

Run these on every pull request. They're fast and catch the highest-frequency class of vulnerabilities.

  • npm audit, pip-audit, or Snyk for known CVEs in dependencies
  • Syft or CycloneDX to generate a Software Bill of Materials
  • Trivy for container base image vulnerabilities

Fail the build on high/critical CVEs with available patches. Warn on everything else.

2. Static analysis (PR / merge to main)

SAST tools read your source code for dangerous patterns — SQL injection, XSS sinks, hardcoded secrets, insecure deserialization.

  • Semgrep for fast, rule-based scans (free tier handles most cases)
  • GitLeaks or TruffleHog for committed secrets
  • CodeQL if you're on GitHub and want deeper semantic analysis

Run Semgrep and GitLeaks on every PR. Reserve CodeQL for nightly runs against main — it's thorough but slow.

3. Infrastructure-as-code scanning (PR)

If you deploy via Terraform, CloudFormation, Kubernetes manifests, or Helm charts, IaC scanning catches misconfigurations before they become production reality.

  • Checkov or tfsec for Terraform
  • kube-score or Kubesec for Kubernetes
  • cfn-nag for CloudFormation

Typical catches: public S3 buckets, security groups open to 0.0.0.0/0, missing encryption at rest, containers running as root.

4. Runtime / DAST scanning (staging post-deploy)

This is the layer most teams skip — and it's where the highest-impact issues hide. Once a build is deployed to staging, you can scan the actual running application for problems that only exist at runtime: header misconfigurations, TLS issues, cookie flags, CORS policy mistakes, CSP gaps, mixed content.

This is where a tool like WebSentry fits cleanly. After your staging deploy completes, hit the WebSentry API (or trigger a scan via webhook) against the staging URL and fail the pipeline if the grade drops below your threshold — say, a B. Because it tests the live response, it catches things SAST never will: a CDN stripping your CSP header, a load balancer downgrading TLS, or a recent cookie change that lost the Secure flag.

A concrete GitHub Actions example

Here's a trimmed pipeline that demonstrates the layering:

name: ci
on: [pull_request, push]

jobs:
  fast-checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Secret scan
        uses: gitleaks/gitleaks-action@v2
      - name: SAST
        uses: returntocorp/semgrep-action@v1
      - name: Dependency audit
        run: npm audit --audit-level=high
      - name: IaC scan
        run: checkov -d ./infra

  deploy-staging:
    needs: fast-checks
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - run: ./deploy.sh staging

  runtime-scan:
    needs: deploy-staging
    runs-on: ubuntu-latest
    steps:
      - name: WebSentry scan
        run: |
          curl -X POST https://websentry.dev/api/scan             -H "Authorization: Bearer ${{ secrets.WEBSENTRY_TOKEN }}"             -d '{"url":"https://staging.example.com","min_grade":"B"}'

Total added time on PRs: usually under two minutes. The runtime scan runs in parallel with smoke tests after staging deploys, so it doesn't extend the critical path.

Handling the day-one finding flood

The first time you turn this on against an existing codebase, you will get hundreds of findings. If you try to fix them all before merging, nothing ships. Use this triage approach:

  1. Baseline existing issues. Tools like Semgrep and Checkov support baseline files — accept current state as the floor, fail only on new findings.
  2. Set a severity gate. Block on critical/high only for the first month. Add medium after the team has cleared the backlog.
  3. Assign a security debt budget. One sprint ticket per week dedicated to clearing baselined findings, oldest first.
  4. Auto-create issues, don't email. Pipe findings into Jira or Linear with the offending file, line number, and rule ID. Nobody reads security emails.

Common mistakes that kill adoption

  • Failing builds on informational findings. If devs learn the security gate cries wolf, they'll add --skip-security flags and you've lost.
  • Running everything on every commit. Reserve heavy scans (CodeQL, full DAST sweeps) for nightly or pre-release pipelines.
  • Scanning production directly without coordination. Active scans can trigger WAFs, rate limits, or alerting. Scan staging; verify production with passive checks only.
  • No ownership. A scan that reports to a Slack channel nobody owns is just background noise. Assign findings to the team that owns the affected service.
  • Ignoring the runtime layer. SAST and dependency scanning are necessary but not sufficient. Most graded security failures — weak TLS configs, missing HSTS, permissive CORS — are only visible at runtime.

What "good" looks like

A mature pipeline produces these signals on every release:

  • A pass/fail security gate that runs in under 3 minutes on PRs
  • An SBOM artifact attached to every build
  • A runtime security grade (e.g., from WebSentry) recorded against the deploy
  • Auto-filed tickets for any new findings, assigned to the right team
  • A monthly trend report showing finding counts dropping over time

If you want a quick read on where your current site sits before you wire any of this up, run a free scan at websentry.dev — it'll give you an A–F grade across SSL, headers, CSP, cookies, DNS and CORS in about 30 seconds, which is usually enough to know whether your pipeline needs runtime checks added today or next quarter.

Check your own site

Run a free security scan and see if your site has the issues covered in this article. Results in under 30 seconds.