SentriScope Attack Graph Architecture
Snapshot-based attack graph materialization, edge taxonomy, path queries, entity correlation, and performance guardrails.
0. Position in the platform
Attack Graph is not the product boundary. It is the graph materialization and traversal engine beneath Attack Path Intelligence.
| Concern | Owner document / app |
|---|---|
| Operator investigation questions | ARCHITECTURE_ATTACK_PATH_INTELLIGENCE.md |
| Snapshot build, nodes, edges, BFS | This document / apps/attack_graph |
| REST intelligence DTOs (planned) | API_ATTACK_PATH_INTELLIGENCE.md / apps/attack_path_intelligence |
| Investigation UI | DESIGN_ATTACK_PATH_INVESTIGATION_UI.md |
Consumers (dashboard, entity pages, LLM, SOAR) should call Attack Path Intelligence APIs, not raw graph endpoints, except for advanced graph explorer and diagnostics.
1. Overview
The Attack Graph layer provides a snapshot-based, tenant-scoped graph of security entities and their relationships for deterministic path traversal and remediation simulation.
Three-layer model (within graph scope):
| Layer | Component | Role |
|---|---|---|
| Truth | Canonical models + edge tables | Authoritative source of entities and relationships |
| Build | apps/attack_graph |
Materializes AttackGraphSnapshot from canonical data |
| Serve | /api/v1/attack-graph/* |
Low-level query and slice APIs for intelligence facade |
The attack graph reuses existing canonical entities and correlation logic. It does not modify canonical models.
Known operational gap (June 2026): build_attack_graph_snapshot_task is not yet triggered automatically after RiskSnapshot completion. See ROADMAP_ATTACK_PATH_INTELLIGENCE.md Phase P0.4.
2. Graph Node Model
| Field | Type | Description |
|---|---|---|
id |
UUID | Primary key (tenant-aware) |
tenant_id |
FK | Tenant (required) |
snapshot_id |
FK | AttackGraphSnapshot this node belongs to |
node_type |
string | asset, identity, application, vulnerability, exposure, credential_leak, ioc, threat_actor, campaign, malware, incident |
canonical_id |
UUID | Stable ID of the source canonical entity |
canonical_model |
string | Source model (e.g. canonical.CanonicalAsset) |
display_name |
string | Human-readable label |
attributes_json |
JSON | Denormalized attributes for display/query |
risk_score |
float | Optional 0–100 risk score |
created_at |
datetime | Set on create |
Indexes: (tenant, snapshot, node_type), (tenant, snapshot, canonical_id)
Uniqueness: (snapshot, node_type, canonical_id)
3. Edge Taxonomy
All edges are directed. Edge classes determine traversal behavior:
| Edge Class | Description | Traversable for Paths | Default Confidence |
|---|---|---|---|
STRUCTURAL |
Direct FK relationship (asset→exposure) | Yes | 100 |
ATTACK_STEP |
Inferred attack path relationship | Yes (confidence ≥ 70) | Varies |
SIGNAL |
Intelligence correlation | No | Varies |
3.1 Edge Types
| Edge Type | Source → Target | Canonical Source |
|---|---|---|
asset_exposed_by |
asset → exposure | CanonicalExposure.asset_id |
exposure_has_vulnerability |
exposure → vulnerability | CanonicalExposure.vulnerability_id |
identity_has_exposure |
identity → exposure | CanonicalExposure.identity_id |
credential_leak_has_exposure |
credential_leak → exposure | CanonicalExposure.credential_leak_id |
identity_credentials_leaked |
identity → credential_leak | CanonicalCredentialLeak.identity_link_id |
credential_targets_asset |
credential_leak → asset | CanonicalIntelEdge (CREDENTIAL_EXPOSES_ASSET) |
credential_exposes_identity |
credential_leak → identity | CanonicalIntelEdge (CREDENTIAL_EXPOSES_IDENTITY) |
asset_connected_to_asset |
asset → asset | CanonicalExposureEdge |
ioc_associated_actor |
ioc → threat_actor | CanonicalIOCThreatActor |
ioc_associated_campaign |
ioc → campaign | CanonicalIOCCampaign |
ioc_observed_in_incident |
ioc → incident | IOCContextCorrelation, CanonicalIntelEdge |
incident_impacts_asset |
incident → asset | CanonicalIncident.asset_id, CanonicalIncidentAsset |
4. Snapshot Lifecycle
- Create —
AttackGraphSnapshotcreated withstatus=PENDING, linked toRiskSnapshot(FK). - Build —
build_graph_snapshot(tenant_id, risk_snapshot_id)via Celery task:
- LoadsRiskSnapshotItemto scope entities to risk-relevant assets
- Extracts nodes from all canonical entity types
- Extracts edges from FK relationships, intel edges, IOC correlations, incident assets
- Setsnode_count,edge_count,max_path_length,build_duration,content_hash
- Status →COMPLETEDorFAILEDwitherror_message - Immutable — Snapshot content is never updated in place; new build creates new snapshot.
5. Query Patterns
Path Queries
| Query | Description | Constraints |
|---|---|---|
find_attack_paths(snapshot_id, source_asset_id, max_depth) |
BFS from source asset | MAX_PATH_DEPTH=8, MAX_RETURNED_PATHS=50 |
find_identity_to_asset_paths(snapshot_id, identity_id) |
Paths from identity to assets | Subset of find_attack_paths |
find_high_risk_paths(snapshot_id, risk_threshold) |
Paths with node risk_score ≥ threshold | Traverses ATTACK_STEP edges only |
find_exposed_assets(snapshot_id) |
Assets with at least one asset_exposed_by edge |
Summary nodes only |
All queries are tenant- and snapshot-scoped. No cross-tenant access.
Query Guardrails
| Parameter | Value |
|---|---|
MAX_PATH_DEPTH |
8 |
MAX_GRAPH_EXPANSIONS |
200,000 |
MAX_RETURNED_PATHS |
50 |
DEFAULT_MIN_CONFIDENCE |
70 |
| Error on limit exceeded | GraphTraversalLimitExceeded (HTTP 400) |
6. API
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/attack-graph/snapshots/ |
List attack graph snapshots |
| GET | /api/v1/attack-graph/snapshots/<id>/ |
Snapshot detail |
| GET | /api/v1/attack-graph/snapshots/<id>/graph/ |
All nodes and edges (JSON) |
| GET | /api/v1/attack-graph/snapshots/<id>/slice/?type=exposed-assets\|crown-jewels\|identity-risk |
Bounded subgraph (max 1000 nodes, 3000 edges) |
| POST | /api/v1/attack-graph/query/path |
Attack path query |
| POST | /api/v1/attack-graph/query/identity-path |
Identity → asset paths |
| POST | /api/v1/attack-graph/query/exposed-assets |
Assets with exposures |
| POST | /api/v1/attack-graph/query/high-risk-paths |
High-risk paths |
Low-level graph APIs. Operator UI should consume Attack Path Intelligence endpoints (planned) with contextual graph expansion — see DESIGN_ATTACK_PATH_INVESTIGATION_UI.md.
Legacy UI: /attack-graph/ (full/slice visualization). Relabeled as Advanced graph explorer in navigation; not the primary investigation entry point.
7. Entity Correlation Engine
The correlation engine resolves the same physical entity ingested from multiple source systems:
7.1 Asset Correlation Rules
An asset from system A is correlated with an asset from system B when:
1. Exact match: Same fqdn or same ip_address (non-ambiguous)
2. Fuzzy match: Same hostname + same mac_address
3. External ID cross-reference: Explicit cross-reference in canonical model
7.2 Merge Governance
| Rule | Enforcement |
|---|---|
| Single canonical_id per entity | After merge, all records share the same canonical_id |
| Source provenance preserved | source_system and external_id retained per source record |
| No destructive merge | Original source records are not deleted |
| Merge audit | Merge events are audit-logged |
8. Performance Strategy
| Concern | Strategy |
|---|---|
| Build scope | Bounded by RiskSnapshotItem set; GRAPH_SNAPSHOT_SCOPE_ONLY=True restricts edge loading to scoped entities |
| Path queries | In-memory BFS over preloaded edges; only ATTACK_STEP edges with confidence ≥ 70 |
| UI default | Slice API (exposed-assets); returns at most 1000 nodes, 3000 edges |
| Index coverage | tenant_id, snapshot_id, node_type, edge_type, source_node_id, target_node_id |
Performance Targets (Simulated: 70k assets, 110k identities, 2M edges)
| Metric | Target |
|---|---|
| Graph build time | < 120 seconds |
| Path query latency | < 1 second |
| Slice generation latency | < 500 ms |
9. Code Locations
| Path | Purpose |
|---|---|
apps/attack_graph/models.py |
AttackGraphSnapshot, AttackGraphNode, AttackGraphEdge |
apps/attack_graph/services/graph_builder.py |
build_graph_snapshot, node/edge extraction |
apps/attack_graph/services/graph_query_service.py |
Path finding queries |
apps/attack_graph/services/graph_slice_service.py |
Subgraph slice generation |
apps/attack_graph/services/confidence_policy.py |
Edge confidence calculation |
apps/attack_graph/tasks.py |
build_attack_graph_snapshot_task (Celery) |
apps/attack_graph/api/views.py |
API endpoints |
apps/attack_graph/templates/attack_graph/attack_graph.html |
Visualization (Cytoscape.js) |