DEV Community

Cover image for I couldn't run Microsoft's Threat Modeling Tool on my Mac, so I rebuilt it for the browser
Eric Elikplim Sunu
Eric Elikplim Sunu

Posted on

I couldn't run Microsoft's Threat Modeling Tool on my Mac, so I rebuilt it for the browser

My cybersecurity course teaches threat modelling with Microsoft's Threat Modeling Tool (TMT). You draw a data-flow diagram of a system, and TMT generates a list of STRIDE threats from rules in a template, then you triage each one.

There was one problem: TMT only runs on Windows. I'm on a 2019 Intel MacBook Pro that already struggles, and running Windows in a virtual machine on it was not going to happen.

So I built ThreatSketch: TMT's threat generation, from TMT's own template, in an app that runs in the browser, on macOS, on Windows and on Linux.

ThreatSketch demo gif
Here's how it got there, including the version I threw away.

What already existed

Two tools sat on either side of the gap:

  • Microsoft TMT generates threats automatically. Its rules live in a template file, the SDL TM Knowledge Base (default.tb7), which Microsoft publishes under the MIT licence. But it's Windows-only.
  • OWASP Threat Dragon runs everywhere and draws the same kind of diagram. But it doesn't generate TMT's rule-based threat list, and it doesn't take into account which trust boundaries a flow crosses, which is a big part of how TMT decides what applies.

So the idea was obvious: draw in Threat Dragon, generate threats the way TMT does.

Attempt one: a command-line tool between the two

The first version was tdtm, a Python command-line tool. You drew your diagram in Threat Dragon and saved it, ran tdtm analyze model.json, then reopened the file in Threat Dragon to find the threats attached.

The engine was the hard part, and it worked:

  • It parses TMT's .tb7 template: the stencils (Web Application, SQL Database, HTTPS and the rest), their properties, and the threat rules.
  • TMT's rules are written in a small filter language. The engine parses them into a syntax tree and evaluates that, rather than calling eval on anything from a template or a model.
  • It works out which trust boundary each element sits in and which boundaries each flow crosses.
  • It merges generated threats into the model without ever overwriting a threat you've edited.

On a real lab model drawn in TMT 7.3, it produced the same 54 threats TMT did, and its CSV export matched TMT's row for row.

Using it was another story. Drawing, saving, running a command and reopening the file is a lot of steps for something that should feel instant. You needed Python, the tool and Threat Dragon installed. And Threat Dragon is an Electron app: version 2.6.2 is a 100 MB download and takes 236 MB once installed, and on my laptop you could feel it.

Attempt two: keep the engine, rebuild everything around it

The engine was worth keeping. Everything around it wasn't. So I rebuilt the app around the same Python code:

  • The Python engine runs unchanged in the browser, through Pyodide (Python compiled to WebAssembly) in a Web Worker. It loads in about 2.5 seconds, and each analysis then takes 10 to 50 ms on my laptop, so threats update as you draw.
  • The canvas is AntV X6, the same library Threat Dragon uses. That kept the file format: ThreatSketch saves Threat Dragon's JSON, so a model still opens in Threat Dragon.
  • The interface is Svelte 5 with Vite.
  • The desktop apps use Tauri 2, which uses the operating system's own web view instead of shipping a copy of Chromium the way Electron does.

That last choice is where the size went:

macOS Threat Dragon 2.6.2 ThreatSketch 0.6
Download 100 MB 22 MB (one app for Intel and Apple Silicon)
Installed 236 MB 44 MB

The Windows installer is 9.6 MB. The web version downloads 6.7 MB on the first visit, mostly the Python runtime; it's a progressive web app on GitHub Pages, so after that it works offline, and models never leave your computer.

Making it feel like a drawing tool

Generating the right threats was only half of it. Drawing had to feel quick, more like Figma or Lucidchart than a form:

  • Hover a shape for a + on each side. Click one to connect to the nearest shape on that side, or drag it onto any shape.
  • A flow stays on the side you drew it from and to. Two flows between the same shapes, one each way, bow apart the way they do in TMT, so neither hides the other.
  • Curved or elbow lines, your choice per flow.
  • A "Review before sharing" list flags what a reader would trip over first: elements still called Process or Data flow, a missing description, threats nobody has triaged yet.

And the rest of the TMT workflow:

  • Triage each threat as TMT does: Not Started, Needs Investigation, Not Applicable or Mitigated, with priority and justification.
  • Open and save TMT's own .tm7 files.
  • Export a report laid out like TMT's Full Report (HTML or PDF) and the threat list in TMT's CSV format.

Testing with classmates

Classmates tried it and sent feedback. Feedback on one exported report pointed out that every element still had its default name, so its threats read like boilerplate. That became the "Review before sharing" list.

One classmate went further and sent pull requests that bring in more of TMT:

  • TMT's stencil icons and flow label boxes;
  • its menu bar, toolbar, and Design and Analysis views;
  • its threat list columns and filters;
  • editing a threat's title, category and description;
  • TMT's Notes pane.

They also checked the engine against a second real TMT model with 232 threats, and it matched. I kept TMT's window as an option rather than the default: the simpler layout, where threats appear as you draw, stays first. That work shipped in version 0.6.

Try it

The desktop apps aren't signed yet. The first time you open one:

  • macOS: choose Open Anyway in System Settings > Privacy & Security.
  • Windows: choose More info > Run anyway.

It's free and open source (MIT), and I'd love help with it: https://github.com/ElikplimSunu/threatsketch

  • Star the repo if it's useful to you; it helps other students find it.
  • Found a problem? Open an issue: https://github.com/ElikplimSunu/threatsketch/issues
  • Want to help? Pick an issue, or something you'd like it to do, and open a pull request. Contributions are welcome.

What I'd take from it: the expensive part of this project was knowing exactly what the engine had to do, and that part survived intact. Everything around it could be thrown away and rebuilt smaller, and it was.

Top comments (0)