QA Engineer Skills 2026QA-2026SAST, DAST, and SCA in CI: Shift-Left Security Pipeline

SAST, DAST, and SCA in CI: Shift-Left Security Pipeline

What Is Shift-Left Security?

Shift-left security means integrating security testing early in the development lifecycle -- ideally in CI/CD pipelines -- rather than waiting for a penetration test before release. For AI applications, this means running static analysis, dependency scanning, and dynamic testing on every commit, with AI-specific rules that catch vulnerabilities traditional tools miss.


Tool Landscape

Category Tool What It Does Integration Point Cost
SAST Semgrep Pattern-based code analysis Pre-commit hook, CI Free (open source rules)
SAST CodeQL Deep semantic code analysis GitHub Actions (native) Free for public repos
DAST ZAP (OWASP) Active web vulnerability scanning CI (against staging) Free/open source
DAST Burp Suite Comprehensive web security testing Manual + CI (Enterprise) Commercial
SCA Snyk Dependency vulnerability scanning CI, IDE, registry Freemium
SCA Dependabot Automated dependency updates GitHub native Free
Secrets GitLeaks Detect secrets in git history Pre-commit hook Free/open source
Container Trivy Container image vulnerability scanning CI Free/open source

Complete CI Security Pipeline

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

jobs:
  sast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Semgrep SAST scan
        uses: semgrep/semgrep-action@v1
        with:
          config: >-
            p/owasp-top-ten
            p/python
            p/typescript
            p/secrets
            p/ai-security
          generateSarif: true
      - name: Upload SARIF
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: semgrep.sarif

  sca:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Snyk dependency scan
        uses: snyk/actions/python@master
        with:
          args: --severity-threshold=high
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

  secrets:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Detect secrets
        uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  dast:
    runs-on: ubuntu-latest
    needs: [sast, sca]  # only run DAST if static checks pass
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to ephemeral environment
        run: ./scripts/deploy-ephemeral.sh
      - name: OWASP ZAP full scan
        uses: zaproxy/action-full-scan@v0.10.0
        with:
          target: ${{ env.EPHEMERAL_URL }}
          rules_file_name: zap-rules.tsv
          cmd_options: '-a -j'
      - name: Upload ZAP report
        uses: actions/upload-artifact@v4
        with:
          name: zap-report
          path: report_html.html

  container-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build Docker image
        run: docker build -t app:${{ github.sha }} .
      - name: Trivy container scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: app:${{ github.sha }}
          format: sarif
          output: trivy-results.sarif
          severity: 'CRITICAL,HIGH'
      - name: Upload Trivy SARIF
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: trivy-results.sarif

AI-Specific Semgrep Rules

Standard SAST rules do not catch AI-specific vulnerabilities. Write custom Semgrep rules:

# .semgrep/ai-security-rules.yaml
rules:
  - id: llm-output-used-in-sql
    pattern: |
      $QUERY = f"... {$LLM_RESPONSE} ..."
      $DB.execute($QUERY)
    message: "LLM output used directly in SQL query. Use parameterized queries."
    severity: ERROR
    languages: [python]
    metadata:
      category: security
      owasp: "A03:Injection"
      ai_specific: true

  - id: llm-output-used-in-shell
    patterns:
      - pattern: os.system(f"... {$LLM_RESPONSE} ...")
      - pattern: subprocess.run(f"... {$LLM_RESPONSE} ...", shell=True)
    message: "LLM output used in shell command. Sanitize or use allowlist."
    severity: ERROR
    languages: [python]
    metadata:
      category: security
      owasp: "A03:Injection"

  - id: api-key-in-prompt
    pattern: |
      $PROMPT = f"... $API_KEY ..."
    message: "API key may be included in LLM prompt. Remove sensitive data."
    severity: WARNING
    languages: [python]

  - id: no-output-sanitization
    pattern: |
      $RESPONSE = $LLM.generate(...)
      return $RESPONSE
    message: "LLM output returned without sanitization. Add output validation."
    severity: WARNING
    languages: [python]

  - id: no-max-tokens-set
    pattern: |
      $CLIENT.chat.completions.create(
        ...,
        ~max_tokens,
        ...
      )
    message: "LLM call without max_tokens. Set a limit to prevent cost/DoS issues."
    severity: WARNING
    languages: [python]

  - id: hardcoded-llm-api-key
    patterns:
      - pattern: '"sk-..."'
      - pattern: "'sk-...'"
      - pattern: |
          $KEY = "sk-$REST"
    message: "Hardcoded OpenAI API key detected. Use environment variables."
    severity: ERROR
    languages: [python, javascript, typescript]

