Skip to content

Commit 19dcead

Browse files
committed
Make NG-SIEM detection hydration guidance detection-type-dependent
Detection hydration from an NG-SIEM Signal trigger is not one-size-fits-all. First-party and third-party detections can be pulled with an Event Query matching the composite DetectionID against Ngsiem.alert.id (verified live). Correlation-rule detections cannot: the rule trigger exposes only a composite DetectionID and an opaque ID, neither of which matches the Ngsiem.detection.id value that Advanced event search filters on, and that field is not in the trigger schema. The field that used to bridge it (Ngsiem.original_indicator.id) is gone from the rule-trigger events, so correlation-rule detections must be hydrated with a Get Detection Details action (or an HTTP Request to /alerts/entities/alerts/v2 passing the composite DetectionID as composite_id). Splits the "enriching a detection you already hold" guidance by detection type in event-query-vs-api.md, adds the same caveat to both trigger-types.md copies and the event-queries use case, and widens the validate.py detection.id-join guard message so it points first-party/third-party detections at Ngsiem.alert.id and correlation-rule detections at Get Detection Details, instead of implying alert.id always works. The guard itself is unchanged (Ngsiem.detection.id = ?arg is never a valid trigger-provided join). 503 tests pass, markdownlint clean.
1 parent 81d3484 commit 19dcead

5 files changed

Lines changed: 66 additions & 28 deletions

File tree

skills/authoring/references/event-query-vs-api.md

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,21 +63,34 @@ the customer's **ingestion connectors** — a tenant with no connectors returns
6363
audit-log events, not alerts, so an Event Query for "high-severity alerts" can
6464
silently return zero. The split is about whether you already hold the object:
6565

66-
- **Enriching a detection you already hold** → Event Query. When a workflow is
67-
triggered on a detection and has its ID, an Event Query to pull more fields is
68-
the right tool (go schemaless, since detection field shapes vary). **Match the
69-
detection's composite ID against `Ngsiem.alert.id`, NOT `Ngsiem.detection.id`.**
70-
The Signal trigger's `Trigger.Detection.DetectionID` is the *composite* ID
71-
(`cid:ngsiem:cid:id`), and in the NG-SIEM event store that value lives in
72-
`Ngsiem.alert.id`; `Ngsiem.detection.id` holds a different, short ID, so a query
73-
keyed on it silently returns **zero rows** (verified live). So:
74-
75-
```
76-
# RIGHT — composite DetectionID matches Ngsiem.alert.id
77-
Ngsiem.alert.id = ?detectID
78-
# WRONG — returns 0 rows for a composite DetectionID
79-
Ngsiem.detection.id = ?detectID
80-
```
66+
- **Enriching a detection you already hold** → depends on the detection type.
67+
When a workflow is triggered on a detection and has its ID, how you pull more
68+
fields depends on what kind of detection fired:
69+
- **First-party and third-party detections** → Event Query. Go schemaless
70+
(detection field shapes vary) and **match the detection's composite ID
71+
against `Ngsiem.alert.id`, NOT `Ngsiem.detection.id`.** The Signal trigger's
72+
`Trigger.Detection.DetectionID` is the *composite* ID (`cid:...:cid:id`), and
73+
in the NG-SIEM event store that value lives in `Ngsiem.alert.id`;
74+
`Ngsiem.detection.id` holds a different, short ID, so a query keyed on it
75+
silently returns **zero rows** (verified live). So:
76+
77+
```
78+
# RIGHT — composite DetectionID matches Ngsiem.alert.id
79+
Ngsiem.alert.id = ?detectID
80+
# WRONG — returns 0 rows for a composite DetectionID
81+
Ngsiem.detection.id = ?detectID
82+
```
83+
84+
- **Correlation-rule detections** → **Get Detection Details** action, NOT an
85+
Event Query. The rule trigger exposes only the composite `DetectionID` and an
86+
opaque `ID`; neither matches the `Ngsiem.detection.id` value that Advanced
87+
event search filters on, and that field is not in the trigger schema. The
88+
field that used to bridge it (`Ngsiem.original_indicator.id`) is gone from the
89+
rule-trigger events, so a correlation-rule detection cannot be hydrated via
90+
Event Query today. Add a **Get Detection Details** gather step (or a
91+
CrowdStrike HTTP Request to `/alerts/entities/alerts/v2` passing the composite
92+
`DetectionID` as `composite_id`) to fetch the full detection, then read fields
93+
from its response.
8194
8295
**Treat detection IDs as opaque.** Per the detections team, `composite_id` (what
8396
the trigger hands you) is the primary key used to retrieve a detection, but its
@@ -86,7 +99,7 @@ silently return zero. The split is about whether you already hold the object:
8699
NG-SIEM → Advanced event search or via the NG-SIEM search API before assuming the
87100
detection has no data. **If the detection type carries indicators directly in the
88101
trigger payload (e.g. EPP: `Trigger.Detection.EPP.Process.SHA256`), prefer reading
89-
them straight from the payload over a hydration query — no join, no empty-result
102+
them straight from the payload over any hydration step — no join, no empty-result
90103
risk.** Discover payload fields with `trigger_search.py --fields <category>`.
91104
- **Fetching the alert/detection *population* you don't have** — "summarize all
92105
high-severity alerts", "list open detections across products" → the Falcon

skills/authoring/references/trigger-types.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,14 @@ list), hydrate with an Event Query and read from its `results` array:
214214
through an inline Python extractor** (`cs.json.decode(data['<Python>.output_stdout'])`)
215215
— that form does not resolve at release. Read `results[0].<Field>` directly.
216216

217+
**Event Query hydration only works for first-party and third-party detections**
218+
(match the composite `DetectionID` against `Ngsiem.alert.id`, not
219+
`Ngsiem.detection.id`). **Correlation-rule detections cannot be hydrated by an
220+
Event Query** — their `Ngsiem.detection.id` is not exposed on the trigger and no
221+
Event Query field matches it. For those, add a **Get Detection Details** action
222+
(or an HTTP Request to `/alerts/entities/alerts/v2` passing the composite
223+
`DetectionID` as `composite_id`). See `references/event-query-vs-api.md`.
224+
217225
**Not every `Trigger.Detection.*` field resolves on the NG-SIEM trigger.**
218226
`${Trigger.Detection.Product}` and `${Trigger.Detection.Description}` are available
219227
on the **base `event: Investigatable`** trigger (the multi-product Detection trigger

skills/authoring/scripts/validate.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -419,12 +419,16 @@ def _check_detection_hydration_join(label, config, issues):
419419
if isinstance(query, str) and _DETECTION_ID_JOIN_RE.search(query):
420420
issues.append(
421421
f"ERROR: Event Query action '{label}' hydrates a detection by "
422-
f"matching 'Ngsiem.detection.id = ?...'. The trigger's composite "
423-
f"DetectionID is stored in 'Ngsiem.alert.id', NOT "
424-
f"'Ngsiem.detection.id' (a different, short ID the trigger never "
425-
f"provides) — this query returns zero rows at runtime and the "
426-
f"workflow enriches nothing, despite releasing cleanly. Change the "
427-
f"join field to 'Ngsiem.alert.id'. See references/event-query-vs-api.md."
422+
f"matching 'Ngsiem.detection.id = ?...'. The trigger never provides "
423+
f"that field. For first-party and third-party detections, the "
424+
f"trigger's composite DetectionID is stored in 'Ngsiem.alert.id' — "
425+
f"change the join field to 'Ngsiem.alert.id'. For correlation-rule "
426+
f"detections, neither Event Query field matches; use a 'Get Detection "
427+
f"Details' action (or an HTTP Request to /alerts/entities/alerts/v2 "
428+
f"passing the composite DetectionID as composite_id) instead. As "
429+
f"written this query returns zero rows at runtime and the workflow "
430+
f"enriches nothing, despite releasing cleanly. See "
431+
f"references/event-query-vs-api.md."
428432
)
429433

430434

skills/workflows/references/trigger-types.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@ rejected at release as "unknown variable" for EPP triggers. Enrich indicators
123123
straight from the trigger payload (e.g. send `Process.SHA256` to VirusTotal);
124124
you do not need an Event Query to hydrate the detection.
125125

126+
**If you must hydrate a detection** (indicators not on the trigger), the path
127+
depends on detection type. First-party/third-party detections can be pulled with
128+
an Event Query matching the composite `DetectionID` against `Ngsiem.alert.id` (not
129+
`Ngsiem.detection.id`). **Correlation-rule detections cannot be hydrated by an
130+
Event Query** — their `Ngsiem.detection.id` is not exposed on the trigger; use a
131+
**Get Detection Details** action (or an HTTP Request to
132+
`/alerts/entities/alerts/v2` passing the composite `DetectionID` as `composite_id`)
133+
instead. See `../../authoring/references/event-query-vs-api.md`.
134+
126135
**Severity is an integer (1-5) at `Trigger.Detection.Severity`, not a string.** Use numeric comparison in CEL conditions:
127136

128137
| Value | Display Name |

use-cases/event-queries.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ capabilities: [workflow, event-query]
1010

1111
User wants a workflow to query the NG-SIEM event store — ingested logs, custom telemetry,
1212
LogScale search results, or enriching a detection the workflow already holds (e.g.
13-
`Ngsiem.alert.id = ?detectID` — the trigger's composite `DetectionID` is stored as
14-
`Ngsiem.alert.id`, not `Ngsiem.detection.id`) — without defining a schema up front. The Event Query action
13+
`Ngsiem.alert.id = ?detectID` — for first-party/third-party detections the trigger's composite
14+
`DetectionID` is stored as `Ngsiem.alert.id`, not `Ngsiem.detection.id`; correlation-rule
15+
detections can't be hydrated this way, use a Get Detection Details action) — without defining a
16+
schema up front. The Event Query action
1517
runs a CQL/FQL query inline and
1618
returns matching events, which subsequent actions process and branch on. This is the
1719
"schemaless" path: you query whatever the event store holds and shape the results downstream,
@@ -104,7 +106,9 @@ code-driven querying belongs in a function.
104106
> **Mention** the alternative when the workflow must be shared: a **Foundry app + FalconPy
105107
> `Alerts`/`Detects` function** (route to **foundry-skills**) — distributable/certifiable, prompts
106108
> for creds on install. This does NOT apply to *enriching a detection
107-
> you already hold* — when the workflow was triggered on a detection and has its ID, an Event Query
108-
> like `Ngsiem.alert.id = ?detectID` to pull more fields is the right tool (match the composite
109-
> `DetectionID` against `Ngsiem.alert.id`, not `Ngsiem.detection.id`). See
110-
> [event-query-vs-api.md](../skills/authoring/references/event-query-vs-api.md).
109+
> you already hold* — when the workflow was triggered on a **first-party or third-party** detection
110+
> and has its ID, an Event Query like `Ngsiem.alert.id = ?detectID` to pull more fields is the right
111+
> tool (match the composite `DetectionID` against `Ngsiem.alert.id`, not `Ngsiem.detection.id`).
112+
> **Correlation-rule detections are the exception:** their `Ngsiem.detection.id` is not in the
113+
> trigger and can't be reached by an Event Query — use a **Get Detection Details** action instead.
114+
> See [event-query-vs-api.md](../skills/authoring/references/event-query-vs-api.md).

0 commit comments

Comments
 (0)