Skip to main content

All weeks · Worksheet · Overview · Pipeline guide

Week 15 · Lecture slides

Week 15

Contents21 sections

DevSecOps: Putting It Together

Software Security · Nutthakorn Chalaemwongwan


Today

  • Security in the CI/CD pipeline
  • Logging, monitoring & alerting
  • Failing safely
  • Vulnerability mgmt & disclosure
  • 🎮 Game: Break the Build (Red vs Blue)

The whole course in one pipeline

  • SAST (Wk2) · SCA + image scan (Wk12–13) · IaC (infrastructure-as-code) config scan (Wk13) · secret scanning (Wk2)
  • Automated gates instead of one-off scans
  • Secure by Design as the default

One app, three layers. You are here: W15. W13, where it runs: a secret baked into an image layer and an IAM policy with Action * on Resource *; fix with a hardened image and least privilege. W14, what it says: the app gets a chatbot; typed text overrides its rules (prompt injection) and its reply goes into the page unescaped (XSS); fix with guardrails, secret redaction and output escaping. W15, how it ships: Semgrep, Trivy and Gitleaks check every push, a red gate fails the PR, and the app denies on error.


One push, three jobs

The security-ci.yml pipeline at a glance. A push or PR to main starts three jobs in parallel: Semgrep (SAST), Trivy (SCA plus IaC) and Gitleaks (secrets, whole git history). Each job runs the same three phases. The report step never fails (|| true or exit-code "0"). The upload step (if: always()) sends the SARIF to the GitHub Security tab, where every finding of every severity shows. The gate step re-scans and can fail the build. Semgrep's --error and Gitleaks' --exit-code 1 fail on any finding. Trivy's two gates fail only on HIGH or CRITICAL, and the IaC gate is skipped if the SCA gate already failed. The report shows everything; the gate decides.


A security gate

# .github/workflows/security-ci.yml
- semgrep   # SAST
- trivy     # SCA (fs) + IaC (config) — image scan is optional, off by default
- gitleaks  # secrets + git history
# each tool runs TWICE: once to report (SARIF, always), once to gate (fails the build)
  • The token gets only what it needs: contents: read, security-events: write
  • Results (SARIF) go to the GitHub Security tab
  • A red run blocks a merge only if the jobs are required checks (branch protection)
Does this PR pass the gate? (Week 15) — open full size

Platform option — GitHub Advanced Security

  • CodeQL code scanning (SAST) on every PR
  • Secret scanning + push protection
  • Dependabot for vulnerable deps
  • SonarQube as a quality/SAST gate alongside

Same idea as the YAML gate — managed, in the repo.


Logging, monitoring, alerting

  • A09:2025 — without logs you can't detect or respond
  • Log security events (authn, authz failures, anomalies)
  • Never log the secret/token value itself (CWE-532) — log reason=bad_token, not the token
  • Alert on suspicious patterns

Detection tooling

  • NIDS (network intrusion detection) — Snort / Suricata watch network traffic
  • HIDS (host intrusion detection) — OSSEC watches one machine
  • SIEM (collects and connects alerts) — Security Onion bundles these tools
  • Network visibility: TAP (lossless) vs SPAN (cheap, can drop)

Alerts — the confusion matrix

Incident realNo incident
Alert firedTrue positive ✅False positive
No alertFalse negative 💀True negative
  • False negative = worst case (missed attack)
  • Some false positives are inevitable — tune, don't silence

When something happens (NIST SP 800-86)

Collection → Examination → Analysis → Reporting

  • Collect what disappears first (order of volatility): memory → temp files → disk → logs
  • Failed/success logins: Windows Event 4625 / 4624

Fail safely

  • A10:2025 — mishandled errors leak info / fail open
  • Fail closed: deny on error, don't bypass checks
  • Don't expose stack traces / secrets in errors

Vulnerability management & disclosure

  • Triage by severity; track to remediation (SLAs)
  • Coordinated disclosure & bug bounties
  • security.txt; a path for researchers to report

One decision, made twice

