Attack paths
What a toxic combination is, how a chain is evaluated and scored, why some are disabled, how to break one, and what the Sapper proposes.
This page explains what Ctadel calls a toxic combination, how a chain is evaluated and scored, what closes a path, and what the Sapper adds.
What a toxic combination is
A toxic combination is a rule about a path in the graph rather than about a single resource. Each link on its own may be harmless or medium: an instance with a public address, an IMDS version that hands out the role without a token, a role that reads a bucket, a bucket classified as holding personal data. Lined up, they form a path an attacker can follow from the Internet to a target.
The "Toxic Combinations" page lists these paths with their "Risk", their "Severity", their title and the resources crossed. Each path is a finding like any other: it has a status and a history, and it can be ignored or accepted.

Two mechanisms produce these paths.
| Mechanism | What it does | Rule keys |
|---|---|---|
| Catalogue chains | A known combination, described in advance: the resource types, relationships and findings expected at each link. | TOX-… |
| Computed paths | Ctadel picks out the entry points, weaknesses, identities and targets in the graph, then walks from every entry point towards every target with no pre-written rule. | PATH-DATA, PATH-ADMIN, PATH-KEY, PATH-CLUSTER, PATH-STORE |
How a catalogue chain is evaluated
A catalogue chain describes its links by concept ("public", "admin", "sensitive data"), each covered by real rules of the catalogue. At every scan, Ctadel evaluates each enabled chain against the graph. Each path found becomes a finding; the same path found again at the next scan is the same finding, not a duplicate.
A few catalogue chains ship disabled; the reason is in their description. They remain visible in the catalogue.
How a computed path is built
Ctadel first picks out in the graph the hosts and services reachable from the Internet (entry points), the weaknesses they carry (vulnerabilities, IMDSv1, secrets, container escape), the identities they yield, the access rights of those identities, and the targets (data classified as sensitive, admin identities, encryption keys, Kubernetes clusters, databases not yet classified).
Each step gets a fixed probability, the same for every customer, published here so that an auditor can read it.
| Step | Probability |
|---|---|
| Entry: public address and a security group open to the world (or unknown) | 0.9 |
| Entry: public address behind a security group with no open rule | 0.5 |
| Entry: behind a public load balancer | 0.7 |
| Entry: Kubernetes service of type LoadBalancer or NodePort | 0.8 |
| Entry: public API endpoint of a cluster | 0.3 |
| Entry: public serverless function, public database | 0.8 |
| Entry: public bucket | 1.0 |
| Exploit: exposed host with no known vulnerability | 0.05 |
| Exploit: vulnerability | EPSS probability, raised to 0.9 when the CVE is in the KEV catalogue and to 0.95 when it is used by ransomware |
| Identity yielded by IMDSv1 / IMDSv2 | 0.9 / 0.6 |
| Identity yielded by a service account | 0.7 |
| Active / unknown / inactive secret | 0.9 / 0.5 / 0.1 |
| Read / write access right | 0.9 / 1.0 |
| Cluster administration, same identity across clouds | 1.0 / 0.9 |
| Container escape | 0.6 |
The value of a target ranges from 0.5 (unclassified database) to 1.0 (health, payment or EU personal data), with 0.8 for an encryption key or a Kubernetes control plane.
The walk starts from every entry point, follows at most 4 relationships, keeps at most 5 paths per entry point and 500 in all, and drops a branch whose probability falls below 0.005. It is bounded in time and in volume: if a bound is hit, the paths found are published but marked incomplete, and no existing computed path is closed on that basis.
Score and severity of a path
For a computed path, the score is the product of the probabilities of its steps, multiplied by the value of the target. Three medium weaknesses that line up can therefore outrank a critical vulnerability that leads nowhere. Severity follows: critical from 0.5, high from 0.2, medium from 0.05, low below. The displayed "Risk", from 1 to 100, is 20 + 80 × √score: a certain path to sensitive data is 100, a one-in-twenty path is 38.
For a catalogue chain, the severity is the chain's own. The risk starts from a base per severity (80 critical, 60 high, 40 medium, 20 low), adds 5 per step up to 15 and 2 per resource up to 10, capped at 100. Ctadel then adjusts it by what it knows of the first resource: +15 if it is reachable from the Internet, +15 if it carries an exploitable weakness, +10 if it is a valuable target, −15 if it is a host or data store nothing reaches and without a weakness. This adjustment is not applied when the evaluation of computed paths is incomplete.
Each node of a computed path records why it is there: the reason and probability of the entry, the exploit, each step and the impact. The detail panel shows them link by link.
How a path is closed
A path stays open as long as all its links hold. To close it, break one: close the exposure, fix the vulnerability, remove a right, encrypt or move the data. The cheapest link is often a single configuration fix; prefer the one with the fewest dependants, for example fixing one host over rewriting a role shared by many.
At the next scan, the evaluation no longer returns that path; it moves to resolved, with the date and the author "system" in its history. Computed paths are closed this way only when their evaluation was complete: an incomplete evaluation closes nothing it could not verify. A path whose rule has been disabled is closed the same way.
The Sapper's proposals
The Sapper is an agent that searches the graph for paths no rule describes. It does not start from a blank page: before any call to the language model, Ctadel draws up a survey, that is the valuable targets, those a known path already reaches, and the frontier, the targets nothing reaches. That is the only place it searches.
On the "Toxic Combinations" page, the "Sapper" box shows the pending proposals and the "Search now" button. A search can also be scheduled at a fixed interval; by default, it is not. A search is bounded; if it stops on its bound, the page says so: "The search stopped on its budget: there may be more to find."
A proposal holds a title, a severity, a confidence, the "Verified path" link by link, the "Evidence" read from the graph and a "Generalised rule (Cypher)" that describes the pattern without naming resource identifiers. Ctadel refuses a rule that names a label, a relationship or a property the graph does not have. You decide: "Accept as a rule" creates a custom toxic rule for your instance, evaluated with the catalogue from the next scan and immediately on the path's first resource; "Reject" files the proposal with your reason. The Sapper reads the whole graph: it is available only to users with access to every project.
Limits
- Probabilities and target values are judgements fixed by Ctadel, the same for everyone; they are not measured on your environment.
- Reachability is computed only for hosts, services and data stores; an identity, a key or a cluster is never an entry point.
- A computed path crosses at most 4 relationships; 5 paths per entry point and 500 in all are kept. Beyond a time or volume bound, the result is marked partial.
- The exploit probability of a vulnerability comes from EPSS and the KEV catalogue; when that data has not yet been synced, a fallback by severity is used (0.2 critical, 0.1 high, 0.03 medium, 0.01 otherwise).
- A managed database is not scanned for vulnerabilities, a machine image is not scanned for secrets, and Kubernetes workload identity is not modelled: the chains that depend on them are disabled.
- When the evaluation of computed paths fails or is incomplete, the risk of catalogue chains is not adjusted and no computed path is produced or closed for that scan.
- The page's category filters ("Exposure", "Lateral Movement", "Privilege Escalation", "Data Access") do not match the categories the catalogue chains carry.
- The Sapper proposes; it creates nothing without your acceptance, and its scheduled searches are disabled by default.