Worksheet 15 — DevSecOps: Putting It Together (4 hrs)
← all weeks · readme · pipeline · slides
Worksheet 15 — DevSecOps: Putting It Together (4 hrs)
Course: Software Security (KOSEN69) · Week 15 Aligned to: OWASP 2025 A09 Security Logging & Alerting Failures · A10 Mishandling of Exceptional Conditions (scanners also cover A02/A03) · CWE-636 (fail open), CWE-532 (logging sensitive data), CWE-209, CWE-489, CWE-798 Signature game: 🔴🔵 Break the Build (Red vs Blue) — Blue scores per catch, Red scores per bypass.
⚠️ Ethics note: The pipeline and
sample-service.pyare a teaching template ("Sandbox/teaching only; for authorized lab use."). Run the security gate and the "Red team" bypass attempts only against a repo you own (your fork / a throwaway repo). Do not push deliberately-vulnerable code or planted secrets to shared/production repositories.
Part 1 — Student Information
| Name | Student ID | Date | Group |
|---|---|---|---|
Part 2 — Lecture Questions
Answer in your own words (2–4 sentences each).
README-pipeline.mdsays each tool runs twice (report step, then gate step). Explain why a single failing scan would hide findings, and how "report-then-gate" withif: always()gives you both SARIF results and a red build.- What is the difference between fail-closed and fail-open? In
sample-service.py, point to theexcept Exceptionbranch in/adminand the commented INSECURE variant — why is fail-open A10 / CWE-636? - The
permissions:block insecurity-ci.ymliscontents: read,security-events: write. Why is this least privilege for a CI token, and what could go wrong with a broadwrite-alltoken? - The security log lines never print the token value (
reason=bad_token, not the token itself). Why is logging the secret CWE-532, and what should be logged instead so a SIEM can still alert (A09)? - Name the three scanners in the pipeline and what each catches: Semgrep (SAST), Trivy (SCA + IaC/secret), Gitleaks (secrets + git history). Which OWASP categories does each map to per the README table?
Part 3 — Hands-on Lab (180 min in class)
The task budgets below add up to 205 min. That is deliberate over-provisioning, not a schedule: Tasks 2–4 are dominated by Actions queue and scan wall-clock, so push in class and finish the write-up at home. Your instructor will say which task runs as homework.
Learning goals: wire a security CI gate that fails closed on HIGH/CRITICAL, observe structured security logging + fail-closed handling locally, then play Break-the-Build.
Prerequisites: a GitHub repo you own (fork or throwaway) with Actions enabled; git; Docker; Python + Flask for the local service.
Environment setup (real commands)
# --- A) Wire the gate into a repo you own (README-pipeline.md §1) ---
mkdir -p .github/workflows
cp labs/week15-devsecops-pipeline/security-ci.yml .github/workflows/security-ci.yml
git add .github/workflows/security-ci.yml
git commit -m "ci: add security gate (Semgrep + Trivy + Gitleaks)"
git push # runs on push/PR to main
# --- B) Run the sample service locally (logging + fail-closed) ---
pip install flask
python labs/week15-devsecops-pipeline/sample-service.py
# In another shell:
curl -s -X POST localhost:5001/login -H 'Content-Type: application/json' -d '{"token":"nope"}' # 401 authn_failure
curl -s localhost:5001/admin -H 'Authorization: bob-token' # 403 authz_failure
curl -s localhost:5001/admin -H 'Authorization: alice-token' # 200 (admin)
What to submit per task: the command / PR link, the relevant output or log lines / Actions step result, a screenshot, and a 2–3 sentence note on the control involved (cite the A0x / CWE).
Tasks
- Task 0 — Onboarding (15 min). Run the sample service; trigger the three curls above. Deliverable: screenshot of the structured
event=...security log lines for authn_failure, authz_failure, and authz_success.
- Task 1 — Logging & fail-closed (35 min, A09/A10). Goal: prove fail-closed behavior. Steps: read
/admininsample-service.py; explain why the broadexcept Exceptionreturns 403, not the secret, and whytype(exc).__name__(not the message) is logged (CWE-209). Identify the line that would make it fail open (the commented INSECURE variant). Deliverable: the log lines + a 2–3 sentence explanation of fail-closed vs fail-open.
- Task 1b — Break the Build, live (25 min, A10 / CWE-636). Goal: exploit a real fail-open, then prove the fix. Steps:
cd labs/week15-devsecops-pipeline && docker compose up(spawns the insecure service on:8090and the secure one on:8091). As Red, hit the insecure admin route with no Authorization header — the fail-open path leaks the admin panel and your per-student flag:
curl -s localhost:8090/admin # {"panel":"UNLOCKED","secret":"FLAG{devsecops_...}"} <- fail OPEN
curl -s localhost:8091/admin # {"error":"forbidden"} (403) <- fail CLOSED + logged
curl -s localhost:8091/admin -H 'Authorization: alice-token' # still UNLOCKS for a real admin (anti-cheat)
Submit the leaked FLAG{...}. Deliverable: the flag, the two contrasting /admin responses (:8090 leak vs :8091 deny), and the exact line in insecure_service.py that fails open. (The instructor auto-grader re-runs these exploits against your hardened box — you pass only if every bypass is blocked and a valid admin token still works.)
- Task 2 — Stand up the gate (35 min). Goal: get the workflow running. Steps: push
security-ci.yml, open the Actions run, confirm the three jobs (semgrep,trivy,gitleaks) execute and SARIF appears in the Security tab. Deliverable: screenshot of the Actions run + the Code scanning alerts page.
- Task 3 — Blue team: pass the gate (30 min). Goal: a green build. Steps: ensure the protected repo has no HIGH/CRITICAL findings and no secrets; fix or justify-and-document any (no blanket-ignore, per README §4). Deliverable: link to the passing run.
- Task 4 — Red team: Break the Build (40 min). Goal: make the gate say no. Steps: on a branch/PR, inject one planted defect (per README §5): an outdated vulnerable dependency (e.g. an old
urllib3), achmod 777in a Dockerfile, or a hard-coded token. Open the PR and watch the matching gate step fail. Deliverable: screenshot of the failing gate step + which job caught it (Trivy SCA / Trivy config / Gitleaks) and whichexit-code: "1"/--errorstep enforced it.
- Task 5 — Score Break-the-Build (25 min). Goal: tally Red vs Blue. Steps: one Blue point per finding the gate caught, one Red point per finding that slipped through; for any bypass, propose the rule that would have caught it. Deliverable: scoreboard + one proposed gate improvement.
Part 4 — Reflection
- Mapping. For three controls you exercised, give: control → A09/A10 (or A02/A03 for a scanner) → CWE → one-line rationale.
- Real incident. Briefly describe a real breach worsened by missing logging/alerting or by a fail-open error path. Which control here would have changed the outcome?
- Best mitigation. Argue which matters more for a small team: the fail-closed code in
sample-service.py, or the CI gate insecurity-ci.yml— and why both together beat either alone.
Grading rubric (100)
| Component | Points | What earns full marks |
|---|---|---|
| Part 2 — Lecture questions | 20 | All 5 answered with correct A09/A10/CWE reasoning |
| Part 3 — Tasks + evidence | 40 | Tasks 0–5 complete; PR/run links, log lines, screenshots present |
| Defense (gate + fail-closed) | 25 | Gate shown to fail closed on a planted defect; fail-closed path explained |
| Part 4 — Reflection | 15 | Accurate mapping, relevant incident, well-argued best mitigation |
Evidence & Integrity (required)
- Identity proof: every screenshot/diagram must show your **
whoami/ login email / student ID and a timestamp**. Generic or borrowed evidence is not accepted. - Personalized flag (if this lab issues one): ____________________
Flags are unique per student — submitting another student's flag is a violation. See SUBMISSION.md.
- Explain in your own words (graded on your reasoning, not copied text):
- What did you do, and why did the vulnerability work?
- Why does your fix actually stop it — and what could still break it?
🤖 Audit the AI (required)
AI is a power tool you must distrust — you are graded on your critique, not the AI's answer.
- Ask an AI assistant to exploit or fix this week's vulnerability. Paste its full answer.
- Find what's wrong or risky in it — insecure code, a subtly incomplete fix, a hallucinated API/function/CVE, a missed edge case, or wrong reasoning. Quote the exact line(s).
- Produce the correct, verified version yourself and explain in 2–3 sentences why the AI's output was insufficient.
Disclose your AI use in the Part 1 table. This task counts toward your Defense + Reflection score.
🧠 Comprehension & Prompt (required)
A. Explain in Plain English (EiPE). In 2–3 sentences, in your own words, describe what this week's vulnerable code/endpoint actually does and why it is exploitable — explain the mechanism, don't dump jargon.
B. Prompt Problem. Write a single prompt that makes an AI produce a correct, secure fix for one finding. Run it: does the exploit now fail? If not, refine the prompt and try again. Submit the final prompt + the verified result. Graded on the prompt's precision and your verification — this trains problem decomposition and AI literacy (Denny et al. 2024).