Two panels showing the same yes-or-no decision at two different times. Build time: the CI gate's HIGH/CRITICAL severity filter, not the scanner itself, decides what a build refuses — root user (DS-0002, HIGH) is caught, :latest (DS-0001, MEDIUM) slips past the filter. Run time: the /admin handler makes the identical decision on an exception — fail-open returns 200 and logs nothing (silent bypass, A09); fail-closed returns 403 and logs event=authz_failure without ever logging the token itself (CWE-532). At build time, letting MEDIUM through is a risk decision — fine if someone made it on purpose, a gap if nobody looked. At run time, the except branch that returns 200 is the actual fail-open bug: A10, CWE-636.


Try it — same request, two services

Pick a token. Both real services answer, and you see what each one logs.

Same request, two services: who fails open, and what gets logged? (Week 15) — open full size

🔴🔵 Game — Break the Build

  • Blue: set up the gate (Semgrep + Trivy + Gitleaks), fail on HIGH/CRITICAL, log security events and deny on error
  • Red: one planted defect per PR — an old dependency (Trivy SCA), a Dockerfile running as root (Trivy config), or a hard-coded token (Gitleaks)
  • Score: Blue +1 per catch · Red +1 per defect that slips through (e.g. chmod 777, FROM :latest stay green) — then propose a rule that would catch it
  • Flag: leak it from the fail-open /admin in insecure_service.py (local run = demo flag; graded flag = your hosted instance)

Break the Build — what each change turns red

The Break the Build game board, measured by running security-ci.yml's own gate commands on the real lab files. Columns: Semgrep gate, Trivy SCA gate, Trivy IaC gate, Gitleaks gate. Blue's baseline is red before Red does anything: unpinned @v4/@v3 action tags and host="0.0.0.0" trip Semgrep, and the docs' own curl examples with the toy alice-token header trip Gitleaks' curl-auth-header (a false positive). Red's attacks, one per PR on Blue's green baseline: urllib3==1.24.1 trips only Trivy SCA (7 HIGH, e.g. CVE-2019-11324). A Dockerfile running as root trips Trivy IaC (DS-0002 HIGH) and also Semgrep (missing-user or last-user-is-root). A ghp_ GitHub token trips Gitleaks (github-pat) and also Trivy SCA, whose secret scanner rates it CRITICAL. Decoys stay green: chmod 777 has no rule, and FROM python:latest is DS-0001 MEDIUM, which the gate filters out.


Try it — which job goes red?

Click Blue's clean baseline, then Red: old urllib3, and find the gate that fails.

Which job goes red, and at which step? The Actions run, step by step (Week 15) — open full size

Task 1b at a glance

Task 1b at a glance. From the lab folder, docker compose up starts two containers from the same python:3.12-slim image, both mounting the lab folder: insecure_service.py on localhost:8090 and secure_service.py on localhost:8091. Send both the same GET /admin with no token. :8090 answers 200 with the panel and the FLAG, because the USERS dictionary lookup raises KeyError and the except branch grants access; its log shows only a 200 access line. :8091 answers 403 forbidden and logs a WARNING on the security logger (event=authz_failure outcome=deny reason=unauthenticated). Then prove the fix keeps admins in: alice-token still unlocks :8091, and the auto-grader checks both. Submit the flag, both responses and the failing-open except line; a local run returns the public demo flag, the graded one comes from your hosted instance.


Deliverable

📋 Worksheet 15 — labs/week15-devsecops-pipeline/worksheet.md (Part 3) · start: push security-ci.yml to your own public repo → GitHub Actions; for the flag, docker compose up → :8090 (insecure) / :8091 (secure)

  • A passing PR that adds the pipeline
  • A screenshot of the failing gate step for your planted defect, and which job caught it
  • The FLAG{...} from the fail-open /admin, written in the worksheet (graded flag: your hosted instance)
  • + Audit the AI / EiPE / Prompt Problem (see worksheet)

Key takeaways

  • Automate security gates — humans forget, pipelines don't
  • You can't defend what you don't log
  • Fail closed; disclose responsibly

Questions?

Next week: Capstone studio & CTF warm-up

All weeks in Software Security 2 (KOSEN)