Pre-build parent and children maps at the start of traversal for O(1)
lookups instead of O(n) array searches per traversal step. This improves
performance for large attack path graphs.
When a principal can assume a role (effective_principal), the virtual
relationship was being created from effective_principal but the graph
showed the original principal, causing disconnected nodes.
Now the virtual relationship is created from the original principal,
keeping the graph fully connected while still detecting escalation
paths that require role assumption.
Removed the extra path_target re-match that was causing role nodes to appear
disconnected in the visualization. The target_role is now only connected via
virtual relationships (PASSES_ROLE → target_role → GRANTS_ACCESS), which
provides a cleaner and more accurate attack path visualization.
Updated PassRole queries to display which specific role(s) can be passed
in the visualization, instead of just showing a count. The path now shows:
Principal → New Resource → Target Role → Privilege Escalation
This allows users to see exactly which admin roles a principal can pass
to escalate privileges, which is crucial for security analysis.
Queries updated: Lambda, ECS, Glue, Bedrock, CloudFormation
Virtual nodes were being created for each result row, causing duplicates
in the graph visualization. Fixed by using aggregation pattern:
1. Deduplicate principals FIRST (before matching target roles)
2. Collect target roles per principal
3. Create ONE virtual node per principal with role count
Queries fixed:
- aws-iam-privesc-passrole-lambda
- aws-glue-privesc-passrole-dev-endpoint
- aws-bedrock-privesc-passrole-code-interpreter
- aws-cloudformation-privesc-passrole-create-stack
The virtual node description now shows "N admin role(s) can be passed"
instead of creating N separate nodes.
Apply the same patterns from PR #9770 to the other privilege escalation
queries that were missing the improvements:
- aws-iam-privesc-create-policy-version
- aws-iam-privesc-attach-role-policy-assume-role
- aws-iam-privesc-passrole-lambda
- aws-iam-privesc-role-chain
Changes applied:
- Add DISTINCT deduplication before creating virtual relationships
- Add re-match paths at the end for proper visualization
- Remove redundant path variables from RETURN statements
- Create unique virtual node IDs per principal->target pair
- Change opacity-based hiding to display:none for finding nodes
- Use visibility:hidden for finding edges in full view
- Add isFilteredView to useEffect dependency array
- In filtered view, all nodes/edges remain visible as expected
When in filtered view, findings are part of the selected path and
should be fully visible, not hidden with reduced opacity.
- Add isFilteredView prop to AttackPathGraph component
- Skip hiding findings when isFilteredView is true
Reverts the visibility-based approach to use data-changing approach
which redraws the graph with only the selected path nodes, optimizing
the layout for the filtered view.
- Store fullData separately when entering filtered view
- Compute filtered subgraph with only visible nodes and edges
- Graph redraws with new data, auto-fitting to show selected path
- Restore fullData when exiting filtered view
Replace data-replacement approach with visibleNodeIds Set to fix
animation issues caused by Next.js server component re-renders.
- Changed useGraphState to compute visibleNodeIds without modifying data
- Graph component now animates opacity changes via D3 transitions
- Keeps DOM structure stable while providing smooth visual transitions
- Findings now properly appear when filtering by a resource node
- Add orange glow filter and pulsing animation for selected/filtered nodes
- Pass isFilteredView prop to graph component to show findings when filtering
- Update node styling to show thicker border (4px) and orange glow on selection
- Ensure findings are visible in filtered view instead of being hidden by default
When clicking a node in the attack path graph:
- Filters the graph to show only upstream (ancestors) and downstream (descendants) paths
- Includes findings directly connected to the selected node
- Shows a "Back to Full View" button to restore the complete graph
- Displays an indicator showing which node is being filtered
Uses atomic Zustand state updates to ensure proper re-rendering of the D3 graph.
Merge all individual resource type items (AWS Account, EC2 Instance,
S3 Bucket, etc.) into a single "Resource" entry to reduce visual
clutter in the graph legend.
Instead of creating one virtual ECS task node per target role, merge all
target roles into a single node per principal. The node description shows
how many admin roles can be passed (e.g., '3 admin role(s) can be passed').
This reduces visual clutter when a principal can pass multiple admin roles.
The virtual nodes represent potential resources that could be created
for privilege escalation, not actual malicious resources. Renamed for
clarity:
- Malicious Task Definition -> New Task Definition
- Malicious Dev Endpoint -> New Dev Endpoint
- Malicious Code Interpreter -> New Code Interpreter
- Malicious Stack -> New Stack
Changed upstream traversal to follow only one parent at each level
instead of all parents. This prevents the entire graph from lighting
up when selecting a node that has multiple ancestors with many children.
- Upstream: now uses find() to get first parent only
- Downstream: unchanged, still highlights all descendants
- Change edge color from orange to white by default
- Highlight entire path in orange on node hover/selection
- Add Ctrl + scroll to zoom functionality with increased speed
- Update node borders to orange on hover/selection
- Add zoom hint to legend
- Remove hover effect from info button
- Added support to Neo4j
- Added Cartography as Attack Paths Scan
- Added Attack Path Scans endpoints for their management and run queries on those scan