Understanding Each Security Layer

SAST (Static Application Security Testing)

Analyzes source code without executing it. Catches code-level vulnerabilities early.

What it catches in AI apps:

  • LLM output used in SQL/shell without sanitization
  • API keys hardcoded in prompt templates
  • Missing output validation on LLM responses
  • Insecure deserialization of model outputs

Limitations: Cannot detect runtime behavior, configuration issues, or logical flaws.

DAST (Dynamic Application Security Testing)

Tests the running application by sending requests and analyzing responses.

What it catches in AI apps:

  • XSS via LLM-generated HTML content
  • SSRF through AI URL fetching features
  • Authentication bypass on AI endpoints
  • Information disclosure in error messages

Limitations: Requires a running environment, slower than SAST, cannot see code-level issues.

SCA (Software Composition Analysis)

Scans dependencies for known vulnerabilities (CVEs).

What it catches in AI apps:

  • CVEs in PyTorch, TensorFlow, LangChain, Hugging Face libraries
  • Vulnerable transitive dependencies in the ML pipeline
  • License compliance issues with model dependencies

ML-specific SCA concerns:

  • ML libraries are updated less frequently than web frameworks
  • Model files from external sources may contain malicious payloads
  • The LangChain ecosystem has had several critical CVEs

Pipeline Architecture

  Developer Commits Code
           |
           v
  +------------------+
  | Pre-commit Hooks |   <-- GitLeaks (secrets), Semgrep (quick scan)
  | (< 30 seconds)   |       Runs before code leaves developer machine
  +--------+---------+
           |
           v
  +------------------+
  | SAST + SCA       |   <-- Semgrep (full), Snyk (deps), CodeQL (deep)
  | (2-5 minutes)    |       Runs on every PR
  +--------+---------+
           |
           v
  +------------------+
  | DAST             |   <-- OWASP ZAP against ephemeral environment
  | (10-30 minutes)  |       Runs after SAST passes (why scan if code is broken?)
  +--------+---------+
           |
           v
  +------------------+
  | Container Scan   |   <-- Trivy (image vulnerabilities)
  | (2-5 minutes)    |       Runs on every built image
  +--------+---------+
           |
           v
  +------------------+
  | AI Security      |   <-- Prompt injection, jailbreak, data leakage tests
  | Tests            |       Runs when AI code or prompts change
  | (5-15 minutes)   |
  +------------------+

Handling Security Findings

Severity-Based Response

Severity SLA Action
Critical (e.g., SQL injection, API key leak) Block merge, fix immediately PR cannot merge until fixed
High (e.g., XSS, vulnerable dependency) Fix within 3 days PR can merge with security team approval
Medium (e.g., missing headers, info disclosure) Fix within 2 weeks PR can merge, ticket created
Low (e.g., best practice violation) Fix in next sprint No merge block, warning only

False Positive Management

SAST tools produce false positives. Manage them systematically:

# .semgrep-ignore.yaml
rules:
  - id: no-output-sanitization
    paths:
      # Internal tools that only display to admins
      - src/admin/debug_panel.py
    comment: "Admin debug panel, no user-facing output"
    approved_by: "security-team"
    approved_date: "2026-01-15"

Track your false positive rate. If it exceeds 20%, the team will stop trusting the tool. Tune rules to reduce noise while maintaining detection capability.

A security pipeline is not set-and-forget. Review findings weekly, update rules monthly, and re-evaluate tool effectiveness quarterly.