SwadhyAI Notes

All System Design notes

System Design · Security

Threat Modeling for System Design

“Design a URL shortener” is incomplete until someone asks who can mint a redirect to malware, enumerate private slugs, or melt the hot key. A is that conversation, written down.

Draw a with , walk , grow an for the crown-jewel goal, then attach and honest .

Modeling journey

1

Links, keys, reputation, capacity.

2

Flows and stores, then boundaries.

3

Walk each element once.

4

Cheapest path to the goal.

What actually happens

Start from and actors, not from tools. A DFD without the click analytics store will miss disclosure of browsing history. Every cross-boundary flow is a candidate for spoofing or tampering.

is a checklist on those elements. An is better when you already know the attacker’s goal (take over redirects, ransom availability). keep both tied to product language.

Heavier methods (, for privacy) belong when the business risk is high. Interview answers should still be STRIDE + tree + residual risk in ten minutes, fed by (“credential stuffing is real on this login”).

How to run a design-time model

1. Scope. One user journey (create link, follow link, admin disable). Unbounded whole-company models never finish.

2. Diagram. Processes, stores, externals, data flows. Circle trust boundaries. Delete decorative boxes.

3. Threaten, then mitigate. STRIDE cells, tree for the top goal, map each high-likelihood path to a control, owner, and metric. Record residual risk in the same doc.

Simple rule of thumb

If you cannot name the cheapest path to the worst asset, you do not have a threat model yet—you have a architecture poster.

Data-flow threats

Boundaries are where STRIDE earns its keep

Diagram text: the exact Mermaid definition below preserves the nodes, labels, and connections. Enable JavaScript to view the rendered diagram.
Read the diagram definition
flowchart LR
  Browser["Browser"] -->|HTTPS| Edge["Edge / WAF"]
  Edge -->|mTLS| API["URL API"]
  API --> Cache["Cache"]
  API --> DB["Link store"]
  API --> Queue["Click events"]
  Queue --> Analytics["Analytics"]
  Admin["Admin SSO"] --> API
  subgraph TB1["Trust boundary: internet"]
    Browser
  end
  subgraph TB2["Trust boundary: control plane"]
    Admin
  end
  subgraph TB3["Trust boundary: data"]
    DB
    Analytics
  end
ElementSTRIDE
Browser → edgeFake Host / stolen cookieTLS strip if you allow HTTPShared NAT IPsReferrer leaksVolumetric + L7—
API processForged internal headerIDOR update targetNo actor on writesVerbose errorsHot slugDebug endpoint
Link storeStolen DB roleRow rewriteDeletes without auditDump of private slugsLock contentionOVER_GRANT role
Analytics storeJob identity reusePoisoned eventsUnsigned pipelineClick trailsUnbounded fan-outWarehouse SA → OLTP

Data-flow threats include metadata: slug length, timing of follows, and cache hit ratio can leak that a private campaign exists even when the target URL is encrypted at rest.

STRIDE in interview English

One sentence each, then a control

S · Spoofing

Prove identity: mTLS, SSO, bound cookies. Never trust X-User-Id from the client.

T · Tampering

Integrity: TLS, signed payloads, optimistic concurrency on link records.

R · Repudiation

Accounting: immutable audit with actor, resource, reason—not just NAT IP.

I · Info disclosure

Unguessable slugs, no sequential IDs, field encryption, error hygiene.

D · Denial of service

Per-slug and per-IP budgets; cache popular keys; cap origin RPS.

E · Elevation

No debug listeners; workers cannot write the link table; admin is JIT.

Attack trees

AND/OR paths beat a flat bug list

Diagram text: the exact Mermaid definition below preserves the nodes, labels, and connections. Enable JavaScript to view the rendered diagram.
Read the diagram definition
flowchart TB
  G["Goal: steal or hijack short links"]
  G --> S["Spoof admin session"]
  G --> T["Tamper with redirect target"]
  G --> R["Repudiate abusive clicks"]
  G --> I["Info: enumerate private slugs"]
  G --> D["DoS the lookup path"]
  G --> E["Elevate: worker writes DB"]
  S --> S1["Phish SSO"]
  S --> S2["Steal cookie on XSS"]
  T --> T1["IDOR on update API"]
  T --> T2["Poison cache entry"]
  I --> I1["Sequential slug brute force"]
  D --> D1["Hot-key flood on popular slug"]

AND vs OR nodes

