Security Graph Model¶
Use this page when the question is not "how do I open the graph?" but "what is this graph actually storing, how should I read it, and what stays true when the snapshot gets large?"
agent-bom persists the graph as a snapshot-oriented control-plane view:
- nodes are canonical entities such as agents, MCP servers, tools, packages, credentials, containers, cloud resources, vulnerabilities, and misconfigurations
- edges are typed relationships such as
uses,depends_on,exposes_cred,affects,invoked, andlateral_path - attack paths are precomputed fix-first paths derived from the persisted graph, with an explicit reachability verdict and evidence basis
- interaction risks are analysis results over recorded configuration and runtime evidence; their presence alone does not establish observed activity
This is not a best-effort browser-only canvas. It is a persisted graph snapshot loaded from the control plane.
Data locations, access and evidence sources¶
Graph and inventory requests without a scan ID use the current tenant estate.
If a selected job has no persisted graph, these reads return available evidence,
retain available prior evidence for that target, and report partial
collection_coverage with graph_evidence_unavailable. A later authoritative
scan with a valid empty graph still retires that target's earlier inventory.
An empty estate is a successful empty result with unknown assessment coverage.
Storage read failures remain errors. Explicit scan IDs retain historical scope.
Open a completed scan in Investigation, select a recorded data store or dataset, then inspect its relationships and source evidence. The artifact is the persisted graph snapshot; use the recorded resource identity to investigate permissions or runtime receipts next.
| Question | Graph evidence | Interpretation |
|---|---|---|
| Where does data live? | data_store, dataset, and stores relationships |
Recorded or derived storage structure; account, region and environment are available only when supplied by the source. |
| Who has access? | Identity and permission relationships, including has_permission |
Read the permission evidence and conditions; a structural path alone does not establish authorization. |
| Who accessed it? | Runtime accessed relationships and associated receipts |
Inspect the recorded operation, outcome and time. A denied attempt is not a successful read. |
| How did this evidence arrive? | Node data_sources, relationship evidence and snapshot context |
Collection provenance, such as scan, connector or imported evidence; not the location of the underlying business data. |
Cloud enrichment can derive a companion data-store node from resource metadata for buckets, databases, lakes and warehouses. That classification is not a content scan, complete lineage map or proof of sensitive records. Ingesting inventory or a scan report does not by itself ingest the contents of those stores. Source coverage and missing location or access evidence must be evaluated separately.
Explore an estate map¶
Open Investigation for a completed scan and switch to the broad graph view. Large displayed graphs use the bounded estate map; smaller investigations retain the detailed relationship canvas.
- Expand Map controls and group displayed assets by Environment to use their recorded provider, account/project and environment. Missing metadata stays unknown; an evidence source name is not treated as an environment.
- Find a displayed asset by name or ID, or select it on the map. Its connected assets remain highlighted while unrelated assets fade. Counts cover the displayed graph and may exclude assets outside its draw budget or filters.
- Use the shared details panel to inspect Location and evidence source and directional relationships, then expand the investigation to load related evidence. Use graph search or Summary to investigate beyond the displayed subset.
Environment groups arrange existing assets without creating graph relationships. A highlighted connection preserves the recorded relationship; it does not establish permission, successful access or exploitation. The map reports displayed node and edge counts and retains a text alternative for the rendered overview.
Reachability truth¶
Every path distinguishes executable evidence from investigation context:
confirmed— complete, directed, provenance-backed hop receipts support the recorded path; this is not proof of successful execution or exploitationlikely— package/dependency or observed graph evidence supports the pathunknown— structural topology connects the entities, but executable reach has not been proven; these candidates stay below evidence-backed pathsunlikely— graph or symbol evidence disproves reachability; the finding is retained as evidence but is not emitted as an exploit chain
Credential and tool exposure increase impact, not reachability. MITRE ATT&CK and ATLAS enrich evidence-backed hops; their technique mappings never create a hop or promote a structural candidate into an executable path.
Reading Context Map evidence¶
Open Context for a completed scan, then select a relationship label to inspect its source, target, and affected package. Repository and SBOM imports remain static inventory in Repository/Lineage; they are not MCP agent configurations. These links describe scan evidence:
- Configured server records an agent configuration, not an invocation.
- Advertises tool records a tool declaration, not successful execution.
- Credential reference records a configured name, not secret disclosure or use.
- Package vulnerability associates the finding with evidenced package owners, not every tool exposed by the server. Multiple package associations remain separate.
A connected path is an investigation lead. To establish what an agent touched, inspect runtime receipts with matching agent/tool identities and recorded resources, decisions, and outcomes. A blocked attempt is not successful access; missing resource or outcome evidence remains unknown. Finding badges show related runtime activity, not proof that vulnerable code executed. Existing snapshots need a new scan to reflect corrected ownership correlations.
What a snapshot means¶
Each graph snapshot is identified by:
scan_idtenant_idcreated_at
The snapshot captures:
- the nodes present at that scan/control-plane save point
- the edges between those nodes
- the derived attack paths and interaction risks for that saved graph
- aggregate counts used for graph headers, graph search, and UI summaries
The important operator rule is:
- pagination changes the visible canvas
- pagination does not change what the snapshot is
So when the graph page says showing 1-500 of 3,200 nodes, it is telling you
how much of the persisted graph is on the current page, not that the rest of
the graph disappeared.
IDs, timestamps, and evidence¶
The graph uses stable identifiers wherever possible:
- agents use canonical agent IDs
- MCP servers use canonical server
stable_id - tools, resources, and packages use their own stable IDs
- graph nodes expose a
node_idthat the API and UI can round-trip
That means operators can talk about:
- one node across filters
- one snapshot across pages
- one server across repo scan, fleet sync, gateway discovery, and runtime
Time fields have specific meaning:
created_aton the snapshot = when the graph snapshot was persistedfirst_seenon a node = earliest observed timestamp for that entity in the current correlated modellast_seenon a node = latest observed timestamp for that entity in the current correlated model
Those are different concepts. A snapshot is a saved graph view; first_seen and
last_seen are entity lifecycle signals inside that view.
Credential environment-variable slots belong to the recorded MCP server
occurrence. Repeated observations of that server and slot can join; the same
variable name on differently scoped servers cannot establish shared credentials
or identity bindings. Older raw snapshots can recover this boundary from their
recorded parent server. Missing or conflicting slot ownership stays
snapshot-scoped. Previously correlated snapshots using identity versions before
scoped-identity.v4 require recomputation from source snapshots; correlating the
old output again does not repair its joins. Slot references do not expose secret
values or prove that a credential was successfully used.
What the graph is for¶
The graph is not meant to be a generic everything-map. It exists for three operator jobs:
- blast radius Follow package or configuration risk into agents, credentials, tools, and reachable runtime surfaces.
- inventory correlation Show how repo, fleet, gateway, and runtime evidence point at the same MCP server or agent surface.
- fix-first triage Let operators collapse many exposed paths with one change instead of chasing every finding separately.
For the product and review rubric behind these jobs, see
docs/graph/SECURITY_GRAPH_UX_RUBRIC.md.
Reading the graph in the UI¶
The UI exposes three layers of interpretation:
- snapshot metadata
- scan ID
- captured time
- total nodes and edges
- current page window
- topology filters
- focused vs expanded view
- relationship scope
- runtime/static scope
- agent filters
- severity filters
- node detail
- node ID
- first seen / last seen
- incoming / outgoing edges
- sources and impact counts
That split is intentional:
- the header tells you what snapshot you are looking at
- the filters tell you how you are slicing it
- the detail panel tells you why one node matters
Inspecting one instance or path¶
Open Investigation → Summary, drill into an account or environment, then choose Inspect on a package. Matching package names can represent different instances: the row includes available image/workload context, and Node ID reveals the canonical identifier used by the API. Missing context stays absent.
In Attack Paths → List, expand any hop to load up to 12 direct neighbors. Outgoing and incoming groups retain the relationship labels; an access edge is not automatically a dependency. Use Traverse from this hop for a focused investigation, or Retry neighbor lookup after a failed request. A partial response does not establish that a node has no other neighbors.
The queue distinguishes paths shown, unique paths loaded from both the occurrence queue and priority cards, and the snapshot total. Evidence priority identifies a priority-card score; Queue score identifies an occurrence-queue score. Neither score establishes compromise.
New demo projections direct dependencies from a workload to its image and from an image to its packages. This change does not rewrite existing saved snapshots; rebuild the demo snapshot to see corrected projection semantics.
Paging recorded relationships through the API¶
For a persisted canonical node, authenticated clients can request one bounded relationship page without loading the whole neighborhood:
curl --get "$AGENT_BOM_API_URL/v1/graph/incident-edges" \
--header "Authorization: Bearer $AGENT_BOM_API_KEY" \
--data-urlencode "node_id=$NODE_ID" --data-urlencode "limit=24"
The response contains the seed, endpoint nodes, recorded edges, and next_cursor.
Reuse the returned scan_id and snapshot_generation on every node expansion.
Follow next_cursor with those values and the same node and direction; the
generation check prevents mixing graph data across a replaced snapshot.
limit counts relationships (1–100), so parallel edges can share a neighbor.
in and out filter recorded endpoints; they do not establish permission or
execution. Completeness covers the current recorded page, and totals stay unknown.
On a stale-cursor or generation-mismatch 400, discard the accumulated view and
restart from the first page; unsupported backends return 501.
Context uses these pages for progressive persisted-neighborhood exploration.
Scale and readability¶
To keep the graph readable at larger sizes, agent-bom uses:
- persisted snapshots rather than only transient browser layouts
- paginated node windows
- precomputed attack paths for shortlist triage
- focused vs expanded topology modes
- relationship-scope filters
- node detail enrichment on demand
- an independent persisted-path fast lane, so full-estate fix guidance cannot delay the first ranked path
- semantic role chains in the queue (
agent → server → package → finding) and bounded one-hop traversal for direct dependencies and dependents
The operator workflow should be:
- start with the focused graph or attack-path shortlist
- narrow by agent, severity, or relationship scope
- expand a hop for bounded direct neighbors, or traverse from it into lineage
- open node detail for IDs, timestamps, and impact
- page or expand only when the current slice is too narrow
Relationship categories¶
At a high level the graph separates:
- inventory relationships
- hosts
- uses
- depends_on
- provides_tool
- exposes_cred
- attack relationships
- affects
- vulnerable_to
- exploitable_via
- remediates
- lateral_path
- runtime relationships
- invoked
- accessed
- delegated_to
- governance relationships
- manages
- owns
- part_of
- member_of
This is why the graph page has relationship-scope filters. The same snapshot can be read as inventory, attack path, runtime context, or governance context without pretending those are all the same edge type.
What the graph is not¶
The graph is not:
- a replacement for the raw scan JSON
- a guarantee that every runtime event is persisted forever
- a substitute for the proxy or gateway itself
- a live network map of traffic that never entered the control plane
It is the persisted operator model that unifies inventory, findings, runtime evidence, and remediation.
Investigate an agent from Context¶
Context defaults to Persisted snapshot. Choose a completed scan, then search or page the agent selector. The scan status response supplies the graph snapshot ID without downloading the full report. Selection uses the server's canonical node ID, so identically named agents from different sources remain distinct.
The initial view requests one page of up to 24 recorded relationships. Select a node and choose Expand connections for its first page, or Load more relationships for its continuation. Collapse connections removes the selected node's loaded pages and expansions that depend solely on them. Independent branches, shared descendants and later root pages stay loaded. Focus here shows the selected node and its immediate recorded neighbors. Back to neighborhood restores the loaded overview without fetching again or discarding earlier expansions. Browsing scan pages preserves the current selection; choosing a different scan replaces it. Switching graph lenses retains the selected snapshot. Restart neighborhood clears the workspace and reloads the selected agent. Direction filters recorded incoming/outgoing endpoints, not effective permissions.
The canvas initially shows at most eight nodes and 12 relationships. Expand canvas raises that limit to 24 nodes and 36 relationships; Compact canvas restores the smaller view. The loaded workspace has a budget of 240 relationships or 10 pages. The Loaded entities section makes cached nodes searchable by name or exact ID and grouped by entity type, without fitting the whole graph on screen. Select a node or edge to inspect recorded relationships; the overview keeps relationship labels in the inspector to avoid covering nearby cards. Fit all frames the nodes currently on the canvas; large layouts may use smaller labels. Readable view centers the selected entity at readable zoom. Neither control fetches additional evidence or raises the canvas limits. Counts cover loaded evidence only; unqueried relationships and collection coverage remain unknown. A new snapshot generation clears the workspace and requires a restart. There is no automatic multi-hop collection or full-graph download in this mode. These bounds do not establish an end-to-end enterprise performance guarantee.
Scan-derived (unpersisted) explicitly opens the older scan projection when needed. It loads a bounded scan snapshot before filtering locally and does not fetch additional evidence when expanding. Authentication or network failures do not silently switch to this mode.
Shared infrastructure is not evidence that agents communicated. Inspect a relationship for its recorded direction and evidence; permissions, exploitation, and execution must have their own supporting evidence.
Select an agent and scan in Context, then choose Investigate reach & permissions. The investigation retains that scope and presents recorded paths. Select a path, then use its investigation questions:
- Reach & connections opens ordered permission receipts and bounded incoming/ outgoing neighbor expansion. Other agents, tools and resources appear only when the selected snapshot records their relationships.
- Assume compromise adds an explicit analyst assumption. It inspects existing receipts from the agent onward; it does not execute calls or simulate a successful attack. Denial and blocking evidence remain visible.
- CVE conditions shows recorded advisory prerequisites separately from the local exploitability assessment. Missing prerequisites remain unrecorded.
- Potential impact identifies recorded resource context and evidence gaps; an impact category is not proof of an actual consequence.
- Recorded activity preserves exact agent identity in the trace explorer. The explorer retrieves a bounded sample per source; its records are not correlated to a scan merely because navigation carries that scan ID.
Runtime hop receipts expose recorded opaque event/trace references when present on the matching runtime edge. Missing or placeholder references stay absent. These references do not create an end-to-end trace lookup or prove exploitation.