Part one: the Tech Stack Graph
Every repository is scanned on its own and knows nothing about the others. Each publishes what it provides and what it consumes, and an edge forms wherever one repository's consumes meets another's provides. The estate assembles itself, without a central inventory anyone has to maintain. An edge is never inferred from a name that looks similar, which is why the graph holds up on a monorepo and on two hundred services alike.
A datum that exists but cannot be seen is a datum nobody trusts, so the canvas is the keystone and every other view hangs off it. Click a repository for its run detail and all 58 metrics by family; click a node for every field it carries, the repositories it crosses into, the metrics that cite it and its connections. A metric opens the evidence behind it, down to the individual record, with SARIF findings rendered alongside their code snippets.
The joins that make one graph out of many scans
Packages
What a repository publishes to a registry, and what every other repository installs. The join that answers "who ships this, and who consumes it".
Services
HTTP and RPC surfaces a repository serves, matched against the ones other repositories call.
Containers
Images built here and images pulled there, joined through the registry reference rather than a guess at the name.
Infrastructure as code
Declared cloud resources across AWS, Azure, GCP and Kubernetes, plus the Terraform modules and providers that declare them.
Helm charts
Charts a repository publishes and the ones a deployment repository depends on.
Registries
npm, Maven, Terraform, Helm and OCI registries: where artefacts come from, and the supply-chain edge a compromised upstream would travel along.
Routes and workflows
The HTTP surface a repository serves and the CI workflows that build it, so the build system is part of the picture rather than beside it.
Code and people
Files, functions, methods, classes and interfaces where a scan resolved them, plus the contributors who can change each repository.
What the graph does that a diagram cannot
Rewind the whole estate
Pick an instant and every panel resolves each repository to the run it had then, so the canvas, the side panel and the drawers all describe the same moment rather than mixing a snapshot with head.
Scales by not loading what you have not opened
A repository-level skeleton first, a repository interior only when you open it. Tens of thousands of nodes still open in a browser tab.
Twenty-five node kinds, filtered to taste
Visibility is a per-user preference that records what you were offered, so a kind you turned off stays off when a later release adds new ones.
Every number opens the records behind it
A metric that says 23 opens the 23 things it counted, each expandable to the full record, with SARIF findings rendered alongside their code snippets.
Browse what nothing cited
The records drawer holds everything the scan stored, not only what a metric happened to count. Coverage you can check is the difference between a report and an assertion.
Trends, not just values
Any metric across every run, so a number that moved reads as a movement rather than as a new value.
Metrics no single repository can compute
Orphaned repositories, the organisation bus factor and shared-library fan-out, computed hourly across the estate and landing as ordinary metrics beside the rest.
Third parties are part of the stack
The hosts your code reaches out to are structural nodes. Egress is what turns a dependency list into a picture of where data goes.
Ownership is a first-class edge
Contributors are nodes. A repository nobody has touched in a year with a bus factor of one is an architecture risk, and this is where it becomes visible.
One repository failing does not blank the page
A scan error is scoped to the repository it happened in. Only a failure of the graph itself covers the canvas.
No catalog to maintain
No YAML file describing your services that somebody has to keep current. Every edge exists because a scan found a declaration on both sides.
The whole run is on the page
Tool, window, collectors, diagnostics, truncation and history. If a scan stopped early, the page says so instead of quietly reporting a smaller number.
What teams open it to answer
Blast radius
A vulnerable package in one repository is a question about every repository that consumes it. Follow the join instead of grepping for a string across an organisation.
Supply-chain exposure
Which registries you pull from, which base images you build on, and which repositories inherit them: the path a compromised upstream would travel.
Incident scoping
A CVE lands on a Friday. The graph turns "are we affected" into a traversal, and the evidence drawer produces the records to attach to the ticket.
Ownership and continuity
Orphaned repositories, single-maintainer services and fan-out on a library nobody owns, visible before any of it becomes an incident.
Architecture review and onboarding
A new engineer, an auditor or an acquirer sees how the estate fits together without a workshop, and can time-shift to see how it got that way.
Inventory that stands up in an audit
Every node traces to a scan run with a timestamp, a tool and a collector. The inventory has provenance, not just contents.
Part two: the threat model
A zone is a column, a column is a side of a trust boundary, and a flow that crosses one is where the threats are. The diagram reads left to right, from the people outside to the things worth stealing.
Internet
Outside every boundary you control. The ordinary user at the end of a route, the outside contributors who can change the code, and the third parties your code sends data to.
Entry points
What accepts a request from outside. Every HTTP route the analyzer found, plus the load balancers, gateways, CDNs, WAFs and tunnels it recognises. Every flow into this column crosses a boundary.
Internal
Reachable only once something in the entry column has been used. Services, container images, compute and the repositories themselves.
Data and secrets
What an attacker is actually after. Databases, buckets, queues and caches, and the secret stores that front them.
Assembled from evidence, not from memory
Every element traces back to something a scan observed. Entry points are the HTTP routes the analyzer found, collapsed into one sorted table per repository rather than sixty boxes, plus anything matching the public-ingress catalogue: load balancers, API gateways, CloudFront, Apigee, ingress controllers, WAFs, network firewalls, proxies, tunnels, function URLs and AI gateways. Data stores are the databases, object storage, queues, streams, caches and secret managers recognised across AWS, Azure, GCP and Kubernetes, with exposure winning over storage so a public bucket is drawn on the boundary rather than behind it. Third parties come from outbound calls found in code, not from every hostname mentioned in a config file, which is the difference between six real destinations and five hundred blocklist entries.
Where the product infers rather than observes, it says so: inference is drawn hollow and dashed, and an analyst's annotation always overrules it. An entry point somebody meant to expose and one nobody asked for are different facts, and the diagram keeps them apart.
A real editor, not a rendered picture
Your layout survives the rescan
Zones, positions, sizes, flows and annotations are stored. A rebuild adds what is new and dates what is gone, never moves, renames or deletes your work, and archives rather than destroys.
Columns you can move and resize
Four fixed columns cannot describe an estate with a DMZ, a partner network and several VPCs, so a zone is a rectangle you drag, stretch and name.
Draw the flows a scanner cannot see
Connect from any side of any element, drag either endpoint later, label the line. The batch job that reads the database at midnight is real even though no scan will find it.
Citable reference numbers
Every shape and line carries a stable sequential id, so an assessor can write "the flow at &12 crosses the boundary without authentication" and everyone is looking at the same thing.
Undo that goes back far enough
Two hundred steps of geometry, connections and labels with the usual keyboard shortcuts. Rearranging a diagram is exploratory work and should be safe.
A tray for what is not placed yet
Newly discovered elements arrive in a tray rather than scattered onto your diagram. You decide what belongs on the canvas.
Inference is drawn as inference
Anything derived rather than observed is hollow and dashed, and your annotation overrules it in both directions, including a human saying this is not exposed.
One model, or one per system
As many saved models as you have systems to describe, each with its own zones, annotations and attack path. Archive the ones that have served their purpose.
Rebuild a repository at a time
An estate too large for one request rebuilds per repository, so a model of two hundred services refreshes without a long-running job.
Only seven groups reach the canvas
A threat model is not an inventory. The vocabulary that would bury an attack path in ten thousand dependency nodes is never requested from the server, not merely hidden in the browser.
One diagram, five vocabularies
Switching methodology changes the face of each threat card and nothing else, so an analyst who has arranged a diagram never has to rearrange it to answer an assessor's question in a different vocabulary. Where a methodology genuinely has nothing to say about a threat, the card reads Unmapped: a fabricated privacy category on an evidence diagram is worse than a blank one.
STRIDE
Spoofing, Tampering, Repudiation, Information disclosure, Denial of service, Elevation of privilege, mapped through the attacker-capability vocabulary that already drives the rest of the product.
LINDDUN
Deliberately sparse. LINDDUN classifies threats to a data subject, and most application CVEs are not privacy threats; the common answer is Unmapped and it stays that way.
DREAD
Five axes derived from the CVSS vector, CWSS, EPSS, KEV membership and whether a public exploit exists, rather than scored by a person in a room. Every axis reports where its number came from.
PASTA
A seven-stage process, not a taxonomy. Stages 1 to 3 are business activities no scan can evidence and the legend says so; 4 to 7 map onto the attack-path stage a threat was correlated into.
OCTAVE
The face names the trust zone of the element at risk: a data-store threat and an edge threat are different risks even when they are the same CVE.
Attack paths from intrusions that really happened
An attack path is a sequence of MITRE ATT&CK vectors, and selecting one lights the elements in your architecture that satisfy each stage: an overlay, never a rearrangement. Paths whose techniques a named group or ATT&CK campaign has actually used carry a marker, so a plausible path and an observed one are not the same claim. Load a documented campaign as a starting point and it is projected onto stages in kill-chain order, with whatever did not fit stated rather than dropped. The same path definitions drive risk prioritisation, so a finding the diagram lights up and a finding the queue puts at the top are the same rule evaluated twice.
What the model is for
Design review without a workshop
The diagram already exists and already carries the current findings, so the review starts at the argument rather than at the drawing.
Evidence for an assessor
OWASP DSOMM asks for annotated diagrams with the identified threats, recorded where the team can find them. Export as OSCAL or as an evidence pack and the request is answered.
Prioritise by what the thing is
The same CVE on a public gateway and on an internal batch worker are different risks. Zone membership is the context that makes that judgement without a meeting.
Scope a penetration test
Hand the tester the entry points, the trust boundaries and the third parties in one picture, with reference numbers to quote in the report.
Run a tabletop against a real campaign
Load a documented MITRE ATT&CK campaign, see which stages your architecture satisfies, and argue about the ones it does.
Show that the boundary is where you say it is
Every flow crossing a zone edge is recorded, so segmentation claims stop being architectural intent and become something on a diagram you can point at.
Evidence an assessor can read
OWASP DSOMM asks for annotated diagrams with the identified threats, recorded where the team can find them, and a diagram with zones and no threats on it is architecture, not threat modelling. Export the model as OSCAL, where each correlated vector is an observation and each annotation a finding, or as an evidence pack carrying the rendered canvas alongside the records behind it. Re-exporting an unchanged model is byte-comparable. Zones, positions, flows and annotations persist: a rescan adds what is new and dates what is gone, and never moves, renames or deletes your work.
How this compares
Six categories of tool overlap with some part of this, and each is better than Vulnetix at something. Here is where the line falls, including where it falls against us.
Diagram-first threat modelling tools
Compared with IriusRisk, ThreatModeler, SD Elements, OWASP Threat Dragon, Microsoft Threat Modeling Tool
These start from a drawing or a questionnaire somebody keeps current, and generate threats from a curated library. Vulnetix starts from your scans: the elements are what was found, and the threats are your actual open findings with their CVSS, EPSS, KEV and exploit evidence. If you need a governance questionnaire and a countermeasure library mapped to a control framework, those tools do that and this does not.
Threat modelling as code
Compared with Threagile, pytm, STRIDE-GPT
A YAML or Python description of the architecture, versioned with the code. The idea is right and the maintenance is the catch: the file is only as accurate as the last person to update it. Here the architecture comes out of the same scan that produces the SBOM, and the parts a scan cannot know stay editable by hand.
Cloud security graphs
Compared with Wiz, Orca, Tenable, XM Cyber, RedSeal
These read the running estate through cloud APIs, agents and network configuration, and are very good at it. Vulnetix reads what your repositories declare and ship, so it works before anything is deployed and inside CI, with no cloud credentials, no agent and no access to your production account.
ASPM risk graphs
Compared with Apiiro, Cycode, OX Security, ArmorCode, Snyk AppRisk
The nearest neighbours: correlate code, build and cloud into one graph and rank the toxic combinations. The difference is what you get out. Here it is a real data-flow diagram you can edit, annotate and hand to an assessor as OSCAL, and every number on it opens the records it counted rather than ending at a score.
Developer portals and software catalogs
Compared with Backstage, Cortex, OpsLevel, Port
A catalog is a set of YAML files describing services, kept current by the people who remember to update them. The Tech Stack Graph is assembled from scans, so it cannot drift from the code. It is not a portal: no scaffolder templates and no engineering scorecards.
Attack path and exposure management
Compared with XM Cyber, RedSeal, Skybox, Tenable One, Cymulate
Network-layer path analysis across a live estate, usually with an appliance or agents. Attack paths here are sequences of MITRE ATT&CK vectors correlated against your architecture and findings, and the same definitions drive risk prioritisation, so what the diagram calls critical and what the queue calls critical are the same rule.
Questions people arrive with
Do I have to draw the diagram?
No. The first build derives zones, elements and flows from your scans and places them. From then on it is yours: move anything, add the flows a scanner cannot see, rename the zones. A rebuild adds what is new and dates what is gone, and never undoes an edit.
Is Vulnetix an alternative to IriusRisk, ThreatModeler or SD Elements?
For teams whose threat models go stale because nobody maintains the drawing, yes. The trade is deliberate: you give up a curated countermeasure library and questionnaire-driven governance, and you get a diagram derived from evidence that carries your real findings.
How is this different from a cloud security graph like Wiz or Orca?
Those model the running cloud through cloud APIs and agents. This models what your repositories declare and ship, so it works before deployment and inside CI, with no cloud credentials, no agent and no access to your production network. They answer what is exposed right now; this answers what your architecture is and where the threats sit in it.
Does it replace Backstage, Cortex or a service catalog?
It replaces the part of a catalog that goes out of date, because the graph is assembled from scans rather than from YAML somebody maintains. It is not an internal developer portal: no scaffolder, no golden paths, no engineering scorecards.
Which threat modelling methodologies are supported?
STRIDE, LINDDUN, DREAD, PASTA and OCTAVE. Switching one changes the face of each threat card and nothing else, so a diagram you have arranged is never rearranged to answer a question in another vocabulary. Where a methodology genuinely has nothing to say, the card reads Unmapped rather than inventing a category.
Can I export something an auditor will accept?
Two things. OSCAL assessment results, where each correlated attack vector is an observation and each annotation is a finding, and an evidence pack carrying the rendered diagram alongside the records behind it. Re-exporting an unchanged model is byte-comparable, which is what makes it usable as evidence.
Where do the attack paths come from?
MITRE ATT&CK, loaded from the published STIX bundles. A path is a sequence of vectors correlated against your architecture and findings. Paths whose techniques a named group or documented campaign has actually used are marked, so a plausible path and an observed one are never the same claim.
What does it need to run?
The Vulnetix CLI in your pipeline. The graph is assembled from independent single-repository scans, so there is nothing central to install and no inventory to seed. Adding a repository to the estate means scanning it.
See how findings are ranked in Risk Prioritization, or how the scans that feed both are run in Code Scanner.