OR means any child suffices (phish or XSS). AND means both are required (steal session AND hit an IDOR that still trusts the session). Mitigations on AND nodes are high leverage: break either child. Mitigations on OR nodes must cover every child or the attacker shops.

Annotate cost, not only possibility

A 128-bit slug space makes brute force more expensive than buying a stolen admin cookie. Spend engineering on the cheap leaf. That is how threat models prioritize, unlike equal-weight STRIDE coloring.

From model to design changes

Controls, detection, residual risk

Worked shortener controls

  • Random 64+ bit slugs; rate-limit create and lookup independently.
  • Updates require owner or admin; IDOR tests in CI.
  • Cache keys include slug + target version so poison is versioned out.
  • Click pipeline is append-only and cannot UPDATE links.

Detection and residual

  • Alert on target-URL changes, bulk creates, and origin RPS vs cache hit.
  • Residual: a phished admin still redirects until session revoke SLO fires.
  • Residual: metadata of private slugs if length and timing leak.

Sizing: 10k create/sec with 8-byte slugs is not the security problem; sequential 6-character base62 (~56B space) at 100k guesses/sec is enumerable in days. That one number should change the ID design before you discuss Kafka.

Trade-offs

Breadth vs finishability. Whole-estate PASTA never ships. One journey STRIDE does. Time-box, then iterate when intel changes.

Checklist vs trees. STRIDE avoids forgetting DoS. Trees show combinations. Use both; do not score STRIDE cells as if they were CVSS.

Prevent vs detect. Blocking unguessable IDs is cheap. Detecting a phished admin needs session analytics. Budget both.

Privacy vs security STRIDE. LINDDUN finds linkability the CIA triad under-weights. Dual-running both on the same DFD is extra work and extra truth.

Accepted residual vs theater. Writing “risk accepted” without an owner is how models become wallpaper.

What must never become false

Every flow that crosses a trust boundary must have a named spoofing and tampering story, and the cheapest path to the highest-value asset must either be mitigated or explicitly accepted with an owner. A diagram without that path is not a threat model.

Failure timeline: model skipped the store

T+0      Whiteboard STRIDE on the HTTPS API only
T+2w     Sequential slugs ship; "we'll add auth later"
T+1m     Attacker enumerates campaign links; disclosure (I) never had a cell
T+1m+1d  Analytics job uses the API role; dumps click trails
T+1m+2d  Hot celebrity slug stampede; origin has no per-key budget (D)
Outcome  The DFD omitted stores and the tree omitted cheap leaves

Exercises

  1. Draw a level-1 DFD for create/follow/admin-disable. List one STRIDE hit per boundary crossing and one residual risk you would accept at v1.
  2. Build an attack tree for “replace a bank’s short link with a phishing URL.” Mark AND/OR. Which single control prunes the most expensive limb?
  3. 6-char base62 slugs, 100k guesses/sec. About how long to cover the space? What bit length would you pick instead, and how does that change cache key size at 10k create/sec?

Choosing and explaining threat modeling

A complete explanation connects the mechanism to a requirement. Describe what improves when you introduce it, which new failure cases become possible, and how you would know that the trade-off is worthwhile.

Explain the core idea

Assets and actors first, then a DFD with trust boundaries, then STRIDE on each element.

For the crown-jewel goal, grow an attack tree so AND/OR paths show where one control prunes a limb.

End with mitigations, detection, owners, and residual risk—otherwise it is a poster.

When it belongs

Any system-design interview after the happy-path boxes are drawn.

Design reviews for new data stores, admin planes, or public write APIs.

When privacy (LINDDUN) or business-risk processes (PASTA) are in scope.

How it fails

Missing stores and metadata flows from the DFD.

STRIDE as wallpaper with no cheap-path ranking.

Controls without owners or metrics.

Ignoring residual risk, especially phished authentic sessions.

Trade-offs to weigh

Time-boxed journey models versus never-finished estate models.

Prevention cost versus detection coverage.

Privacy modeling extra pass versus missing linkability.

Common misunderstandings

Confusing a pentest report with a threat model.

Treating STRIDE letters as a numeric score.

Modeling only the public API and skipping workers, caches, and admin SSO.

Saying “we use TLS” as the entire tampering story.

Primary references

Short takeaway

Threat modeling is how system design earns its security claims: diagram the flows, walk STRIDE, tree the prize, and write the leftover risk where an interviewer can see it.