CTI graph.
Relationships materialised as edges, so a pivot from one indicator to everything it touches is a traversal rather than a five-table join.
Why a graph at all
The interesting questions in threat intel are relational. Not “is this IP bad” but “what else does the actor behind this IP touch, and do we have any of it?” Answering that from normalised entity tables means an unbounded join; answering it from edges is a walk.
The tables
graph_nodes— one row per entity participating in a relationship, typed by entity kind.graph_edges— directed, typed relationships, each carrying its own confidence.graph_communities— precomputed clusters, for “what moves together”.
It is a graph in Postgres — no separate graph database in the running system. The same rows that answer a lookup answer a traversal, so a relationship you can see in an API response is a relationship the graph already holds.
Traversal
Exposed as POST /v1/graph/traverse. You give a starting entity and a depth; you get back the reachable subgraph with the edge types that connected it.
POST /v1/graph/traverse
{
"start": { "type": "indicator", "value": "192.168.0.123" },
"depth": 2
}
→ nodes: the indicator, 4 actors, 2 campaigns
edges: attributed-to, communicates-with, indicates
each edge carries its own confidenceDepth is bounded deliberately. An unbounded walk on a dense graph returns most of the graph, which is not an answer.
How edges get created
During enrichment. When a record is linked, the relationships the upstream asserted become edges — attribution from OTX pulses, malware association from MalwareBazaar, technique mapping from MITRE.
An edge is a claim like any other. “This IP is attributed to this actor” can be strongly or weakly supported, and the traversal reports which — so a two-hop pivot through a weak edge is visibly weaker than one through a corroborated edge.
Consumed by SARA
The graph is not only for OmniIntel's own surfaces. It is wrapped as a contract that SARA consumes, alongside the KB chunk push . So the same curated relationships answer questions asked from outside this product.