Skip to main content

All weeks · Worksheet · Overview

Week 2 · Lecture slides

Week 2

Contents18 sections

Secure SDLC, Tooling & Fuzzing

Software Security · Nutthakorn Chalaemwongwan


Today

  • Security across the SDLC ("shift left")
  • SAST · DAST · SCA · secret scanning · fuzzing
  • Triaging findings by CWE
  • 🏁 Game: Bug Triage Race + a Fuzzing Race

Recap — Week 1

  • Threat modeling finds design flaws (before code)
  • This week: find implementation flaws — automatically, at scale
  • Same goal: catch it early, cheap to fix

Security across the SDLC

Requirements → Design → Code → Build → Test → Deploy → Operate

  • Each phase has security activities
  • Shift left: find issues early — cheaper to fix
  • DevSecOps = security automated into the pipeline

The tooling families

A left-to-right software development pipeline with five stages: write code, commit, build, deploy, run. Four scanners are placed at the stage each one actually operates on, and under each is written what it cannot see, grounded in the actual CWEs found in this week's vulnerable-repo/app.py and harness.c.


SAST vs DAST in one line

  • SAST — reads the code, finds bug patterns (no running). Many false positives.
  • DAST — attacks the live app from outside. Fewer FPs, misses source-level issues.

Use both — they find different things.


Worked example: what each tool catches

@app.route("/user")
def user():
    name = request.args.get("name")
    q = "SELECT * FROM users WHERE name='%s'" % name   # SAST → CWE-89
    return db.execute(q).fetchall()
AWS_SECRET_ACCESS_KEY = "hK8pQ2mN5vX9wZ3rT6yU1sA4bC7dE0fG2hJ5kL8"  # Gitleaks → CWE-798
  • Semgrep (SAST): flags the string-built SQL query (CWE-89)
  • Gitleaks (secret scan): flags the hardcoded key — must be a real-looking secret; the AWS-docs example key (wJalr...EXAMPLEKEY) is a known public string and won't fire any rule
  • DAST/fuzzer: would catch a crash/SQLi by hitting /user, not reading it
  • Same file also plants command injection, a weak md5 hash, and debug=True — Task 1 grades all five

Fuzzing — how real CVEs are found

  • Feed random/mutated inputs, watch for crashes
  • Coverage-guided (libFuzzer/AFL++) explores new code paths
  • Pair with sanitizers (ASan) to pinpoint the bug
# run inside labs/toolbox — Apple clang has no libFuzzer runtime
clang -g -fsanitize=address,fuzzer harness.c -o fuzz
mkdir -p corpus && printf 'FUZ' > corpus/seed && ./fuzz corpus

How fuzzing finds it

![A coverage-guided fuzzer reaches a bug a static analyzer misses: the harness has four nested byte checks (F, U, Z, Z) and the fourth reads data[3] with no size>3 guard, so the input 'FUZ' reads one byte out of bounds. SAST reads the code and stays silent; the fuzzer mutates inputs and is rewarded for each new branch reached, climbing random -> F -> FU -> FUZ until the unguarded read crashes under AddressSanitizer, which writes a reproducer file. SAST and fuzzing are complements, not substitutes.](img/fuzzing-finds-it.svg)


Try it — what actually crashes this harness

Type bytes, or pick a preset. Each cell is one if in the real source.

What actually crashes harness.c, computed live (Week 2) — open full size

Triage: not every finding is a bug

  • True positive vs false positive
  • Map each to a CWE + severity
  • Prioritize by exploitability × impact
  • Noise kills trust in tools — triage well

Try it — which bug is this, really?

Seven raw findings from a real scan. Map each back to the one bug underneath.

Which bug is this really? Raw findings, deduplicated (Week 2) — open full size

Tools you'll meet

  • Trivy — the SCA scanner you'll actually run this lab (dependency scan today; image + IaC scanning return in W12/13)
  • SonarQube, GitHub Advanced Security (GHAS) — quality-gate/SAST-in-the-repo tools you'll see in industry/internships, not used in this lab
  • Address technical debt early — cheaper than re-work later

🏁 Game — Bug Triage Race

  • Run Semgrep + Gitleaks on the flawed repo
  • Score = true positives − misclassified · live scoreboard
docker run --rm -v "$PWD/vulnerable-repo:/src" semgrep/semgrep \
  semgrep --config p/default --config p/owasp-top-ten /src
docker run --rm -v "$PWD/vulnerable-repo:/repo" zricethezav/gitleaks:latest \
  detect -s /repo -v --no-git

🐝 Mini-game — Fuzzing Race

  • First team to make the provided target crash wins
  • One crash → one root-cause note
  • Full fuzz→exploit lab returns in Week 11

Lab 2 — deliverable

📋 Worksheet 2 — labs/week02-sdlc-tooling/worksheet.md (Part 3) · kickoff: bash scan.sh (Semgrep ×2 rulesets + Gitleaks --no-git on ./vulnerable-repo)

  • A findings triage table: tool, CWE, severity, TP/FP, fix idea (3 TP + 1 FP, justified)
  • 1 fuzzing crash with a one-line root cause
  • Trivy SCA scan of the NoteVault project target
  • A security CI gate built from Week 15's security-ci.yml
  • One SAST blind spot you found by hand
  • Defend/fix: remediate all 5 planted flaws, before/after diff — this alone is 25 of 100 rubric points
  • + Audit the AI and EiPE / Prompt Problem (see worksheet)

Key takeaways

  • No single tool finds everything — layer SAST/DAST/SCA/fuzzing
  • Triage by CWE + severity; kill the noise
  • Fuzzing is the highest-yield bug finder — automate it

Questions?

Next week: Cryptography used correctly

All weeks in Software Security