S083 · OWASP Top 10, Secrets Mgmt & Threat Modelling
The 10 ways your app will get hacked, and how to stop it.
Module M10: Security · Session 83 of 130 · Track: SYS 🛡️
What you'll be able to do after this session
- Explain OWASP Top 10, Secrets Mgmt & Threat Modelling to a friend in one minute, out loud, no notes.
- Recognise it when you see it in real code / systems / papers.
- Complete the hands-on exercise at the end without looking up help.
Prerequisites
If you can't answer these in 30 seconds each, redo the linked session first:
Pre-read (skim before the session)
- 🎥 Intuition (5–15 min) · OWASP Top 10 explained in 10 minutes — Fireship — the whole list in one coffee break.
- 🎥 Deep dive (30–60 min) · OWASP Top 10 2021 walkthrough — F5 DevCentral — category by category with real CVE examples.
- 🎥 Hands-on demo (10–20 min) · SQL Injection demo with DVWA — LiveOverflow — watch an attacker exfiltrate a database in real time.
- 📖 Canonical article · OWASP Top 10 2021 — the source of truth.
- 📖 Book chapter / tutorial · PortSwigger Web Security Academy — Learning path — free, hands-on, industry standard.
- 📖 Engineering blog · GitHub — Threat modelling the way we ship — how a real team institutionalises threat modelling.
(a) Intuition · 5 min
The one-paragraph mental model. Why this concept exists, what problem it solves, and the analogy that makes it stick.
In one sentence: The 10 ways your app will get hacked, and how to stop it.
The OWASP Top 10 is exactly what it sounds like: the ten most common categories of web-app security failure, curated every few years by the Open Web Application Security Project from a survey of thousands of real breaches. Think of it as the checklist every code review, every pen test, every SOC 2 audit implicitly runs against.
Reading it once won't make you secure — but not reading it is professional malpractice. Almost every breach you've heard of (Equifax, Capital One, Target, LinkedIn, Uber, Optus) maps to one of these categories. The 2021 edition, in rough priority order: A01 Broken Access Control, A02 Cryptographic Failures, A03 Injection, A04 Insecure Design, A05 Security Misconfiguration, A06 Vulnerable Components, A07 Identification/Authentication Failures, A08 Software & Data Integrity, A09 Logging/Monitoring Failures, A10 SSRF.
Secrets management is the operational side. Every production system has API keys, DB passwords, signing keys, TLS certs. Where do they live? Not in git. Not in env files checked into the repo. Not in Slack. The industry answer is a vault: HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault. Fetched at runtime, rotated automatically, never touched by a human.
Threat modelling is the proactive discipline. Before you ship a feature, you sit down with the design and ask, methodically, "who might attack this, how, and what's the blast radius?". The industry framework is STRIDE: Spoofing, Tampering, Repudiation, Information disclosure, Denial of service, Elevation of privilege. Ten minutes of STRIDE per feature would have prevented most breaches on the front page.
Gotcha to carry forever: All ten of these categories are design and process failures, not "we forgot to install a library". You cannot bolt security on at the end — it has to be baked into how you design, code, review, deploy, and monitor.
(b) Visual walkthrough · 15 min
Diagrams, worked examples, step-by-step visuals.
The 2021 Top 10, ordered by frequency of appearance in real incidents:
| # | Category | One-line meaning | Real breach |
|---|---|---|---|
| A01 | Broken Access Control | User A can read User B's data via URL tampering | Facebook 2019 (50 M tokens) |
| A02 | Cryptographic Failures | Data in transit/rest not properly encrypted | Equifax 2017 partially |
| A03 | Injection | Untrusted input becomes code (SQLi, XSS, cmd) | TalkTalk 2015 SQLi |
| A04 | Insecure Design | Business logic itself is flawed | Coinbase 2022 |
| A05 | Security Misconfiguration | Default creds, verbose errors, open S3 buckets | Capital One 2019 (S3 + SSRF) |
| A06 | Vulnerable/Outdated Components | Old lib with known CVE | Equifax 2017 (Struts CVE) |
| A07 | Auth Failures | Weak passwords, no MFA, session mgmt bugs | Colonial Pipeline 2021 |
| A08 | Software/Data Integrity | Unsigned updates, insecure deserialisation | SolarWinds 2020 |
| A09 | Logging/Monitoring Failures | Breach detected 200 days late | Target 2013 |
| A10 | SSRF | Server-side request forgery to internal metadata | Capital One 2019 |
Here's the STRIDE threat-model loop you should run on every new feature:
Worked example — Capital One 2019 breach mapped:
- A10 SSRF: the WAF (Web Application Firewall) had an SSRF bug an attacker used to call
http://169.254.169.254/(AWS instance metadata). - A05 Misconfig: the IAM role attached to that instance had
s3:*on 700+ buckets — over-privileged. - A01 Broken Access Control: the attacker used those creds to enumerate and download 100 M records.
- A09 Logging Failure: exfil happened over months; no alert fired on the massive S3 GET volume.
Four categories, one incident, 100 M records leaked.
(c) Hands-on · 20 min
Code you type and run. Not pseudo-code — real, runnable, copy-pasteable.
Do the before and after on the two most common failures: SQL injection and hard-coded secrets.
# ---------- SQL Injection: BAD vs GOOD ----------
import sqlite3
db = sqlite3.connect(":memory:")
db.executescript('''
CREATE TABLE users(id INT, name TEXT, email TEXT);
INSERT INTO users VALUES (1,"alice","a@x.com"),(2,"bob","b@x.com");
''')
# BAD: string concatenation — attacker input is executed as SQL
def bad_lookup(name):
q = f"SELECT * FROM users WHERE name = '{name}'"
print("QUERY:", q)
return db.execute(q).fetchall()
# GOOD: parameterised query — driver escapes for us
def good_lookup(name):
return db.execute("SELECT * FROM users WHERE name = ?", (name,)).fetchall()
# Normal input works for both
print("bad ok :", bad_lookup("alice"))
print("good ok:", good_lookup("alice"))
# Malicious input
payload = "alice' OR '1'='1"
print("BAD returns EVERYTHING:", bad_lookup(payload))
print("GOOD returns nothing: ", good_lookup(payload))
# ---------- Secrets: BAD vs GOOD ----------
# BAD: hard-coded in source, ends up in git history forever
API_KEY = "sk-live-abcdef1234567890" # never do this
# GOOD: fetch at runtime from environment (12-factor) or a vault
import os
API_KEY = os.environ.get("STRIPE_KEY")
if not API_KEY:
raise RuntimeError("STRIPE_KEY missing — refuse to start")
# ---------- Tiny threat model in code comments ----------
# Feature: /api/download?report_id=42
# STRIDE:
# Spoofing: require session cookie (S081)
# Tampering: URL is server-authoritative; server picks path
# Repudiation: audit log user_id + report_id + timestamp
# Info disclosure: AuthZ check: does user own report 42? <-- often forgotten
# DoS: rate limit 60/min per user
# Elevation of priv: report path must stay inside /reports/, no ../Observe when you run it:
- The BAD query with
alice' OR '1'='1returns every user — the whole table. - The GOOD query returns
[]— the driver treats the payload as a literal string. - Printing the raw query in BAD makes the attack obvious. In prod, you'd never see the query.
- The
os.environ.get()pattern is the minimum bar; a real vault is one step further. - The STRIDE comment block is the deliverable of a threat model — six categories, six mitigations, per feature.
Try this modification: add a /report HTTP endpoint that accepts a filename. First write it insecurely (open(user_input)). Then fix it by (a) whitelisting to /reports/, (b) calling os.path.realpath and checking it starts with /reports/. That's the "path traversal" fix — a subclass of A01.
(d) Production reality · 10 min
How this shows up in real systems, gotchas, war stories, common bugs.
Equifax 2017 (148 M records, USD ~1.4 B in costs). A known Apache Struts CVE, patched 2 months prior. Nobody in the org owned "patch the framework". A06 + A09 (no log alert on the anomalous outbound traffic). Fix: SBOM (software bill of materials) + auto-scanning (Dependabot, Snyk, Trivy) as blocking CI checks.
SolarWinds 2020. Attackers compromised the build system and inserted a backdoor into signed updates. Every customer that auto-updated (~18,000 orgs, including US federal agencies) got the backdoor. A08 — Software and Data Integrity Failures. Fix: SLSA framework, reproducible builds, signed provenance (Sigstore).
Log4Shell (Dec 2021, CVE-2021-44228). One-line JNDI lookup in a logging library let attackers RCE any Java app that logged a user-controlled string. Every ops team on Earth spent Christmas patching. Lesson: transitive deps you didn't know you had can end your career.
The AWS SSRF pattern. The instance metadata endpoint http://169.254.169.254 gives IAM creds. Any SSRF bug in your app becomes credential theft in seconds. Fix: IMDSv2 (requires a token, blocks trivial GET), and least-privilege IAM roles.
How top teams operate:
- Security paved road: one blessed way to do auth, secrets, TLS. Deviations require security review.
- Bug bounty: HackerOne / Bugcrowd — pay researchers instead of getting extorted.
- Red team / purple team exercises.
- Blameless postmortems on every incident, published internally.
- Secrets scanning in CI: GitHub Secret Scanning, TruffleHog, gitleaks — reject the PR if a key is committed.
- Automated dependency updates: Renovate/Dependabot with auto-merge for green PRs.
The mindset shift. Security isn't a team you throw problems at; it's a property of the whole software delivery pipeline — code, review, build, deploy, run, monitor. If security is a bottleneck team, you've built it wrong.
(e) Quiz + exercise · 10 min
- Name three of the OWASP Top 10 categories from memory and give a one-line real-world example of each.
- What is STRIDE and why do you run it before writing code, not after?
- Why is hard-coding an API key in source (even in a private repo) considered a critical failure?
- Explain how the Capital One 2019 breach chained A10 (SSRF) with A05 (misconfig) and A01 (broken access control).
- What is an SBOM and why did Log4Shell push the industry to adopt them?
Stretch (connects to S082 — TLS/PKI): Design the certificate + secrets story for a new microservice: how does it get (a) its TLS cert, (b) its database password, (c) its API key for a third-party service — such that no human ever sees any of them and rotation is automatic? Sketch the components involved.
Explain-out-loud test
If you can't teach these 3 things to a friend without notes, redo the session:
- What is OWASP Top 10, Secrets Mgmt & Threat Modelling? (one sentence, no jargon)
- When would you use it? (one concrete example)
- When would you NOT use it? (one anti-pattern)
What comes next
- Next session (S084): The ML Mental Model — Features, Labels, Train/Val/Test
- Previous (S082): TLS 1.3, PKI & Cert Lifecycle
- Hub: The 6-Month Learning Plan
Part of a 130-session evergreen learning series. Session structure: (a) intuition · (b) visual walkthrough · (c) hands-on · (d) production reality · (e) quiz + exercise. Duration: 60 minutes.
More from M10 · Security
all modules →