Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"name": "s1-secops-skills",
"source": "./plugins/s1-secops-skills",
"description": "SentinelOne SecOps skills for Claude: PowerQuery threat hunting and STAR/Custom Detection rules; Management Console API; Singularity Data Lake API; SDL dashboards; log parsing (OCSF); Hyperautomation SOAR; z-score anomaly baselining; autonomous DFIR alert investigation (soc-investigator); and one-prompt SDL solutions: source onboarding, asset enrichment, UEBA, ingest health, detection exclusions, Risk-Based Alerting, alert noise reduction, and Detection as Code.",
"version": "1.2.8",
"version": "1.2.12",
"author": {
"name": "Prithvi Moses",
"email": "prithvi.moses@sentinelone.com"
Expand Down
2 changes: 1 addition & 1 deletion plugins/s1-secops-skills/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "s1-secops-skills",
"version": "1.2.11",
"version": "1.2.12",
"description": "SentinelOne SecOps skills for Claude: PowerQuery threat hunting and STAR/Custom Detection rules; Management Console API; Singularity Data Lake API; SDL dashboards; log parsing (OCSF); Hyperautomation SOAR; z-score anomaly baselining; autonomous DFIR alert investigation (soc-investigator); and one-prompt SDL solutions: source onboarding, asset enrichment, UEBA, ingest health, detection exclusions, Risk-Based Alerting, alert noise reduction, and Detection as Code.",
"author": {
"name": "Prithvi Moses",
Expand Down
Binary file modified plugins/s1-secops-skills/dist/hyperautomation.skill
Binary file not shown.
Binary file modified plugins/s1-secops-skills/dist/mgmt-console-api.skill
Binary file not shown.
Binary file modified plugins/s1-secops-skills/dist/powerquery.skill
Binary file not shown.
Binary file not shown.
Binary file modified plugins/s1-secops-skills/dist/sdl-api.skill
Binary file not shown.
Binary file modified plugins/s1-secops-skills/dist/sdl-dashboard.skill
Binary file not shown.
Binary file modified plugins/s1-secops-skills/dist/sdl-log-parser.skill
Binary file not shown.
Binary file modified plugins/s1-secops-skills/dist/sdl-solutions.skill
Binary file not shown.
Binary file modified plugins/s1-secops-skills/dist/soc-investigator.skill
Binary file not shown.
215 changes: 119 additions & 96 deletions plugins/s1-secops-skills/docs/solutions/ueba-anomaly-detection.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -248,11 +248,13 @@ Performance: start with the most selective (smallest-cardinality) subquery. PQ e
## 10. `union`

```
| union (query1), (query2), … // up to 10 queries
| union (query1), (query2), … // comma-separated branches in ONE union
```

Stacks result sets as rows. Unlike SQL union, the queries can have different columns and different types — missing columns become null. Output has no sort order (add `sort` after).

A `union` takes at most **10 subqueries**; more than 10 returns HTTP 400. Write it as a leading command, `| union (q1),(q2),...`, at the start of the query. A subquery may synthesise rows, e.g. `( | limit 1 | columns a=2, b='bar' )`, which is how you build literal rows for a `savelookup`. Do not precede `union` with a main pipeline ending in `| limit` (e.g. `<filter> | limit 1 | union (...)`); that returns HTTP 400 at any branch count. To combine more than 10 subqueries, nest: `| union ( | union (b1),...,(b10) | columns ... ), ( | union (b11),... | columns ... )`, keeping each inner union at 10 or fewer. When branches differ only by a matched literal, prefer a single scan with a `let` plus a ternary over a wide union.

Use to merge heterogeneous sources (e.g., `api_server` logs with fields `operation`/`elapsed_time` and `frontend` logs with `url`/`http_status`). Rename columns in each sub-query's `columns` to unify them:

```
Expand Down
17 changes: 17 additions & 0 deletions plugins/s1-secops-skills/skills/powerquery/references/pitfalls.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,23 @@ Fix — for first-element access inside a query, use `array_get` in a `let`:
| let first_resource_name = first_resource.name
```

**On the alert / findings stream, group and filter the entity with the WILDCARD accessor.**
The stream is `dataSource.name='alert' class_uid=99602001` (`finding_info.title` is a flat,
`contains:anycase(...)`-filterable string = the alert name; `metadata.product.name` is one of STAR /
EDR / Identity / CWS / EPP). The alert entity (user or host) is only usable as a `group by` / `filter`
key via the wildcard form `resources[*].name` (and `resources[*].type` for the asset type). The
first-element forms do NOT work as a grouping key here: `resources[0].name` returns HTTP 400 in
`group`/`columns`, `resources.name` returns null, and even `array_get(resources,0).name` cannot be a
group key on this stream. Wildcard values come back JSON-array-wrapped, e.g. `["j.doe@corp.com"]` or
`["DESKTOP-GDIA5I7"]`, so strip the `[` `]` `"` wrapping when post-processing. The same wildcard form
reads optional MITRE on custom alerts: `finding_info.attacks[*].tactic.uid` / `.name`.

```
dataSource.name='alert' class_uid=99602001
| filter finding_info.title contains:anycase("SPIKE")
| group hits = count() by entity = resources[*].name, tactic = finding_info.attacks[*].tactic.uid
```

For analytics over array fields, prefer top-level scalar fields
(`severity_id`, `finding_info.title`, `metadata.product.name`, `class_name`),
or step out of PowerQuery to the V1 query API which exposes the full event
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,15 @@ Panels are placed by `layout: {w, h, x, y}`. When appending a new section to an

The SDL dashboard render engine has a longer query budget than the PowerQuery MCP. A query that times out in MCP validation may still render in the UI. Conversely, a query that returns from MCP may render slowly in the UI. The final smoke test for every dashboard is: open it in the UI, watch each tab load, confirm no panel spins indefinitely.

### 8.6 Data-source scope: All Data vs XDR (panels can be empty under the wrong scope)

The top-left data-source selector (All Data vs XDR) applies to every panel on the dashboard. Two panel kinds read data that lives OUTSIDE the XDR view and therefore return no data under XDR, even though the query is correct:

- **`| dataset 'config://datatables/<table>'` reads** (config datatables / lookups). A `| dataset` config-table panel renders empty under the XDR scope.
- **The SentinelOne alert / findings stream** (`dataSource.name='alert' class_uid=99602001`, category `security`). It sits in the native store, not the XDR log-telemetry view, so alert-stream panels are empty under XDR.

Ingested source telemetry (XDR-attributed) renders under either scope, which is why most detection panels look fine and only the alert-stream / lookup panels appear "broken" under XDR. This is a scope mismatch, not a missing field or a bad query. Guidance: put a one-line reminder in the dashboard `description` (shown on every tab) and on the affected tabs telling the user to select **All Data**; the `description` is the most reliable place because it is visible regardless of which tab is open. There is no dashboard-JSON field to pin the scope, so a reminder is the fix.

---

## 9. Discovery → author → validate → deploy workflow
Expand Down
4 changes: 2 additions & 2 deletions plugins/s1-secops-skills/skills/sdl-solutions/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ parser, dashboard, or workflow, use the matching primitive skill directly.
|---|---|---|
| Data source onboarding | Take a raw log stream already reaching the tenant and operationalise it end to end from one short prompt: locate the source, normalise it to OCSF, enrich it with device/user context, then build a dashboard, MITRE-mapped detections, and a Hyperautomation flow | `references/data-source-onboarding.md` |
| Asset enrichment | Enrich ingested raw logs with device and user context (OS, IP, agent UUID, AD groups, SID, criticality, risk factors) from the Asset Inventory, at ingest or at query time | `references/asset-enrichment.md` |
| UEBA behavioural anomaly detection | Baseline ANY security or non-security signal per (action, principal) over a chosen window and detect deviations: core classes SPIKE, DROP, SILENT, and NEW-BEHAVIOR, plus six opt-in advanced Tier-1 detections (OFF-HOURS, FAN-OUT, RATIO, VELOCITY, PEER-GROUP, DORMANT). PEER-GROUP flags a principal doing far more of an action than its peer cohort (population by action, or optionally a directory group from the ISPM Asset Inventory Member Of). A global Sensitivity method knob switches volume scoring between Standard (z-score) and Robust (percentile p95/p05, default), and a security use-case selector (account takeover, brute force, insider threat / data exfil, lateral movement, privilege abuse, service/feed health, all, custom) presets the right detections and method. Interactive engine for investigation, or a production deploy (baseline lookup + scheduled PowerQuery rule + nightly refresh + dashboard); Tier-2/3 roadmap (geo-velocity, privilege-change, sequence, RBA) documented for when the data exists | `references/ueba-anomaly-detection.md` |
| UEBA behavioural anomaly detection | Baseline ANY security or non-security signal per (action, principal) over a chosen window and detect deviations. Ten behavioural detections: core SPIKE, DROP, SILENT, NEW-BEHAVIOR plus advanced OFF-HOURS, FAN-OUT, RATIO, VELOCITY, PEER-GROUP, DORMANT; plus two location detections GEO-NEW and IMPOSSIBLE-TRAVEL when a Location field is set; plus Risk-Based Alerting (RBA) that consolidates alerts into one cumulative per-entity risk score. The source is matched by `dataSource.name` or `serverHost`, and the action can be a composite of 2-3 fields. A Sensitivity knob switches volume scoring between Standard (z-score) and Robust (percentile p95/p05, default); a use-case selector (account takeover, account takeover geo, brute force, insider / data exfil, lateral movement, privilege abuse, service/feed health, all, custom) presets detections and method. One-click production deploy: baseline lookups + scheduled PowerQuery rules + Hyperautomation watchdogs + staggered per-baseline nightly refresh + a daily failure-notifier + a review dashboard. The s1-ueba-deployer is the source of truth | `references/ueba-anomaly-detection.md` |
| Ingest health monitoring (per device) | Per-device ingest health: anomaly detection on a 7-day hour-of-day seasonal baseline refreshed daily, detecting when a specific firewall, endpoint, or server spikes, drops, lags (p95), or goes silent, plus parser drift. Deploys per-device baseline lookups, scheduled PowerQuery detections, an ingest-loss watchdog flow, a 5-tab dashboard, an email-notification flow for every failure, and an editable source-exclusions lookup and a device-level config lookup (source level by default, per-device opt-in), with unified Spike/Drop/Lag rules that tag each alert source or device; Parser Drift is optional and tuned per environment | `references/ingest-health-monitoring.md` |
| Detection exclusions (single-event, correlation, or scheduled) | Suppress known-good noise in a STAR Custom Detection rule over a third-party or EDR SDL source. **Ask the user the rule type first** (Step 0): a single-event rule (`queryType: events`) or a correlation rule (`queryType: correlation`) hardcodes the exclusion as an inline `AND NOT (<field> in:anycase (...))` negative list in a boolean S1QL body (correlation appends it to each sub-query in `correlationParams`), fires per event / on multi-event thresholds, and supports mitigation; or a scheduled PowerQuery detection (`queryType: scheduled`) loads a CSV exclusion list as an SDL lookup table and omits matching rows via an anti-join (`\| lookup ... \| filter <col> = null`), aggregates, and ships an effectiveness dashboard. Single-event and correlation deploy just the rule; scheduled deploys the lookup table, the rule, an optional source-of-truth refresh flow, and the dashboard | `references/custom-detection-exclusions.md` |
| Risk-Based Alerting (RBA) | Noisy-but-interesting observations are published as low-noise risk events into a `risk` index instead of alerting individually; risk accumulates per object (user / host), amplified by asset-derived risk factors; one high-fidelity alert fires only when a 24h cumulative score or 7d distinct-MITRE-tactic threshold is crossed, giving a contextualised story instead of disconnected alerts. Deploys contributors, a risk-factor table, a scheduled collector flow (**publish as Shared Draft, then prompt the user to bind the "SentinelOne SDL" connection, then activate**, the connection cannot be bound via API), four incident rules (user/host x score/tactics), and a dashboard | `references/risk-based-alerting.md` |
| Risk-Based Alerting (RBA) | Noisy-but-interesting observations are published as low-noise risk events into a `risk` index instead of alerting individually; risk accumulates per object (user / host), amplified by asset-derived risk factors; one high-fidelity alert fires only when a 24h cumulative score or 7d distinct-MITRE-tactic threshold is crossed, giving a contextualised story instead of disconnected alerts. Deploys contributors, a risk-factor table, a scheduled collector flow (**publish as Shared Draft, then prompt the user to bind the "SentinelOne SDL" connection, then activate**, the connection cannot be bound via API), four incident rules (user/host x score/tactics), and a dashboard. This is the heavyweight risk-index model (a dedicated `risk` index + collector + contributors + risk factors). For a lightweight alternative that scores the existing SentinelOne alert stream in place against an editable RiskWeights + AssetWatchlist table and fires one watchdog per entity, use the RBA built into the UEBA solution (the s1-ueba-deployer), see `references/ueba-anomaly-detection.md` | `references/risk-based-alerting.md` |
| Detection as Code (DaC) | Stand up a Git + CI pipeline where detection engineers author rules as TOML files, a pull request triggers validation and four-eyes review, and a merge syncs the changed rules to the SentinelOne Custom Detection Rule API. Scaffolds a starter repo (per-target-system folders, CODEOWNERS, branch-protection guidance), seeds working examples of all three rule types (single-event `events`, `correlation`, scheduled PowerQuery), and ships a zero-dependency TOML-to-API sync engine with idempotent create-or-update plus lint-on-PR and sync-on-merge CI for GitHub Actions, GitLab CI, and Azure Pipelines. Unlike the other solutions, DaC sets up a workflow OUTSIDE the tenant that pushes rules in | `references/detection-as-code.md` |
| Alert noise reduction | Find the (source, signature) pairs flooding the alert queue, separate ingested and already-actioned noise (block/drop/sinkhole/reset) from real S1 detections, then recommend an ingestion-severity filter (a console setting on the connector), deploy an auto-resolve Hyperautomation flow that closes already-mitigated alerts with a note, optionally preserve signal-worthy categories (e.g. C2/DGA) as one correlation rule, and ship a noise-vs-signal dashboard. All product/source/signature/action values are discovered live; nothing is hardcoded | `references/alert-noise-reduction.md` |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ Implement the Risk-Based Alerting (RBA) paradigm in SentinelOne SDL. Instead of

Every mechanic in this playbook is tenant-validated end to end (2026-06-24/25): risk index, contributors, factor multipliers, collector flow, incident rules, dashboard, and a real fired alert.

> **Two RBA approaches, pick per need.** This playbook is the heavyweight **risk-index** model: a
> dedicated `risk` index populated by a collector flow from contributor PowerQueries, with
> asset-derived risk factors and four incident rules. A lightweight alternative ships in the UEBA
> solution (the s1-ueba-deployer, see `ueba-anomaly-detection.md`): it scores the existing SentinelOne
> **alert stream** in place against an editable RiskWeights + AssetWatchlist datatable and fires one
> Hyperautomation watchdog per entity, with no separate index or collector. Use the risk-index model
> to score arbitrary contributor queries into asset-weighted, multi-tactic risk objects; use the
> alert-stream model to consolidate the alerts you already have into one cumulative per-entity score.

## Concept mapping: RBA concepts to SentinelOne

| RBA concept | SentinelOne |
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
# UEBA behavioural anomaly detection

The full solution documentation lives at [`docs/solutions/ueba-anomaly-detection.md`](../../../docs/solutions/ueba-anomaly-detection.md).
The **s1-ueba-deployer is the source of truth** for this solution. The full documentation lives at
[`docs/solutions/ueba-anomaly-detection.md`](../../../docs/solutions/ueba-anomaly-detection.md),
mirrored from the deployer.

Read that document for: the security use-case selector (intent to data sources to detections to
scoring method), the ten detections (SPIKE, DROP, SILENT, NEW-BEHAVIOR, OFF-HOURS, FAN-OUT, RATIO,
VELOCITY, PEER-GROUP, DORMANT) with security examples and logic, the Robust vs Standard method, every exact
deployed PowerQuery, what gets deployed in production mode, the Tier 2/3 roadmap, and the interactive
`baseline_anomaly.py` pipeline.
scoring method); the detection set, which is the ten behavioural classes (SPIKE, DROP, SILENT,
NEW-BEHAVIOR, OFF-HOURS, FAN-OUT, RATIO, VELOCITY, PEER-GROUP, DORMANT), plus two location detections
(GEO-NEW, IMPOSSIBLE-TRAVEL) when a location field is set, plus Risk-Based Alerting (RBA); the Robust
vs Standard method; every exact deployed PowerQuery; what gets deployed in production; the composite
action key; source matching by `dataSource.name` or `serverHost`; the staggered per-baseline refresh
and daily failure-notifier flows; and the dashboard All Data vs XDR scope. GEO-NEW, IMPOSSIBLE-TRAVEL,
and RBA are shipped, not roadmap.

This solution is part of the `sdl-solutions` skill; it orchestrates the primitive skills
(`mgmt-console-api`, `powerquery`, `hyperautomation`,
`sdl-dashboard`) rather than reimplementing them.
(`mgmt-console-api`, `powerquery`, `hyperautomation`, `sdl-dashboard`) rather than reimplementing
them.
Loading