Home / Vaults / ThreatModCon 2025
Scaling Threat Modeling with Semantic Knowledge Graphs
ThreatModCon 2025, Barcelona. Eleven linked threat models stacked from the customer at the top to the compute instance at the bottom — a graph of graphs, so a vulnerability in a single line of code can be traced up to the revenue it puts at risk. Five interactive views and five Wardley map walkthroughs, all running inside the vault with no network.
Read key:
sgit_rk1_23fb205247b2b9c88a943d7ffece9dacf9c00c50cc94840668b4916f247b8ec4:0ict6flmIn the official UI: open it read-only in a new tab · From the CLI:
sgit clone sgit_rk1_23fb205247b2b9c88a943d7ffece9dacf9c00c50cc94840668b4916f247b8ec4:0ict6flmPublished deliberately, and derived one-way from a vault key that is not published and never will be.
See it live, here
Opens on the hub; every visualisation below it runs from the vault. You can also open it in its own window ↗.
What is in it
A threat model of one system tells you very little
The hub states the argument and then quantifies it: 11 readable layers, 51 nodes, 179 threats, 3 critical. The zoom ladder runs Customer → Business → Application → Component → Package → Class → Method → Source Code → Environment → Runtime → Compute, each layer carrying its own node and threat counts.
The point of stacking them is traversal, not tidiness. One model answers what could go wrong here. Eleven linked models answer what does this line of code put at risk, which is a different question and the one an executive is actually asking.
One SQL injection, four different messages
The fifth Wardley walkthrough takes a single critical finding in a payment gateway and writes the message four ways — Board Member, CISO, CTO, Developer — each with guidance on how to communicate and a message ready to send.
It is the same instinct as the pentest report vault: the finding does not change, the framing does, and both are derived from one underlying model rather than written four times by hand.
From graph to Wardley map, in five steps
The Wardley set walks from a plain graph to a positioned map, through evolution stages, to security prioritisation — from "everything is critical" to risk-based decisions — and ends on the multi-persona cost view.
It pairs naturally with wardley-maps.sgit.ai, whose argument is that maps are claims, not pictures. These are the claims, drawn.
The whole estate on one screen
Alongside the layered explorer there is a flat view of the same data — end customer, payment processing, user authentication, order fulfilment — for when you want the shape of the system rather than a path through it.
Two upstream data files were broken, and both were repaired in the open
This is the part worth reading even if threat modelling is not your subject. tm-6-class-layer.json and tm-11-compute-layer.json are not valid JSON in the source repository, so the class and compute layers do not load there at all. Both are fixed in this vault, and the vault documents the repair rather than quietly shipping it:
source/threat-models-data/.The upstream being public is what makes the repair auditable rather than merely asserted: the broken originals are at DinisCruz/Presentation-Threat-Mod-Con-2025 ↗, and the vault keeps its own untouched copies beside the repaired ones.
And the fix is stated as something you can check rather than trust: comparing original against repaired line by line, the only differences are four stray closing brackets removed and one ], added — the multiset of all content lines is unchanged. That is a repair expressed as a proof, which is a good deal rarer than a repair expressed as a changelog entry.
Making a presentation survive inside a vault
The pages were already standalone HTML. The work was making them run on a blob: origin with no reliable network:
- Libraries inlined at identical versions — d3 7.8.5, three.js r128, tween.js 18.6.4, taken from each library's npm dist. No page touches the network.
- Data repointed. The explorer used to fetch its layers from an origin bucket. It now tries the vault's own copy through
sg.vfs.readText()first, keeps the bucket as a second chance, and falls back to a snapshot inlined at build time — and reports failure on screen instead of silently rendering nothing. - A host handshake per page. Every page posts
sg-app-ready, because each one becomes the iframe document when you navigate to it.
Verified before publishing: a contract scan of all eleven pages for vault-relative references and surviving CDN links, node --check on every inline script block, hub links resolved against the filesystem, and a jsdom render of each page asserting that d3, THREE and TWEEN initialise and the SVG actually builds.
One class of jsdom error is filtered from that test — and the vault records that it was checked against the untouched original first, which produces the same error. Filtering a failure you have not first reproduced on a known-good input is how a test quietly stops testing.
Notes
It asks for nothing. app.json declares "permissions": {} with present: true.
Audited before publishing. No sgit credentials, no third-party API keys, no private keys, no emails, no external company or client named. The modelled estate is a worked example, not a real customer.
One thing you will only see inside the vault. The threat-model explorer loads its eleven layers through sg.vfs.readText(). Open the file straight off disk and it sits on a loading spinner, because there is no vault bridge to answer it — which is the clearest small demonstration on this site of what the bridge actually does.