diff --git a/v1/cybersecurity-attack-paths/README.md b/v1/cybersecurity-attack-paths/README.md
index f6c7427..a2bd814 100644
--- a/v1/cybersecurity-attack-paths/README.md
+++ b/v1/cybersecurity-attack-paths/README.md
@@ -53,7 +53,7 @@ This template enumerates multi-step attack paths across an enterprise asset grap
### Tools
- Python >= 3.10.
-- `relationalai` SDK >= 1.15 (path enumeration with multi-edge patterns is a preview capability) and the `rai` CLI, both installed by the Quickstart steps below.
+- `relationalai` SDK >= 1.21 (path enumeration with multi-edge patterns is a preview capability) and the `rai` CLI, both installed by the Quickstart steps below.
- OS notes: works on macOS, Linux, and Windows; the Quickstart's virtual-environment activation command assumes macOS or Linux.
## Quickstart
@@ -99,7 +99,7 @@ This template enumerates multi-step attack paths across an enterprise asset grap
```text
3 kill-chain attack path(s) reach a crown jewel (exploit -> cred -> 1-2 pivots, from an internet-facing asset):
- [3 hops] VPN Gateway --[exploit]--> Jump Host --[cred]--> File Server --[pivot]--> Customer Database
+ [3 hops] VPN Gateway --[Asset.exploit_to]--> Jump Host --[Asset.cred_to]--> File Server --[Asset.pivot_to]--> Customer Database
```
See the runbook for the full output.
@@ -142,7 +142,7 @@ CSV files --> Define Asset + technique edges --> Kill-chain enumeration (multi-e
The analysis starts by modeling each attacker technique as its own directed relationship between assets — `exploit_to`, `cred_to`, `pivot_to` — plus a technique-agnostic `can_reach` union edge that the point query uses.
-The centerpiece is a multi-edge path pattern (which needs `relationalai>=1.15`) that composes the techniques in series: an exploit first, then credential reuse, then one or more lateral pivots, ending at an explicit destination. Filtering the source to an internet-facing asset and the destination to a crown jewel pins the threat model. Enforcing edge order is the whole point — a single union edge or a flat join cannot express "exploit first, then credentials, then pivots," which is exactly the kill-chain signature analysts care about, and each hop records the technique it used.
+The centerpiece is a multi-edge path pattern (which needs `relationalai>=1.21`) that composes the techniques in series: an exploit first, then credential reuse, then one or more lateral pivots, ending at an explicit destination. Filtering the source to an internet-facing asset and the destination to a crown jewel pins the threat model. Enforcing edge order is the whole point — a single union edge or a flat join cannot express "exploit first, then credentials, then pivots," which is exactly the kill-chain signature analysts care about, and each hop records the technique it used.
A separate point query pins both endpoints by id to enumerate every route between a chosen entry point and a chosen crown jewel over the union edge. The kill-chains are then ranked by the exposure summed along each one. Finally, the assets lying on any crown-jewel chain are flagged back onto the ontology as `Asset.on_attack_path`, so a later query can pull them without re-enumerating paths.
@@ -176,7 +176,7 @@ See `cybersecurity_attack_paths.py` for the implementation and `runbook.md` to r
Why do I see relationalai version or path import errors?
-- Path enumeration with multi-edge patterns requires `relationalai` 1.15 or newer. Confirm your installed version with `python -m pip show relationalai`.
+- Path enumeration with multi-edge patterns requires `relationalai` 1.21 or newer. Confirm your installed version with `python -m pip show relationalai`.
diff --git a/v1/cybersecurity-attack-paths/cybersecurity_attack_paths.py b/v1/cybersecurity-attack-paths/cybersecurity_attack_paths.py
index dabb8a2..793d307 100644
--- a/v1/cybersecurity-attack-paths/cybersecurity_attack_paths.py
+++ b/v1/cybersecurity-attack-paths/cybersecurity_attack_paths.py
@@ -2,7 +2,7 @@
Enumerates multi-step attack chains across an enterprise asset graph by composing
distinct attacker techniques in series -- a capability unlocked by multi-edge path
-patterns (relationalai>=1.15):
+patterns (relationalai>=1.21):
- Loads Asset nodes (hosts, services, accounts) and three DISTINCT directed edges
between them, one per technique: exploit_to (vulnerability exploitation),
@@ -109,7 +109,7 @@ def load_csv(filename):
# --------------------------------------------------
# Paths: kill-chain attack paths (multi-relationship sequence)
-# PREVIEW capability; requires relationalai>=1.15.
+# PREVIEW capability; requires relationalai>=1.21.
# --------------------------------------------------
# model.path(a.exploit_to, b.cred_to, c.pivot_to.repeat(1, MAX_PIVOTS), dst) is a
# MULTI-EDGE pattern: distinct relationships in series. It matches the kill-chain
@@ -157,16 +157,12 @@ def load_csv(filename):
hop_df = hop_df.drop_duplicates(["path_id", "hop"]).sort_values(["path_id", "hop"])
# Reassemble each kill-chain: ordered asset names + the technique used at each hop.
-def technique_label(raw):
- # relationship labels arrive as e.g. "-->"; strip to the verb stem.
- stem = raw.strip("-<>⟨⟩→ ")
- return stem[:-3] if stem.endswith("_to") else stem
-
+# The technique is the relationship label as-is -- the dotted relationship name,
+# e.g. "Asset.exploit_to".
chains = []
for pid, g in kill_df.groupby("path_id"):
assets = list(g.sort_values("step")["asset_name"])
- techs = [technique_label(t) for t in
- hop_df[hop_df["path_id"] == pid].sort_values("hop")["technique"]]
+ techs = list(hop_df[hop_df["path_id"] == pid].sort_values("hop")["technique"])
labelled = assets[0]
for nm, tech in zip(assets[1:], techs):
labelled += f" --[{tech}]--> {nm}"
@@ -183,7 +179,7 @@ def technique_label(raw):
# --------------------------------------------------
# Pin both endpoints by id and enumerate all simple routes between them over the
# technique-agnostic can_reach edge (any technique, 1..MAX_ROUTE_HOPS). This is the
-# >=1.15 native point query -- src/dst unified to specific assets inside all_paths().
+# >=1.15-era native point query (still current) -- src/dst unified to specific assets inside all_paths().
src_pt, dst_pt = Asset.ref(), Asset.ref()
route = model.path(src_pt.can_reach.repeat(1, MAX_ROUTE_HOPS), dst_pt).all_paths()
diff --git a/v1/cybersecurity-attack-paths/pyproject.toml b/v1/cybersecurity-attack-paths/pyproject.toml
index cf164c1..36a16b1 100644
--- a/v1/cybersecurity-attack-paths/pyproject.toml
+++ b/v1/cybersecurity-attack-paths/pyproject.toml
@@ -9,7 +9,7 @@ description = "RelationalAI template: enumerate multi-step cyber attack chains a
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
- "relationalai==1.15.0",
+ "relationalai==1.21.1",
"pandas>=2.0.0",
]
diff --git a/v1/cybersecurity-attack-paths/runbook.md b/v1/cybersecurity-attack-paths/runbook.md
index 10a75b5..8f37ea6 100644
--- a/v1/cybersecurity-attack-paths/runbook.md
+++ b/v1/cybersecurity-attack-paths/runbook.md
@@ -6,7 +6,7 @@ A security team wants to see how an external attacker could chain techniques to
Asset graph (12 assets, 16 technique-tagged steps: exploit / cred / pivot)
│
▼
-/rai-graph-analysis — Path enumeration (multi-edge, relationalai>=1.15)
+/rai-graph-analysis — Path enumeration (multi-edge, relationalai>=1.21)
• kill-chain signature: exploit (from an internet-facing asset),
then credential reuse, then 1-2 lateral pivots, into a crown jewel -> 3 chains
• point query: every route from Public Web Server to Customer Database
@@ -35,7 +35,7 @@ Each prompt is pasted into a fresh agent session loaded with the named `/rai-*`
**Prompt:** /rai-graph-analysis Which attack chains follow the full kill-chain signature — an exploit step starting from an internet-facing asset, then a credential-reuse step, then one or two lateral pivots — and end at a crown jewel (an asset flagged `crown_jewel`)? Show the technique used at each hop.
-**Response:** 3 kill-chains reach a crown jewel. VPN Gateway —exploit→ Jump Host —cred→ File Server —pivot→ Customer Database; Mail Relay —exploit→ Finance Workstation —cred→ Engineer Workstation —pivot→ Domain Controller; and a 4-hop chain Public Web Server —exploit→ Application Server —cred→ Jump Host —pivot→ Backup Server —pivot→ Customer Database. The technique order is enforced by the path pattern, so chains that move in a different order are correctly excluded.
+**Response:** 3 kill-chains reach a crown jewel. VPN Gateway —Asset.exploit_to→ Jump Host —Asset.cred_to→ File Server —Asset.pivot_to→ Customer Database; Mail Relay —Asset.exploit_to→ Finance Workstation —Asset.cred_to→ Engineer Workstation —Asset.pivot_to→ Domain Controller; and a 4-hop chain Public Web Server —Asset.exploit_to→ Application Server —Asset.cred_to→ Jump Host —Asset.pivot_to→ Backup Server —Asset.pivot_to→ Customer Database. The technique order is enforced by the path pattern, so chains that move in a different order are correctly excluded.
## 4. All routes between one entry and one crown jewel