Berkner Tech

Threat Modeling an IoT Product With STRIDE

IoT threat modeling loop with STRIDE: diagram, enumerate, rank, mitigate, and validate

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:

Three IoT trust boundaries to threat model first: device to cloud, device to app, and device to hand

Step 2: Apply STRIDE to Every Element

STRIDE is a six-letter prompt you apply to each element of the diagram. Spoofing asks whether an attacker can pretend to be someone else. Tampering asks whether data or firmware can be altered. Repudiation asks whether an action can be denied after the fact. Information disclosure asks what leaks. Denial of service asks what can be knocked over. Elevation of privilege asks how a low-trust actor becomes a high-trust one. Walk every dataflow against all six and the gaps appear.

Doing It 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:

Anatomy of a threat-model-as-code command using pytm to generate STRIDE findings for an IoT product
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
Example output
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.


References and Further Reading