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.
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.
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.
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.
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.
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-unfixedand 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
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
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
Image scanning: OS packages and language libraries inside container images (Trivy, Grype, ECR scanning). Smaller base images (distroless) mean fewer findings.
- 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
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
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
What does each scanner type find?
Why gate only on new, fixable, high-severity findings?
Practice
Add Trivy (filesystem and image) to a pipeline with a sensible gate.
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.