Command Palette

Search for a command to run...

Hectal
PHASE 7Advanced ~15 min· topic 5 of 5

Topic 7.5

Security Scanning in Pipelines: SAST, Dependencies, Images & IaC

In one line

Pipelines are the cheapest place to catch security problems. Static analysis (SAST, like CodeQL or Semgrep) finds risky code patterns, dependency scanning (Dependabot, OWASP Dependency-Check, Trivy, Snyk) finds known vulnerabilities in libraries, image scanning finds vulnerable OS packages in containers, and IaC scanning (Checkov, Trivy config) finds risky Terraform and Kubernetes settings. Fail builds on new high-severity, fixable findings, track the rest, and keep noise low.

0/5 · 0%

Think of it like this

A food safety inspection at several points: checking recipes for dangerous instructions (SAST), checking ingredients for recalls (dependency scanning), checking the packaging (image scanning), and checking the kitchen's layout and equipment (IaC scanning).

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

SAST
Static Application Security Testing: finding security flaws by analysing source code.
SCA
Software Composition Analysis: finding known vulnerabilities in third-party dependencies.
CVE
A public identifier for a known vulnerability.
SARIF
A standard format for static analysis results, shown in GitHub's code scanning.
IaC scanning
Checking infrastructure-as-code files for insecure settings.
Fixable vulnerability
A vulnerability with an available patched version.

Step by step

01Tiffin's scanning layers

Each scanner runs at the stage where it's most useful, and results go to GitHub's Security tab as SARIF, so findings appear on pull requests.

Tiffin's scanning layersdiagram
Rendering diagram…

02The scanning jobs

CodeQL analyses Java on pull requests, and Trivy scans dependencies, IaC, and the built image, failing only on critical or high findings that have a fix.

.github/workflows/security.yml (excerpt)whole fileyaml
jobs:
  codeql:
    runs-on: ubuntu-latest
    permissions: { security-events: write, contents: read }
    steps:
      - uses: actions/checkout@v4
      - uses: github/codeql-action/init@v3
        with: { languages: java-kotlin, build-mode: autobuild }
      - uses: github/codeql-action/analyze@v3

  trivy:
    runs-on: ubuntu-latest
    permissions: { security-events: write, contents: read }
    steps:
      - uses: actions/checkout@v4
      - uses: aquasecurity/trivy-action@0.33.1
        with:
          scan-type: fs                     # dependencies + IaC + secrets in the repo
          scanners: vuln,misconfig,secret
          severity: CRITICAL,HIGH
          ignore-unfixed: true
          exit-code: "1"
          format: sarif
          output: trivy.sarif
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with: { sarif_file: trivy.sarif }

03A finding and its fix

The image scan finds a critical vulnerability in a transitive JSON library. Dependabot already has a PR bumping it, so the fix is to merge that PR after its tests pass.

terminal
$ trivy image --severity CRITICAL,HIGH --ignore-unfixed ghcr.io/tiffin-team/web:sha-8f3a1c2 | tail -6
── expected output ──
Java (jar)
Total: 1 (HIGH: 0, CRITICAL: 1)
┌──────────────────────────────────────┬────────────────┬──────────┬───────────────────┬───────────────┐
│ Library │ Vulnerability │ Severity │ Installed Version │ Fixed Version │
├──────────────────────────────────────┼────────────────┼──────────┼───────────────────┼───────────────┤
│ com.example:fast-json (app.jar) │ CVE-2026-31337 │ CRITICAL │ 2.4.1 │ 2.4.3 │
The vulnerable version and package name here are illustrative. The workflow is real: scan, find the fixed version, update, rescan.

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Scanners nobody acts on

Every scanner runs with exit-code: 0 and reports to a dashboard nobody owns.

terminal
$ gh api repos/tiffin-team/web/code-scanning/alerts --paginate --jq '[.[] | select(.state=="open")] | length'
── what you'll see ──
1184
# critical alerts open for over 200 days, including ones with simple version-bump fixes

Myth vs fact

Myth

A clean scan means the app is secure.

Fact

Scanners find known patterns and known vulnerabilities. Design flaws, business logic bugs, and new attack techniques need threat modelling, reviews, and testing too (DevSecOps course).

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Prefer ignore-unfixed and reachability-aware tools for gating, so builds fail only on vulnerabilities you can actually fix (and ideally that your code reaches). Unfixable findings go to tracking, not the gate.

Remember this

  1. 1

    SAST: analyses source code for vulnerable patterns: SQL built from strings, unsafe deserialisation, path traversal, hard-coded credentials. CodeQL (GitHub code scanning), Semgrep, SonarQube security rules.

  2. 2

    Dependency scanning (SCA): compares your dependencies against vulnerability databases (CVE/GHSA/OSV). Dependabot alerts and update PRs, Trivy or OWASP Dependency-Check in CI. Watch transitive dependencies too.

  3. 3

    Image scanning: OS packages and language libraries inside container images (Trivy, Grype, ECR scanning). Smaller base images (distroless) mean fewer findings.

  4. 4

    IaC scanning: Terraform, Kubernetes manifests, Helm charts, and Dockerfiles for risky settings: public buckets, privileged pods, missing encryption (Checkov, Trivy config, kube-linter).

  5. 5

    Policy: fail on new critical/high findings that have a fix, report the rest to a dashboard (GitHub code scanning with SARIF uploads), and allow documented, expiring exceptions.

  6. 6

    Fixing is the goal: automated update PRs (Dependabot, Renovate) with tests make most fixes routine. Scanning without fixing just creates noise.

Explain it without notes

01

What does each scanner type find?

02

Why gate only on new, fixable, high-severity findings?

Practice

01

Add Trivy (filesystem and image) to a pipeline with a sensible gate.

02

Enable Dependabot security updates and merge one update through CI.

Trade-offs

  • ↔

    More scanners catch more issues but add pipeline time and noise. Strict gates prevent new vulnerabilities but can block urgent releases, so provide a documented exception path.

Done when you can

  • My pipeline runs SAST, dependency, image, and IaC scans.

  • Gates fail on new, fixable, serious findings.

  • Findings have owners and automated update PRs.