How OpenSourceOM stores the security graph
The graph is the inventory plus the relationships that make a finding matter. A public bucket and an admin role are separate facts. An edge between them is the question security teams actually ask. What a security graph is, as a category, is in What a cloud security graph is. This page is how Core stores one.
Storage is PostgreSQL: a nodes table and an edges table, with
provider-specific attributes in JSONB. There is no open query language. You run
named path queries, blast radius,
and CSPM rules that the engine already knows how to evaluate.
What a scan writes
Each collector emits a batch of nodes and edges and upserts it. Node ids are stable and
provider-scoped, so a later scan updates the same row. Edge ids are
source|target|type. See Schema for the closed set of
types.
- Internet — one synthetic node,
internet:global, used as the start of external reachability. - Workload — EC2, GCE, Azure VM, or Kubernetes pod.
- Network — security group, namespace, or Service.
- Identity — IAM role or user, service account, or Azure principal.
- Datastore — S3, GCS, or Azure Storage.
- Finding — written by rules and CVE enrichment, linked with
VIOLATES.
Edges that queries walk
| Edge | Meaning in Core |
|---|---|
REACHABLE | Internet can reach a workload. AWS requires a public IPv4 address and an open security group. Azure and GCP use a public or NAT IP and do not read firewalls. Kubernetes uses a LoadBalancer or NodePort that selects the pod. |
ASSUMES | An identity is in use. On AWS, Azure, and GCP the workload is the source and the role or service account is the target. On Kubernetes the service account is the source and the pod is the target. |
CAN_ACCESS | An identity can reach a datastore. AWS derives this from instance-profile allow statements. Azure derives it from role-assignment scope. GCP derives it from project and bucket IAM. |
AFFECTS | A workload is attached to a network control (security group or namespace). |
VIOLATES | A finding applies to a resource. The finding is the source. |
How a path becomes a priority
internet-to-datastore walks outward from internet:global and keeps
paths that end on a datastore and pass through at least one workload. CSPM rules then ask
three yes/no questions about a matched resource: is it reachable from the internet, does it
sit on an internet-to-datastore path, and can an admin identity access it? Those answers add
points to the rule’s base score. The arithmetic is on
Prioritization.
Limits you should plan for
- Path walks are recursive SQL with a depth cap and a row limit. They are built for a pilot graph, not an unbounded enterprise crawl. Named queries follow every edge type, so a
VIOLATESedge can extend a path if it points onward from the current node. - AWS
CAN_ACCESSevaluates allow statements on the instance profile’s role and does not evaluate denies or conditions. Azure evaluates role-assignment scope andNotActionson the same permission entry, and skips conditional assignments. GCP evaluates project and bucket IAM and skips conditional bindings. - GCP
public_accessmeans the bucket IAM policy grantsallUsersorallAuthenticatedUsersan object-read role. Azurepublic_accessmeans blob public access is allowed and a container is set to blob or container access. - Pack rules and the public-datastore check list at most 500 nodes of the target type, ordered by name. A larger account is only partly evaluated.
- Findings are nodes in the same database. Deleting a resource cascades its edges, including
VIOLATES.
Where to go next
- Schema — ids and property bags
- Attack paths — each named query
- Collectors — which APIs produce which edges
Questions
How does OpenSourceOM store the security graph?
In PostgreSQL, in a nodes table and an edges table. Provider attributes sit in JSONB. There is no separate graph database and no ad-hoc query language.
How do I query the OpenSourceOM graph?
Run one of six named queries, such as om paths run internet-to-datastore, or open the same query in the web console. internet-to-sensitive-datastore keeps paths that end on a datastore whose sensitivity property is set. Blast radius is a separate command.
Related reading
Copyright © 2026 OpenSourceOM. Licensed under Apache-2.0.