Triage attack paths with Chalk graph resolvers
This demo shows how to run graph queries and risk-scoring expressions on Chalk to rank alerts by the assets they can reach. Select an alert to inspect its path and score, then explore the code to see how it works.
Same alert, different route to important data
Compare a paired detection on two assets to see why graph context changes the example’s priority.
Try this experiment · expected results
1Compare the miner alerts
Select the crypto-miner alert on checkout-web-01, then the one on ds-sandbox-17.
Expected: The detection is similar, but the route to sensitive assets and the resulting priority differ.
2Trace the reason
Read the highlighted path, then the graph features and risk-score contributions.
Expected: You can connect the verdict to reachable assets instead of relying on the alert’s severity alone.
Chalk follows connections from the alerted asset to sensitive data. Compare the two miner alerts: the same process can deserve a different priority when its reachable assets differ.
Kestrel Pay, its estate and its alerts are fictional. The graph is a real Neo4j database running as a Chalk scaling group, and every verdict above is a real Chalk online query against a branch that holds these feature definitions. Each alert also shows a recorded run of the same query instantly, while the live one runs. Of the eight alerts, 4 are prioritized by the example’s scoring rules. These verdicts illustrate that policy on the fictional estate; the demo takes no action on real infrastructure.
Built on Chalk
Chalk hosts the graph service and runs the resolver and scoring expressions in an online query. The example supplies the fictional estate, Cypher traversals and rules for prioritizing alerts.
Graph context from Python
A Chalk Python resolver calls Neo4j with Cypher and returns graph results as features. The query combines them with the example’s scoring expressions.
Host the graph service
Chalk runs the Neo4j container as a CPU ScalingGroup. The example configures Neo4j as read-only and its public route to require a Chalk token; resolvers use the cluster address.
Rules in the feature definitions
Chalk evaluates the example’s weights and thresholds as native feature expressions. The application defines the policy, and the query returns its score alongside the supporting features.
Return evidence with the score
A Chalk online query returns the triage result, graph features and attack-path data together. The application draws that path so the visitor can inspect the result.
Run it on your own
You will need uv, the Chalk CLI and a Chalk environment. Clone the example, log in, deploy Neo4j, set ATTACK_GRAPH_URL and apply the feature definitions to a branch. Query a catalog alert to inspect its score and path.
To adapt the example, load your asset inventory and relationships into the graph, then review the Cypher traversals and policy weights for your estate. The repository includes a Python reference and a recorded-query check for the fictional alert catalog.
git clone https://github.com/chalk-ai/attack-paths
cd attack-paths
# Neo4j with the fictional estate, read-only, reachable only inside your cluster.
./deploy_graph.py
chalk secret set ATTACK_GRAPH_URL=http://<graph service>:7474
# The alert features, the graph resolver and the scoring, on a branch.
chalk apply --branch attack-paths
chalk query --branch attack-paths --in security_alert.id=ALR-1041 \
--out security_alert.triage --out security_alert.risk_scorePut graph context behind your alerts
Graphs, identity, asset inventories and alert history: talk to an engineer about turning your security context into features your triage can act on.