Threat Modeling an IoT Product with STRIDE
Most security problems in connected products are not coding bugs. They are design decisions that were never questioned. Threat modeling is the practice of questioning them on purpose, before the hardware exists, and STRIDE is the checklist that makes it systematic. Here is how I run a threat model on an IoT product and turn it into a list a team can actually act on.
Why Threat Modeling Beats Bug Hunting
Penetration testing finds the bugs you shipped. Threat modeling finds the bugs you were about to ship, while they still cost an afternoon to fix instead of a recall. It works on a whiteboard, needs no hardware, and surfaces the structural problems that no scanner will ever catch: a missing authentication step, a trust boundary that was never drawn, an update path with no signature.
Step 1: Draw the System
Start with a data-flow diagram: the processes, the data stores, the external actors, and the lines of data between them. The lines that cross a trust boundary are where threats concentrate, so those are the ones to draw carefully.

Step 2: Apply STRIDE to Every Element
STRIDE is a six-letter prompt you apply to each element of the diagram. Walk every dataflow against all six and the gaps appear.
| Letter | Threat | The question it forces |
|---|---|---|
| S | Spoofing | Can an attacker pretend to be another user, device, or service? |
| T | Tampering | Can data, firmware, or a message in transit be altered? |
| R | Repudiation | Can someone perform an action and later deny doing it? |
| I | Information disclosure | What leaks, whether in transit or at rest? |
| D | Denial of service | What can be knocked over, exhausted, or jammed? |
| E | Elevation of privilege | How does a low-trust actor become a high-trust one? |
Keep the Model as Code
A threat model written as code stays in sync with the design instead of rotting in a slide deck. A small framework like pytm lets you describe the system and generate the threats from it:

from pytm import TM, Server, Dataflow, Actor
tm = TM("Smart Lock")
user = Actor("Mobile App User")
api = Server("Cloud API")
lock = Server("Lock Controller")
Dataflow(user, api, "unlock request (HTTPS)")
Dataflow(api, lock, "unlock command (MQTT)")
tm.process()python3 tm.py --report template.md --dfd
Generating threats for: Smart Lock [HIGH] Spoofing the Mobile App User: no mutual auth on API [HIGH] Tampering with the unlock command in transit [MED] Information disclosure: unlock events logged in clear [MED] Denial of service: unbounded unlock retries [LOW] Elevation of privilege via the debug interface Wrote 14 threats to report.md
Each line maps to a letter of STRIDE and to a specific dataflow on the diagram. That traceability is what turns a vague worry into an assignable ticket.
Step 3: Rank and Mitigate
Not every threat earns a control. Rank them by impact and likelihood, then assign each high-priority item a concrete mitigation: mutual authentication on the API, a signature on the unlock command, readout protection on the controller. The output of a good threat model is a short, prioritized list of design changes, not a hundred-page document no one reads.
Where This Fits
A structured threat model is the front end of secure product development, and it is one of the three services we lead with. Building the model with your team and turning it into a ranked set of design fixes is the kind of work we do at Berkner Tech.



