Week 15 · worksheet

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.py are 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

NameStudent IDDateGroup

Part 2 — Lecture Questions

Answer in your own words (2–4 sentences each).

  1. README-pipeline.md says each tool runs twice (report step, then gate step). Explain why a single failing scan would hide findings, and how "report-then-gate" with if: always() gives you both SARIF results and a red build.
  2. What is the difference between fail-closed and fail-open? In sample-service.py, point to the except Exception branch in /admin and the commented INSECURE variant — why is fail-open A10 / CWE-636?
  3. The permissions: block in security-ci.yml is contents: read, security-events: write. Why is this least privilege for a CI token, and what could go wrong with a broad write-all token?
  4. 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)?
  5. 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 /admin in sample-service.py; explain why the broad except Exception returns 403, not the secret, and why type(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 :8090 and 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), a chmod 777 in 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 which exit-code: "1" / --error step 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

  1. Mapping. For three controls you exercised, give: control → A09/A10 (or A02/A03 for a scanner) → CWE → one-line rationale.
  2. 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?
  3. Best mitigation. Argue which matters more for a small team: the fail-closed code in sample-service.py, or the CI gate in security-ci.yml — and why both together beat either alone.

Grading rubric (100)

ComponentPointsWhat earns full marks
Part 2 — Lecture questions20All 5 answered with correct A09/A10/CWE reasoning
Part 3 — Tasks + evidence40Tasks 0–5 complete; PR/run links, log lines, screenshots present
Defense (gate + fail-closed)25Gate shown to fail closed on a planted defect; fail-closed path explained
Part 4 — Reflection15Accurate 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):
  1. What did you do, and why did the vulnerability work?
  2. 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.

  1. Ask an AI assistant to exploit or fix this week's vulnerability. Paste its full answer.
  2. 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).
  3. 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).