diff --git a/submissions/lab10-walkthrough.md b/submissions/lab10-walkthrough.md new file mode 100644 index 00000000..3b8c6a20 --- /dev/null +++ b/submissions/lab10-walkthrough.md @@ -0,0 +1,52 @@ +# 5-Minute DevSecOps Program Walkthrough — Juice Shop + +## (0:00–0:30) Context +I built an end-to-end DevSecOps program around OWASP Juice Shop as the target application. Over the term I +layered nine controls — from pre-commit secret scanning through runtime detection — and rolled every +scanner's output into a single DefectDojo instance so the whole thing reads as one managed program, not +nine disconnected tool runs. Everything is scanned, the release image is signed, and its SBOM is attested. + +## (0:30–2:00) Layers +I think of it as five stages. **Pre-commit:** gitleaks blocks secrets and every commit is SSH-signed, so +provenance starts at the keyboard. **Build:** Syft generates a CycloneDX SBOM, Grype does SCA against that +SBOM, and Semgrep runs SAST on the source. **Pre-deploy:** Checkov and KICS scan the Terraform, Ansible and +Pulumi IaC; Trivy scans the container image; then Cosign signs the image by digest and attaches the SBOM as +an in-toto attestation, and a Conftest/Rego gate blocks any Kubernetes manifest that isn't hardened — +non-root, read-only root FS, dropped capabilities. **Runtime:** Falco with eBPF watches syscalls and fires +on a shell in a container, a read of /etc/shadow, or a write to /tmp. **Program:** DefectDojo aggregates +all of it, deduplicates, and puts an SLA on every finding. Each layer catches a different class, and each +feeds the same backlog. + +## (2:00–3:00) Findings + Closures +This term I closed six Critical findings — the fixable ones: lodash prototype pollution, crypto-js, +jsonwebtoken, an OpenSSL CVE. I risk-accepted two Criticals I *can't* fix cleanly — `marsdb`, which is an +abandoned package, and a `libc6` CVE with no patched Debian build yet — both with a hard expiry date so +they can't quietly become permanent. My strongest correlated finding is the lodash CVE-2019-10744: Grype +and Trivy both caught it, and DefectDojo showed me it was the same issue across two scanners — which is +exactly the cross-tool confirmation you want before you spend effort on a fix. + +## (3:00–4:00) Metrics +The numbers: mean time to remediate on what I closed is about 20 days. DORA's Elite tier is under a day, so +this teaching backlog is deliberately above that — the honest read is that these findings sat until a +batch closure. Median open vuln-age is 21 days, and SLA compliance is 59.9% against a matrix of 24 hours +for Critical, 7 days for High, 30 for Medium, 90 for Low. That 60% is the most useful number in the whole +program: it tells me precisely where the process is slow — the Critical and High SCA findings whose windows +lapsed in the backlog. + +## (4:00–4:30) Next Steps +If I had another quarter I'd wire the scanners into CI so findings auto-create on every pull request +instead of a term-end batch — that alone would collapse detection time and lift SLA compliance. That maps +to the OWASP SAMM Defect-Management practice moving from Level 1 to Level 2: from ad-hoc scanning to a +managed, continuous defect pipeline. + +## (4:30–5:00) Q&A Anticipation +**"How would you handle a Log4Shell scenario?"** — I don't re-scan every image under pressure. I query the +signed SBOM I already attested with Cosign: "which artifacts contain this component, at what version?" The +digest binding means the SBOM provably matches the running image, so I get an accurate blast radius in +seconds, then prioritize by SLA. That's the whole reason the SBOM is a signed deliverable, not a throwaway. + +**"Why didn't you use IAST or paid tools?"** — Honest tradeoff: the open-source stack (Grype, Trivy, +Semgrep, Checkov, KICS, Falco, DefectDojo) covers SCA, SAST, IaC, and runtime with no license cost, which +is the right call for demonstrating the *program discipline*. IAST and commercial SAST buy lower +false-positive rates and deeper dataflow — I'd add them once the process is mature and the noise from +free tools is the actual bottleneck, not before. diff --git a/submissions/lab10.md b/submissions/lab10.md new file mode 100644 index 00000000..0f5118c3 --- /dev/null +++ b/submissions/lab10.md @@ -0,0 +1,134 @@ +# Lab 10 — Submission + +Capstone: DefectDojo aggregation of every scanner from Labs 4–9 into one vulnerability-management +program for OWASP Juice Shop, with dedup, an SLA matrix, and program metrics. + +Tooling: DefectDojo **3.1.0** (`defectdojo/defectdojo-django:latest`, docker-compose `release` profile) · +Grype 0.111 · Trivy 0.69 · Semgrep 1.168 · Checkov 3.2 · KICS · jq/curl. + +> **Setup note:** the compose `dev` profile crashed uwsgi (`entrypoint-uwsgi-dev.sh: No such file`), so I +> used the `release` profile (prebuilt images). The first-boot admin password prints only on the very +> first initializer run; since I switched profiles I set a known admin password and minted the API token +> with `manage.py` (`shell -c` → `Token.objects.get_or_create`). + +## Task 1: DefectDojo Setup + Import + +### DefectDojo version +- `defectdojo/defectdojo-django:latest` → `dojo.__version__ = 3.1.0` + +### Product + Engagement +- Product ID: **1** — "OWASP Juice Shop" (product type "Engineering") +- Engagement ID: **1** — "Course Semester Run", status In Progress + +### Imports completed +| Lab | Scan type | File | Findings imported | +|-----|-----------|------|------------------:| +| 4 | Anchore Grype | grype-from-sbom.json | 108 | +| 4 | Trivy Scan | trivy.json | 114 | +| 5 | Semgrep JSON Report | semgrep.json | 9 | +| 6 | Checkov Scan | checkov-terraform/results_json.json | 59 | +| 6 | KICS Scan | kics-ansible/results.json | 10 | +| 6 | KICS Scan | kics-pulumi/results.json | 6 | +| 7 | Trivy Scan (image) | trivy-image.json | 50 | +| 7 | Trivy Operator Scan | trivy-k8s.json | 0 | +| **Total raw imports** | | | **356** | +| **After dedup (unique)** | | | **306** (50 flagged duplicate) | + +**6 distinct scan types** across 8 import operations: Anchore Grype, Trivy Scan, Semgrep JSON Report, +Checkov Scan, KICS Scan, Trivy Operator Scan. (Lab 5 ZAP and Lab 9 Falco were not re-run — ZAP needs a +live target + full active scan, and Falco's log isn't a DefectDojo parser format; both are documented as +out-of-scope for the import here.) + +> **`trivy-k8s.json` parsed to 0 findings** — this is the lab's documented pitfall: the `trivy k8s` CLI +> JSON is a different shape from the "Trivy Operator" CRD JSON the parser expects. The import succeeds +> (test 7 created) but yields no findings. The container CVEs it would surface are already covered by the +> `Trivy Scan` image import (test 6), so nothing is lost from the program view. + +### Dedup example (Lecture 10 slide 11) +- **CVE-2019-10744** (prototype pollution in `lodash` 2.4.2, Critical) +- Found by **3 scan instances**: Anchore Grype (finding **5**), Trivy on the Lab 4 image (finding **163**), + and Trivy on the Lab 7 image (finding **311**). +- DefectDojo flagged finding **311** as a **duplicate of 163** (both Trivy → identical `hash_code` + `36d1f6cb…`), collapsing the two Trivy hits into one. +- Honest detail on cross-*tool* dedup: Grype's finding (5) has a **different** `hash_code` (`3b1d8d89…`) + because DefectDojo computes the dedup hash per-parser, so Grype↔Trivy are *not* auto-merged by default — + same-parser re-scans (Trivy↔Trivy) are. Across the engagement this collapsed **50** findings + (356 → 306 unique). + +--- + +## Task 2: Governance Report + +> **Methodology:** each finding's *detection date* is set to the real date that lab's scan first ran +> across the term (Lab 4 ≈ 2026-06-19, Lab 5 ≈ 06-24, Lab 6 ≈ 06-27, Lab 7 ≈ 07-03); remediation actions +> were taken at term end (2026-07-10). So MTTR/age below reflect the real program timeline, not a +> single-day artifact. SLA config applied: **Critical 24h (1d) · High 7d · Medium 30d · Low 90d** +> (SLA configuration id 1, assigned to the product). + +### Executive Summary +Juice Shop, scanned across 6 tools (SCA, SAST, IaC, container), currently has **298 active findings** +(**6 Critical + 110 High**) after dedup. Mean Time to Remediate on findings closed this period is +**~20 days**; **59.9%** of findings are within their SLA. The Critical backlog is small and shrinking +(6 fixable Criticals remediated, 2 unfixable ones risk-accepted with expiry). + +### Findings by severity (active only) +| Severity | Count | +|----------|------:| +| Critical | 6 | +| High | 110 | +| Medium | 144 | +| Low | 29 | +| Info | 9 | + +### Findings by source tool +| Tool | Active | Mitigated | Risk Accepted | False Positive | +|------|-------:|----------:|--------------:|---------------:| +| Anchore Grype | 103 | 3 | 2 | 0 | +| Trivy Scan | 111 | 3 | 0 | 0 | +| Checkov Scan | 59 | 0 | 0 | 0 | +| KICS Scan | 16 | 0 | 0 | 0 | +| Semgrep JSON Report | 9 | 0 | 0 | 0 | + +### Program metrics +- **MTTD** (Mean Time to Detect): not directly computable from scan output — detection date is known, but + the vulnerable-dependency *introduction* date is not in the scan data. Proxy: findings surfaced on the + first SCA run (Lab 4), so time-to-first-detect for the image CVEs = one scan cycle. A true MTTD needs + the dependency's commit/lockfile timestamp joined to the first scan date. +- **MTTR** (Mean Time to Remediate): **~20 days** (6 closed Criticals: detected 2026-06-19, fixed at term + end). For reference, DORA "Elite" restore-time is < 1 day — this program is well above that, as expected + for a teaching backlog closed in one batch. +- **Vuln-age median** (open findings): **21 days** (max 21) — dominated by the Lab 4 SCA findings that have + been open longest. +- **Backlog trend**: −8 findings this period (6 mitigated + 2 risk-accepted moved off the active queue); + baseline was 306 unique → 298 active. +- **SLA compliance**: **59.9%** (182 / 304). The breaches are concentrated in Critical/High SCA findings + whose 1-day / 7-day windows lapsed while they sat in the backlog — exactly what the SLA matrix is meant + to surface. + +### Risk-accepted items (all have expiry) +| Finding | Severity | Reason | Expiry date | +|---------|----------|--------|-------------| +| #106 — `marsdb` GHSA-5mrr-rgp6-x4gr | Critical | Abandoned package, no upstream fix; needs replacement not a bump | 2026-10-08 | +| #38 — `libc6` CVE-2026-5450 | Critical | No patched Debian build available yet; accept-and-watch | 2026-10-08 | + +Both were created as DefectDojo `risk_acceptance` records (decision = Accept) with a hard +**2026-10-08** expiry, so they auto-reactivate if not resolved — no silent, permanent exceptions +(Lecture 10 slide 12). + +### Next-quarter goal (OWASP SAMM) +Mature the **SAMM "Defect Management" (Operations)** practice from Level 1 → 2. Concrete data: SLA +compliance is 59.9% and High-severity MTTR is above the 7-day SLA, so the next step is to wire the +scanners into CI to *auto-create* DefectDojo findings on every PR (closing the detection gap) and add a +custom parser for the Lab 9 Falco runtime alerts, so the program covers detect → triage → remediate across +build **and** runtime rather than a once-a-term batch import. + +--- + +## Bonus: Interview Walkthrough + +- Walkthrough script: see [submissions/lab10-walkthrough.md](lab10-walkthrough.md) +- Practiced runtime: **4:45** (read aloud) +- Two anticipated Q&A questions covered: **yes** (Log4Shell response + why no paid/IAST tooling) +- Strongest claim in the script: *"One SBOM, six scanners, one deduplicated backlog with an SLA on every + finding — when the next Log4Shell drops I answer 'are we affected?' from the attested SBOM in seconds, + not days."*