Threat modeling is the practice of asking how a system could be attacked, then changing the design so those attacks fail. It happens on paper, before anyone writes the code. The simplest example is a sketch of a web app with arrows showing where data moves, and a note at each arrow asking who could tamper with it.
Design-level threats are cheaper to fix than coded ones. Moving a trust check from the client to the server costs a line on a diagram. Doing it after launch costs a rewrite. Here is the baseline system we will model, drawn as the boxes and arrows a team would sketch first:
The diagram shows five parts: a web client, an API, an auth service, a database, and a third-party webhook. Everything runs in one region with one account model. Each arrow is a place where data crosses from one owner to another, and each crossing is a place to ask what could go wrong.
The course follows one system, a multi-tenant SaaS API. Many customers, called tenants, share the same API and database. Each tenant stores its own customer data and has admins who perform sensitive actions like inviting users or exporting records.
The functional scope is small. A user logs in, reads and writes tenant data, and an admin manages the tenant. A webhook sends events to a customer’s outside system when data changes.
The simplest working version is one API server, one auth module, and one database with a tenant_id column on every row. It works for ten tenants. It is also the baseline that later lessons will attack and harden.
Two non-functional signals matter here. The first is scale. Assume 2,000 tenants with 50 users each, so 100,000 accounts. If each user makes 1 request per second at peak, the API sees up to 100,000 requests per second, and one server cannot hold that.
The second is attacker incentive. One database holds every tenant’s data, so a single flaw that skips the tenant_id check exposes all 2,000 customers at once. That makes the system worth attacking.
Security controls also cost something. Checking a token with a remote auth call adds latency to every request. Extra checks on admin actions add operational work for the team. Let’s see how stronger controls trade off against speed and effort: