Threat modelling has a reputation problem: it sounds like a methodology, which sounds like two days and a facilitator. So teams skip it, ship the payment flow, and discover in an assessment that the amount is trusted from the client.
Here is the version that actually happens: ninety minutes, three people, one flow — the one that moves money.
Who is in the room
- One engineer who knows how the flow is implemented.
- One person who knows the business rules — refunds, partial payments, promotions, what "paid" means.
- Someone to write it down who is not either of them.
More than four people and it becomes a meeting. Fewer than three and you miss the gap between what the code does and what the business assumes.
Minutes 0–20: draw it
On a whiteboard, in the room, live. Not a diagram from the wiki, which reflects the architecture of eighteen months ago.
- Every component that touches the transaction: app, API, payment gateway, webhook receiver, database, queue, ledger, email.
- Every arrow, labelled with what data crosses it.
- Draw the trust boundaries as lines: client to server, your infrastructure to the gateway, gateway callback back to you.
- Mark where the authoritative record of "this order is paid" lives. Arguments start here, and the argument is the point.
Minutes 20–40: abuse cases
Stop asking what could break. Ask what someone would try if they wanted free goods, and write each as a sentence.
- "I change the amount in the request and pay ₹1 for a ₹10,000 order."
- "I replay the gateway’s success callback for an order I cancelled."
- "I start a payment, close the app before the callback, and claim the order never completed."
- "I apply the same single-use coupon in twenty parallel requests."
- "I refund to a different account than the one that paid."
- "I am an insider issuing a refund to myself, and nothing records that I did."
Minutes 40–75: STRIDE at each boundary
Walk each boundary crossing and ask the six questions. Speed matters more than completeness — you are looking for the ones that make the room go quiet.
| Threat | Question for this flow | Typical control |
|---|---|---|
| Spoofing | Can someone pay as another user? | Authenticated session bound to the order owner |
| Tampering | Can the amount, currency or item be changed? | Server computes the amount; client sends only an order reference |
| Repudiation | Can a user deny a transaction we cannot prove? | Immutable audit log with gateway references |
| Information disclosure | Does the response leak other orders or card data? | Response shaped per endpoint; no card data stored |
| Denial of service | Can payment attempts be used to exhaust something? | Rate limits per account and per instrument |
| Elevation of privilege | Can a customer trigger a refund or adjust a ledger? | Refunds behind a separate role with dual control above a threshold |
Repeat for the webhook boundary. That one earns its own pass, because callbacks are unauthenticated by default in more integrations than anyone expects: verify the signature, verify the amount against your own record, and make processing idempotent on the gateway’s reference.
Minutes 75–90: turn it into tickets
The output is not a document. It is between four and eight backlog tickets, each with an acceptance criterion a reviewer can check.
- "Server derives the payable amount from the order; the API ignores any client-supplied amount. Test: a tampered amount returns 400."
- "Webhook handler verifies the signature and is idempotent on the gateway reference. Test: replaying a callback creates no second fulfilment."
- "Coupon redemption is atomic under concurrency. Test: twenty parallel redemptions of a single-use coupon succeed once."
- "Refunds are role-restricted and audit-logged with actor, amount and reason. Test: a customer role receives 403."
Photograph the whiteboard, attach it to the epic, and put a recurring ninety-minute session in the calendar for the next quarter. A threat model that is refreshed twice is worth more than one that was perfect once.