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

  1. CreateAttackGraphSnapshot created with status=PENDING, linked to RiskSnapshot (FK).
  2. Buildbuild_graph_snapshot(tenant_id, risk_snapshot_id) via Celery task:
    - Loads RiskSnapshotItem to scope entities to risk-relevant assets
    - Extracts nodes from all canonical entity types
    - Extracts edges from FK relationships, intel edges, IOC correlations, incident assets
    - Sets node_count, edge_count, max_path_length, build_duration, content_hash
    - Status → COMPLETED or FAILED with error_message
  3. 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)

Related Articles