Live demo · Attack-path triage

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

  1. 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.

  2. 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.

Alert queue · Kestrel Pay
Raise your own alert
ALR-1041 · EDR · Suspicious process
Crypto-miner process on checkout-web-01
Asset: checkout-web-01 (VM)
prioritizerisk 0.64
reaches :8080runs asreadsexposes :443routes to :443InternetInternetINTERNETcheckout-public-lbcheckout-public-lbLOAD BALANCERcheckout-web-01checkout-web-01VMledger-svcledger-svcCONTAINERcheckout-sessions (Redis)checkout-sessions…DATA STOREcheckout-web-instancecheckout-web-inst…ROLEledger-serviceledger-serviceROLEcheckout-redis-passwordcheckout-redis-pa…SECRETledger-db-credentialsledger-db-credent…SECRETpayments-ledger (Postgres)payments-ledger (…CROWN JEWEL
━ attack path to nearest crown jewel┅ route in from the internet◆ crown jewel
Evidence: shortest attack path
checkout-web-01reaches (8080) →ledger-svcruns as →ledger-servicereads (rds-db:connect) →payments-ledger (Postgres)
How the internet reaches it
Internetexposes (443) →checkout-public-lbroutes to (443) →checkout-web-01
Graph features (Cypher, in a Python resolver)
Hops to nearest crown jewel3
Crown jewels reachable1
Distinct paths (≤ 6 hops)2
Blast radius (assets reachable)7
Secrets reachable2
Privileged roles reachable0
Internet exposure2 hops in
Risk score (Chalk expressions)
Close to a crown jewel+0.44
Reachable from the internet+0.15
Credential already leaked+0.00
Privileged role in reach+0.00
Detection severity+0.05
Several routes in+0.00
Risk score0.64
monitor ≥ 0.3 · prioritize ≥ 0.6
Recorded Chalk query · 2026-10-14 · query cmv8df2f100mr0iwv3qez2itx

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.

Deploy your own

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.

chalk-ai/attack-paths
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_score

Put 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.