diff --git a/src/pages/docs/api.astro b/src/pages/docs/api.astro index ad50768..2fb65d4 100644 --- a/src/pages/docs/api.astro +++ b/src/pages/docs/api.astro @@ -133,10 +133,12 @@ curl -s -H "Authorization: Bearer $OM_API_SECRET" \\ Attack paths for depth and row limits.

- GET /v1/findings returns an array. Each item has finding (the node) + GET /v1/findings returns findings and, when another page remains, + next_cursor. Each item has finding (the node) plus affected_resource_id, affected_resource_name, and - affected_resource_type from the VIOLATES edge. Rows are ordered by - normalized_score descending. Default limit 200. + affected_resource_type from the VIOLATES edge. An attack-path + finding also includes path, the ordered node ids from the internet to the + datastore. Rows are ordered by normalized_score descending. Default limit 200.

POST /v1/rules/run returns matches and findings_created. @@ -163,7 +165,8 @@ curl -s -H "Authorization: Bearer $OM_API_SECRET" \\

Failures are JSON {`{"error":"..."}`} with 400, 401, or 500. A missing or wrong secret on any /v1 route except health is 401 unauthorized. Invalid JSON on ingest is 400 - invalid json body. There is no request id and no pagination cursor. Raise + invalid json body. There is no request id. A list that has another page returns + next_cursor; pass it back as cursor. Raise limit when a list is truncated. There is no server-side maximum above the number you pass, except the fixed caps inside path queries, blast radius, and exports.

diff --git a/src/pages/docs/attack-paths.astro b/src/pages/docs/attack-paths.astro index e0a181a..a12dac8 100644 --- a/src/pages/docs/attack-paths.astro +++ b/src/pages/docs/attack-paths.astro @@ -6,7 +6,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro'; toxic-s3-public-with-admin-role is an alias and is not listed.

+

Attack-path findings

+

+ Named queries answer a question you ask. om rules run and + POST /v1/rules/run also write the combination into the findings list. Control + rules run first. The attack-path rule then writes one finding for each existing + finding on an internet-reachable workload, paired with a datastore that workload can reach. +

+

+ A workload is internet-reachable when a REACHABLE walk from + internet:global ends on it, with the same depth limit as + internet-to-datastore (recursion stops before depth 8). The source finding is a + VIOLATES edge whose target is that workload. Findings with + finding_type: attack_path are not sources, so the pass does not chain. Two + findings on the same workload produce two attack-path rows for the same datastore. +

+

+ The workload reaches a datastore in either of two hops. A CAN_ACCESS edge from + the workload to the datastore is one. ASSUMES to an identity that itself has + CAN_ACCESS is the other. The demo path uses the second: Internet → sg-web → + web-1 → AdminRole → prod-db. When both hops reach the same datastore, the shorter path is + stored, which is the direct CAN_ACCESS edge. The finding description names the + source finding and the datastore, for example "Internet-exposed workload: web-1 is on a path + to prod-db." +

+

+ path is that ordered list of node ids. The finding id is + {'finding:attack-path:{source-finding-id}:{datastore-id}'}. + finding_type is attack_path. normalized_score and + severity are copied from the source finding’s score, using the same bands as other rules. A + source with no score is stored as 75, severity high. The graph-context bonuses are not added + again. The VIOLATES edge points at the workload, so the findings list names that + workload as the affected resource. datastore_id and + source_finding_id are properties on the finding. +

+

+ A reachable workload with no datastore hop does not get this finding. A hop whose workload + has no other finding does not either. Run om rules run attack-path on a graph + that has the edges and no findings, and the pass writes nothing. + om rules run with no id is different: cspm-internet-workload writes + a finding on every internet-reachable workload first, and the attack-path pass then pairs + that finding with each datastore the workload can reach. sensitivity does not + filter these rows. internet-to-sensitive-datastore remains the query that keeps + only marked datastores. +

+

+ Re-running the rule deletes an attack-path finding whose hop or source finding is gone. + Other rules’ findings stay. om enrich cve does not write attack-path rows. Run + rules again after enrichment so a new CVE is paired with the datastore. + GET /v1/findings returns path on the row. The console prints those + ids on the card. SIEM export includes the same list. +

+

Reading an empty result

An empty path list means the edges are not there, not that the account is safe. The walk diff --git a/src/pages/docs/cli.astro b/src/pages/docs/cli.astro index 9d6db8c..20f379c 100644 --- a/src/pages/docs/cli.astro +++ b/src/pages/docs/cli.astro @@ -69,7 +69,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro'; om rules run [rule-id] - Evaluate one rule or the full catalog and upsert findings. + Evaluate one rule or the full catalog and upsert findings. A full run writes attack-path findings after the control rules. om paths list diff --git a/src/pages/docs/console.astro b/src/pages/docs/console.astro index 73fd2e5..384d21f 100644 --- a/src/pages/docs/console.astro +++ b/src/pages/docs/console.astro @@ -19,7 +19,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';

What you can do