DevSecOps··5 min read

Securing CI/CD Pipelines with Deterministic Security Baselines

How engineering teams introduce SAST scanners into legacy codebases without breaking continuous integration, using deterministic baselines and diff-aware scans.

S
Sagar VD
Founder & Security Researcher
Twitter / XLinkedIn

Every engineering team that attempts to introduce static analysis into an existing, mature repository encounters the exact same crisis on Day 1:

The scanner finishes in two seconds and flags 340 issues across the legacy codebase.

If you configure your CI pipeline to fail the build on high-severity findings (exit 1), pull requests grind to a halt. Developers working on a one-line CSS fix are suddenly blocked by a SQL injection flaw written four years ago by an engineer who left the company.

If you don’t fail the build, the scanner becomes a decorative dashboard that nobody checks.

Here is how modern security teams solve this dilemma using deterministic security baselines and diff-aware PR scanning.


1. The Strategy: Stop the Bleeding First

When fixing an insecure application, the cardinal rule of remediation is: Do not let new vulnerabilities enter while you remediate the old ones.

A security baseline snapshots the current state of known findings in the repository:

+------------------------------------+
|  Existing Codebase (340 findings)  | ---> Snapshot into .saasecure/baseline.json
+------------------------------------+
                   │
                   ▼
+------------------------------------+
|  Developer submits Pull Request    |
+------------------------------------+
                   │
                   ├──► Is finding in baseline? ──► YES ──► IGNORE (Known debt)
                   │
                   └──► Is finding NEW? ──────────► YES ──► FAIL BUILD (Exit 1)

By decoupling legacy technical debt from active pull request gating, developers are held accountable only for code they write today.


2. Generating Deterministic Baselines

A baseline file must be deterministic and cross-platform. If a developer generates the baseline on a Windows machine with backslashes (src\routes\user.ts), it must match when evaluated by a Linux CI runner with forward slashes (src/routes/user.ts).

In SaaSecure CLI, snapshotting is a single command:

# In your project root:
.\saasecure-cli.exe . --update-baseline

This creates .saasecure/baseline.json, which tracks normalized relative file paths, rule IDs, and line hashes:

{
  "version": 1,
  "generated_at": "2026-02-22T10:30:00Z",
  "findings": [
    {
      "rule_id": "js-sqli-concat",
      "file": "src/db/legacy_queries.js",
      "line_hash": "a4f89d31...",
      "severity": "high"
    }
  ]
}

Commit this file to git alongside your application code:

git add .saasecure/baseline.json
git commit -m "chore(security): establish initial SAST baseline"

3. Gating Pull Requests in GitHub Actions

Once the baseline is committed, update your CI workflow to apply the baseline and fail only if new vulnerabilities are introduced:

# .github/workflows/security.yml
name: Security Analysis
on:
  pull_request:
    branches: [main]

jobs:
  sast:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0 # Retains git history for diff scans

      - name: Download SaaSecure CLI
        run: Invoke-WebRequest -Uri "https://files.saasecure.dev/win/saasecure-cli.exe" -OutFile "saasecure-cli.exe"

      - name: Run Gated SAST Scan
        env:
          SAASECURE_CI_TOKEN: ${{ secrets.SAASECURE_CI_TOKEN }}
        run: |
          .\saasecure-cli.exe . --baseline --fail-on high --format sarif -o results.sarif

      - name: Upload SARIF to GitHub Security Tab
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: results.sarif

Deterministic Exit Codes

  • Exit 0: Scan passed cleanly or existing findings matched the baseline.
  • Exit 1: New vulnerabilities exceeding your --fail-on threshold were introduced in this PR.
  • Exit 2: Invalid CLI arguments.
  • Exit 3: License or token authentication error.

4. Diff-Aware Scanning: Sub-Second PR Feedback

In repositories with tens of thousands of files, scanning the entire project on every commit is redundant if only two files were modified.

The --since flag leverages git merge-base calculations to inspect only files changed relative to your target branch:

# Analyzes only files modified compared to origin/main
.\saasecure-cli.exe . --since origin/main --fail-on high

This reduces scan times to sub-500 milliseconds, enabling instantaneous feedback on developer pull requests without slowing down shipping velocity.


Summary

Introducing security into a team’s workflow shouldn’t feel like slamming on the brakes. By establishing deterministic baselines and leveraging diff-aware scanning, security teams achieve continuous compliance and eliminate vulnerability debt methodically over time.

Tags:#ci-cd#baselines#git#devsecops#automation
100% Local SAST

Find vulnerabilities in your code before committing.

SaaSecure scans JavaScript, TypeScript, Python, Java, PHP, Go, and Dart locally in seconds. Zero cloud uploads, offline Rust engine, and perpetual licensing.