From 3b04e9e284b6999daef1c889521fec98cde1e52d Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Wed, 2 Sep 2026 14:29:27 -0400 Subject: [PATCH 01/27] Add CrowdStrike plugin Monitors CrowdStrike Falcon host coverage, detections & incidents (via the unified Alerts API, replacing the deprecated Incidents API), Spotlight vulnerabilities, and Prevention/Sensor Update policy coverage. Indexes CrowdStrike Host Group (agencies) and CrowdStrike Host (devices), with a Host Group perspective dashboard scoped to per-agency metrics, plus an account-wide Overview and a Host perspective. Built from CrowdStrike's published API docs and an endpoint reference list; no live CrowdStrike credentials were available during development, so no stream has been tested against real data and no import has run yet. See docs/README.md "Known limitations" for every assumption that still needs live verification. Co-Authored-By: Claude Sonnet 5 --- plugins/CrowdStrike/v1/configValidation.json | 11 + plugins/CrowdStrike/v1/custom_types.json | 16 + .../CrowdStrike/v1/dataStreams/alerts.json | 94 ++ .../v1/dataStreams/currentUser.json | 18 + .../CrowdStrike/v1/dataStreams/devices.json | 88 ++ .../v1/dataStreams/hostGroups.json | 38 + .../v1/dataStreams/preventionPolicies.json | 29 + .../v1/dataStreams/sensorUpdatePolicies.json | 30 + .../v1/dataStreams/sensorUsage.json | 16 + .../v1/dataStreams/vulnerabilities.json | 81 ++ .../hostGroupPerspective.dash.json | 812 ++++++++++++++++++ .../defaultContent/hostPerspective.dash.json | 231 +++++ .../v1/defaultContent/manifest.json | 7 + .../v1/defaultContent/overview.dash.json | 437 ++++++++++ .../CrowdStrike/v1/defaultContent/scopes.json | 26 + plugins/CrowdStrike/v1/docs/README.md | 61 ++ plugins/CrowdStrike/v1/icon.svg | 7 + .../v1/indexDefinitions/default.json | 38 + plugins/CrowdStrike/v1/metadata.json | 34 + plugins/CrowdStrike/v1/ui.json | 32 + 20 files changed, 2106 insertions(+) create mode 100644 plugins/CrowdStrike/v1/configValidation.json create mode 100644 plugins/CrowdStrike/v1/custom_types.json create mode 100644 plugins/CrowdStrike/v1/dataStreams/alerts.json create mode 100644 plugins/CrowdStrike/v1/dataStreams/currentUser.json create mode 100644 plugins/CrowdStrike/v1/dataStreams/devices.json create mode 100644 plugins/CrowdStrike/v1/dataStreams/hostGroups.json create mode 100644 plugins/CrowdStrike/v1/dataStreams/preventionPolicies.json create mode 100644 plugins/CrowdStrike/v1/dataStreams/sensorUpdatePolicies.json create mode 100644 plugins/CrowdStrike/v1/dataStreams/sensorUsage.json create mode 100644 plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json create mode 100644 plugins/CrowdStrike/v1/defaultContent/hostGroupPerspective.dash.json create mode 100644 plugins/CrowdStrike/v1/defaultContent/hostPerspective.dash.json create mode 100644 plugins/CrowdStrike/v1/defaultContent/manifest.json create mode 100644 plugins/CrowdStrike/v1/defaultContent/overview.dash.json create mode 100644 plugins/CrowdStrike/v1/defaultContent/scopes.json create mode 100644 plugins/CrowdStrike/v1/docs/README.md create mode 100644 plugins/CrowdStrike/v1/icon.svg create mode 100644 plugins/CrowdStrike/v1/indexDefinitions/default.json create mode 100644 plugins/CrowdStrike/v1/metadata.json create mode 100644 plugins/CrowdStrike/v1/ui.json diff --git a/plugins/CrowdStrike/v1/configValidation.json b/plugins/CrowdStrike/v1/configValidation.json new file mode 100644 index 00000000..8e9a3a2a --- /dev/null +++ b/plugins/CrowdStrike/v1/configValidation.json @@ -0,0 +1,11 @@ +{ + "steps": [ + { + "displayName": "Authenticate", + "dataStream": { "name": "currentUser" }, + "required": true, + "error": "Could not authenticate. Check your Client ID, Client Secret and CrowdStrike Cloud region are correct, and that the API client has the Hosts: Read scope.", + "success": "Connected successfully." + } + ] +} diff --git a/plugins/CrowdStrike/v1/custom_types.json b/plugins/CrowdStrike/v1/custom_types.json new file mode 100644 index 00000000..3b67cc35 --- /dev/null +++ b/plugins/CrowdStrike/v1/custom_types.json @@ -0,0 +1,16 @@ +[ + { + "name": "CrowdStrike Host Group", + "sourceType": "CrowdStrike Host Group", + "icon": "layer-group", + "singular": "Host Group", + "plural": "Host Groups" + }, + { + "name": "CrowdStrike Host", + "sourceType": "CrowdStrike Host", + "icon": "desktop", + "singular": "Host", + "plural": "Hosts" + } +] diff --git a/plugins/CrowdStrike/v1/dataStreams/alerts.json b/plugins/CrowdStrike/v1/dataStreams/alerts.json new file mode 100644 index 00000000..5efb0008 --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/alerts.json @@ -0,0 +1,94 @@ +{ + "name": "alerts", + "displayName": "Alerts", + "description": "Detections and incidents from the unified Falcon Alerts API, one row per alert, with computed detection and response latency", + "tags": ["Security", "Alerts"], + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "endpointPath": "/alerts/combined/alerts/v1", + "postBody": { + "limit": 100, + "sort": "created_timestamp|desc", + "after": "{{after || null}}", + "filter": "{{(function(){var parts=[];if(typeof timeframe!=='undefined'&&timeframe&&timeframe.start&&timeframe.end){parts.push(\"created_timestamp:>'\"+timeframe.start+\"'+created_timestamp:<'\"+timeframe.end+\"'\");}var sel=(typeof scope!=='undefined'?scope:[])||[];var unwrap=function(v){return Array.isArray(v)?v[0]:v;};if(sel.length){var dev=[],grp=[];sel.forEach(function(o){var id=unwrap(o.rawId);if(o.type==='CrowdStrike Host Group'){grp.push(id);}else{dev.push(id);}});if(dev.length)parts.push(\"device.device_id:[\"+dev.map(function(i){return \"'\"+i+\"'\";}).join(\",\")+\"]\");if(grp.length)parts.push(\"device.groups:[\"+grp.map(function(i){return \"'\"+i+\"'\";}).join(\",\")+\"]\");}var st=(typeof status!=='undefined'?status:[])||[];if(st.length)parts.push(\"status:[\"+st.map(function(s){return \"'\"+(s.value||s)+\"'\";}).join(\",\")+\"]\");return parts.length?parts.join(\"+\"):null;})()}}" + }, + "paging": { + "mode": "token", + "pageSize": { "realm": "body", "path": "limit", "value": "100" }, + "in": { "realm": "payload", "path": "meta.pagination.after" }, + "out": { "realm": "body", "path": "after" } + }, + "pathToData": "resources", + "expandInnerObjects": true + }, + "matches": "none", + "ui": [ + { + "type": "objects", + "name": "scope", + "label": "Host or Host Group (optional)", + "matches": { + "sourceType": { "type": "oneOf", "values": ["CrowdStrike Host", "CrowdStrike Host Group"] } + } + }, + { + "type": "choiceChips", + "name": "status", + "label": "Status", + "isMulti": true, + "options": [ + { "value": "new", "label": "New" }, + { "value": "in_progress", "label": "In Progress" }, + { "value": "closed", "label": "Closed" }, + { "value": "reopened", "label": "Reopened" } + ] + } + ], + "metadata": [ + { "name": "composite_id", "displayName": "ID", "shape": "string", "role": "id", "visible": false }, + { "name": "name", "displayName": "Name", "shape": "string", "role": "label" }, + { "name": "description", "displayName": "Description", "shape": "string" }, + { "name": "status", "displayName": "Status", "shape": "string" }, + { "name": "severity_name", "displayName": "Severity", "shape": "string" }, + { "name": "severity", "displayName": "Severity Score", "shape": "number" }, + { "name": "confidence", "displayName": "Confidence", "shape": "number" }, + { "name": "product", "displayName": "Product", "shape": "string" }, + { "name": "type", "displayName": "Alert Type", "shape": "string" }, + { "name": "tactic", "displayName": "Tactic", "shape": "string" }, + { "name": "technique", "displayName": "Technique", "shape": "string" }, + { "name": "device.device_id", "displayName": "Device ID", "shape": "string", "visible": false }, + { "name": "device.hostname", "displayName": "Hostname", "shape": "string" }, + { "name": "device.platform_name", "displayName": "Platform", "shape": "string" }, + { "name": "filename", "displayName": "File Name", "shape": "string" }, + { "name": "filepath", "displayName": "File Path", "shape": "string" }, + { "name": "cmdline", "displayName": "Command Line", "shape": "string" }, + { "name": "user_name", "displayName": "User", "shape": "string" }, + { "name": "tags", "displayName": "Tags", "shape": "string" }, + { "name": "created_timestamp", "displayName": "Created", "shape": "date", "role": "timestamp" }, + { "name": "updated_timestamp", "displayName": "Last Updated", "shape": "date" }, + { "name": "first_behavior", "displayName": "First Behavior", "shape": "date" }, + { "name": "last_behavior", "displayName": "Last Behavior", "shape": "date" }, + { + "name": "detectionLatencySeconds", + "displayName": "Detection Latency", + "computed": true, + "valueExpression": "{{ ($['first_behavior'] && $['created_timestamp']) ? Math.max(0, (new Date($['created_timestamp']) - new Date($['first_behavior'])) / 1000) : null }}", + "shape": ["seconds", { "formatDuration": true }] + }, + { + "name": "responseLatencySeconds", + "displayName": "Response Latency", + "computed": true, + "valueExpression": "{{ ($['status'] === 'closed' && $['updated_timestamp'] && $['created_timestamp']) ? Math.max(0, (new Date($['updated_timestamp']) - new Date($['created_timestamp'])) / 1000) : null }}", + "shape": ["seconds", { "formatDuration": true }] + }, + { + "sourceId": "device.device_id", + "sourceType": "CrowdStrike Host", + "name": "device.hostname" + }, + { "pattern": ".*" } + ], + "timeframes": true +} diff --git a/plugins/CrowdStrike/v1/dataStreams/currentUser.json b/plugins/CrowdStrike/v1/dataStreams/currentUser.json new file mode 100644 index 00000000..36714d86 --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/currentUser.json @@ -0,0 +1,18 @@ +{ + "name": "currentUser", + "displayName": "Current User", + "description": "A minimal Falcon Hosts query, used only to verify the configured credentials can reach the API", + "tags": ["Security"], + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "/devices/queries/devices/v1", + "getArgs": [{ "key": "limit", "value": "1" }], + "paging": { "mode": "none" }, + "pathToData": "resources" + }, + "matches": "none", + "visibility": { "type": "hidden" }, + "metadata": [{ "pattern": ".*" }], + "timeframes": false +} diff --git a/plugins/CrowdStrike/v1/dataStreams/devices.json b/plugins/CrowdStrike/v1/dataStreams/devices.json new file mode 100644 index 00000000..2b7b10bf --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/devices.json @@ -0,0 +1,88 @@ +{ + "name": "devices", + "displayName": "Devices", + "description": "Host inventory with platform, sensor, network, group membership and policy assignment detail, one row per device", + "tags": ["Security", "Hosts"], + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "/devices/combined/devices/v1", + "getArgs": [ + { "key": "limit", "value": "500" }, + { + "key": "filter", + "value": "{{(function(){var sel=(typeof scope!=='undefined'?scope:[])||[];if(!sel.length)return null;var unwrap=function(v){return Array.isArray(v)?v[0]:v;};var dev=[],grp=[];sel.forEach(function(o){var id=unwrap(o.rawId);if(o.type==='CrowdStrike Host Group'){grp.push(id);}else{dev.push(id);}});var parts=[];if(dev.length)parts.push(\"device_id:[\"+dev.map(function(i){return \"'\"+i+\"'\";}).join(\",\")+\"]\");if(grp.length)parts.push(\"group_ids:[\"+grp.map(function(i){return \"'\"+i+\"'\";}).join(\",\")+\"]\");return parts.length?parts.join(\"+\"):null;})()}}" + } + ], + "paging": { + "mode": "offset", + "pageSize": { "realm": "queryArg", "path": "limit", "value": "500" }, + "offset": { + "mode": "row", + "rowCountIn": { "realm": "payloadArraySize", "path": "resources" }, + "base": 0 + }, + "out": { "realm": "queryArg", "path": "offset" } + }, + "pathToData": "resources", + "expandInnerObjects": true + }, + "matches": "none", + "ui": [ + { + "type": "objects", + "name": "scope", + "label": "Host or Host Group (optional)", + "matches": { + "sourceType": { "type": "oneOf", "values": ["CrowdStrike Host", "CrowdStrike Host Group"] } + } + } + ], + "metadata": [ + { "name": "device_id", "displayName": "Device ID", "shape": "string", "visible": false }, + { "name": "hostname", "displayName": "Hostname", "shape": "string", "role": "label" }, + { "name": "platform_name", "displayName": "Platform", "shape": "string" }, + { "name": "os_version", "displayName": "OS Version", "shape": "string" }, + { "name": "product_type_desc", "displayName": "Product Type", "shape": "string" }, + { "name": "agent_version", "displayName": "Sensor Version", "shape": "string" }, + { + "name": "status", + "displayName": "Containment Status", + "shape": [ + "state", + { + "map": { + "success": ["normal"], + "warning": ["containment_pending", "lift_containment_pending"], + "error": ["contained"] + } + } + ] + }, + { "name": "reduced_functionality_mode", "displayName": "Reduced Functionality Mode", "shape": "string" }, + { "name": "first_seen", "displayName": "First Seen", "shape": "date" }, + { "name": "last_seen", "displayName": "Last Seen", "shape": "date" }, + { "name": "local_ip", "displayName": "Local IP", "shape": "string" }, + { "name": "external_ip", "displayName": "External IP", "shape": "string" }, + { "name": "mac_address", "displayName": "MAC Address", "shape": "string" }, + { "name": "machine_domain", "displayName": "Domain", "shape": "string" }, + { "name": "site_name", "displayName": "Site", "shape": "string" }, + { "name": "serial_number", "displayName": "Serial Number", "shape": "string" }, + { "name": "system_manufacturer", "displayName": "Manufacturer", "shape": "string" }, + { "name": "system_product_name", "displayName": "Model", "shape": "string" }, + { "name": "group_ids", "displayName": "Host Group IDs", "shape": "string", "visible": false }, + { "name": "tags", "displayName": "Tags", "shape": "string" }, + { + "name": "device_policies.prevention.applied", + "displayName": "Prevention Policy Applied", + "shape": "boolean" + }, + { + "name": "device_policies.sensor_update.applied", + "displayName": "Sensor Update Policy Applied", + "shape": "boolean" + }, + { "pattern": ".*" } + ], + "timeframes": false +} diff --git a/plugins/CrowdStrike/v1/dataStreams/hostGroups.json b/plugins/CrowdStrike/v1/dataStreams/hostGroups.json new file mode 100644 index 00000000..52c4f838 --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/hostGroups.json @@ -0,0 +1,38 @@ +{ + "name": "hostGroups", + "displayName": "Host Groups", + "description": "All Host Groups (agencies) in the Falcon tenant", + "tags": ["Security"], + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "/devices/combined/host-groups/v1", + "getArgs": [{ "key": "limit", "value": "500" }], + "paging": { + "mode": "offset", + "pageSize": { "realm": "queryArg", "path": "limit", "value": "500" }, + "offset": { + "mode": "row", + "rowCountIn": { "realm": "payloadArraySize", "path": "resources" }, + "base": 0 + }, + "out": { "realm": "queryArg", "path": "offset" } + }, + "pathToData": "resources" + }, + "matches": "none", + "visibility": { "type": "hidden" }, + "metadata": [ + { "name": "id", "displayName": "ID", "shape": "string", "visible": false }, + { "name": "name", "displayName": "Name", "shape": "string", "role": "label" }, + { "name": "description", "displayName": "Description", "shape": "string" }, + { "name": "group_type", "displayName": "Group Type", "shape": "string" }, + { "name": "assignment_rule", "displayName": "Assignment Rule", "shape": "string" }, + { "name": "created_by", "displayName": "Created By", "shape": "string" }, + { "name": "created_timestamp", "displayName": "Created", "shape": "date" }, + { "name": "modified_by", "displayName": "Modified By", "shape": "string" }, + { "name": "modified_timestamp", "displayName": "Last Modified", "shape": "date" }, + { "pattern": ".*" } + ], + "timeframes": false +} diff --git a/plugins/CrowdStrike/v1/dataStreams/preventionPolicies.json b/plugins/CrowdStrike/v1/dataStreams/preventionPolicies.json new file mode 100644 index 00000000..af54ad07 --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/preventionPolicies.json @@ -0,0 +1,29 @@ +{ + "name": "preventionPolicies", + "displayName": "Prevention Policies", + "description": "Prevention policies assigned to a Host Group, one row per policy", + "tags": ["Security", "Policies"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "/policy/combined/prevention/v1", + "getArgs": [ + { "key": "limit", "value": "100" }, + { "key": "filter", "value": "groups:'{{object.rawId}}'" } + ], + "pathToData": "resources", + "expandInnerObjects": true + }, + "matches": { "sourceType": { "type": "oneOf", "values": ["CrowdStrike Host Group"] } }, + "metadata": [ + { "name": "id", "displayName": "ID", "shape": "string", "role": "id", "visible": false }, + { "name": "name", "displayName": "Policy Name", "shape": "string", "role": "label" }, + { "name": "description", "displayName": "Description", "shape": "string" }, + { "name": "platform_name", "displayName": "Platform", "shape": "string" }, + { "name": "enabled", "displayName": "Enabled", "shape": "boolean" }, + { "name": "created_timestamp", "displayName": "Created", "shape": "date" }, + { "name": "modified_timestamp", "displayName": "Last Modified", "shape": "date" }, + { "pattern": ".*" } + ], + "timeframes": false +} diff --git a/plugins/CrowdStrike/v1/dataStreams/sensorUpdatePolicies.json b/plugins/CrowdStrike/v1/dataStreams/sensorUpdatePolicies.json new file mode 100644 index 00000000..cf6596a7 --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/sensorUpdatePolicies.json @@ -0,0 +1,30 @@ +{ + "name": "sensorUpdatePolicies", + "displayName": "Sensor Update Policies", + "description": "Sensor update policies assigned to a Host Group, one row per policy", + "tags": ["Security", "Policies"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "/policy/combined/sensor-update/v2", + "getArgs": [ + { "key": "limit", "value": "100" }, + { "key": "filter", "value": "groups:'{{object.rawId}}'" } + ], + "pathToData": "resources", + "expandInnerObjects": true + }, + "matches": { "sourceType": { "type": "oneOf", "values": ["CrowdStrike Host Group"] } }, + "metadata": [ + { "name": "id", "displayName": "ID", "shape": "string", "role": "id", "visible": false }, + { "name": "name", "displayName": "Policy Name", "shape": "string", "role": "label" }, + { "name": "description", "displayName": "Description", "shape": "string" }, + { "name": "platform_name", "displayName": "Platform", "shape": "string" }, + { "name": "enabled", "displayName": "Enabled", "shape": "boolean" }, + { "name": "settings.build", "displayName": "Sensor Build", "shape": "string" }, + { "name": "created_timestamp", "displayName": "Created", "shape": "date" }, + { "name": "modified_timestamp", "displayName": "Last Modified", "shape": "date" }, + { "pattern": ".*" } + ], + "timeframes": false +} diff --git a/plugins/CrowdStrike/v1/dataStreams/sensorUsage.json b/plugins/CrowdStrike/v1/dataStreams/sensorUsage.json new file mode 100644 index 00000000..0c92de4f --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/sensorUsage.json @@ -0,0 +1,16 @@ +{ + "name": "sensorUsage", + "displayName": "Sensor Usage", + "description": "Weekly average of unique sensors seen reporting, account-wide", + "tags": ["Security", "Usage"], + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "/billing-dashboards-usage/aggregates/weekly-average/v1", + "pathToData": "resources", + "expandInnerObjects": true + }, + "matches": "none", + "metadata": [{ "pattern": ".*" }], + "timeframes": ["last30days", "thisQuarter", "lastQuarter"] +} diff --git a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json new file mode 100644 index 00000000..a1813b42 --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json @@ -0,0 +1,81 @@ +{ + "name": "vulnerabilities", + "displayName": "Vulnerabilities", + "description": "Open Spotlight vulnerabilities with CVE, severity and remediation detail, one row per vulnerability finding", + "tags": ["Security", "Vulnerabilities"], + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "/spotlight/combined/vulnerabilities/v1", + "getArgs": [ + { "key": "limit", "value": "200" }, + { "key": "facet", "value": "host_info" }, + { + "key": "filter", + "value": "{{(function(){var parts=[];var sel=(typeof scope!=='undefined'?scope:[])||[];var unwrap=function(v){return Array.isArray(v)?v[0]:v;};if(sel.length){var dev=[],grp=[];sel.forEach(function(o){var id=unwrap(o.rawId);if(o.type==='CrowdStrike Host Group'){grp.push(id);}else{dev.push(id);}});if(dev.length)parts.push(\"aid:[\"+dev.map(function(i){return \"'\"+i+\"'\";}).join(\",\")+\"]\");if(grp.length)parts.push(\"host_info.groups:[\"+grp.map(function(i){return \"'\"+i+\"'\";}).join(\",\")+\"]\");}var st=(typeof status!=='undefined'?status:[])||[];if(st.length)parts.push(\"status:[\"+st.map(function(s){return \"'\"+(s.value||s)+\"'\";}).join(\",\")+\"]\");return parts.length?parts.join(\"+\"):null;})()}}" + } + ], + "paging": { + "mode": "offset", + "pageSize": { "realm": "queryArg", "path": "limit", "value": "200" }, + "offset": { + "mode": "row", + "rowCountIn": { "realm": "payloadArraySize", "path": "resources" }, + "base": 0 + }, + "out": { "realm": "queryArg", "path": "offset" } + }, + "pathToData": "resources", + "expandInnerObjects": true + }, + "matches": "none", + "ui": [ + { + "type": "objects", + "name": "scope", + "label": "Host or Host Group (optional)", + "matches": { + "sourceType": { "type": "oneOf", "values": ["CrowdStrike Host", "CrowdStrike Host Group"] } + } + }, + { + "type": "choiceChips", + "name": "status", + "label": "Status", + "isMulti": true, + "options": [ + { "value": "open", "label": "Open" }, + { "value": "closed", "label": "Closed" }, + { "value": "reopen", "label": "Reopened" }, + { "value": "expired", "label": "Expired" } + ] + } + ], + "metadata": [ + { "name": "id", "displayName": "ID", "shape": "string", "role": "id", "visible": false }, + { "name": "aid", "displayName": "Device ID", "shape": "string", "visible": false }, + { "name": "cve.id", "displayName": "CVE", "shape": "string", "role": "label" }, + { "name": "cve.severity", "displayName": "CVE Severity", "shape": "string" }, + { "name": "cve.base_score", "displayName": "CVSS Score", "shape": "number" }, + { "name": "cve.exploit_status", "displayName": "Exploit Status", "shape": "string" }, + { "name": "cve.published_date", "displayName": "CVE Published", "shape": "date" }, + { "name": "status", "displayName": "Status", "shape": "string" }, + { "name": "host_info.hostname", "displayName": "Hostname", "shape": "string" }, + { "name": "host_info.platform", "displayName": "Platform", "shape": "string" }, + { "name": "host_info.local_ip", "displayName": "Local IP", "shape": "string" }, + { "name": "app.product_name_version", "displayName": "Affected Product", "shape": "string" }, + { "name": "created_timestamp", "displayName": "First Found", "shape": "date", "role": "timestamp" }, + { "name": "updated_timestamp", "displayName": "Last Updated", "shape": "date" }, + { "name": "closed_timestamp", "displayName": "Closed", "shape": "date" }, + { + "name": "daysOpen", + "displayName": "Days Open", + "computed": true, + "valueExpression": "{{ $['created_timestamp'] ? Math.floor((Date.now() - new Date($['created_timestamp'])) / 86400000) : null }}", + "shape": "number" + }, + { "sourceId": "aid", "sourceType": "CrowdStrike Host", "name": "host_info.hostname" }, + { "pattern": ".*" } + ], + "timeframes": false +} diff --git a/plugins/CrowdStrike/v1/defaultContent/hostGroupPerspective.dash.json b/plugins/CrowdStrike/v1/defaultContent/hostGroupPerspective.dash.json new file mode 100644 index 00000000..6f34b365 --- /dev/null +++ b/plugins/CrowdStrike/v1/defaultContent/hostGroupPerspective.dash.json @@ -0,0 +1,812 @@ +{ + "name": "Host Group", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": ["{{variables.[Host Group]}}"], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "f981efd7-e832-4a4a-9c4f-3d1697673732", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Hosts", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[devices]}}", + "name": "devices", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host Group]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Host Groups]}}" + } + }, + "group": { "by": [], "aggregate": [{ "type": "count" }] } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + } + } + }, + { + "i": "b6fad726-680e-4998-93ca-d8df9117560b", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Prevention Policy Applied", + "description": "Hosts with a prevention policy applied", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[devices]}}", + "name": "devices", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host Group]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Host Groups]}}" + } + }, + "filter": { + "multiOperation": "and", + "filters": [ + { "column": "device_policies.prevention.applied", "operation": "equals", "value": "true" } + ] + }, + "group": { "by": [], "aggregate": [{ "type": "count" }] } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + } + } + }, + { + "i": "4d4fd992-1fca-4f5d-88fc-be3b8796c202", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Sensor Update Policy Applied", + "description": "Hosts with a sensor update policy applied", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[devices]}}", + "name": "devices", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host Group]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Host Groups]}}" + } + }, + "filter": { + "multiOperation": "and", + "filters": [ + { + "column": "device_policies.sensor_update.applied", + "operation": "equals", + "value": "true" + } + ] + }, + "group": { "by": [], "aggregate": [{ "type": "count" }] } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + } + } + }, + { + "i": "251a78d2-e3f8-456f-9b41-1f5e60cc95db", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Open Vulnerabilities", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[vulnerabilities]}}", + "name": "vulnerabilities", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host Group]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Host Groups]}}" + } + }, + "filter": { + "multiOperation": "and", + "filters": [{ "column": "status", "operation": "equals", "value": "open" }] + }, + "group": { "by": [], "aggregate": [{ "type": "count" }] } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + } + } + }, + { + "i": "7a3911ff-6ab8-4784-ba84-8b588853f49b", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "OS / Platform Breakdown", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[devices]}}", + "name": "devices", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host Group]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Host Groups]}}" + } + }, + "group": { + "by": [["platform_name", "uniqueValues"]], + "aggregate": [{ "type": "count" }] + } + }, + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count", + "labelColumn": "platform_name_uniqueValues", + "showValuesAsPercentage": true, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "4a955419-a6f1-4c80-93dc-36fd5970f5a8", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Sensor Version Distribution", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[devices]}}", + "name": "devices", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host Group]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Host Groups]}}" + } + }, + "group": { + "by": [["agent_version", "uniqueValues"]], + "aggregate": [{ "type": "count" }] + } + }, + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count", + "labelColumn": "agent_version_uniqueValues", + "showValuesAsPercentage": true, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "2dbd1817-b505-466d-ae56-9dcd5a639572", + "x": 0, + "y": 5, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Prevention Policies", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[preventionPolicies]}}", + "name": "preventionPolicies", + "pluginConfigId": "{{configId}}" + }, + "scope": { + "scope": "{{scopes.[Host Groups]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Host Group]}}" + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": ["name", "platform_name", "enabled", "description", "modified_timestamp"], + "hiddenColumns": ["id", "created_timestamp"] + } + } + } + } + }, + { + "i": "269c103b-cd25-4d0e-bd48-4adf52925f59", + "x": 2, + "y": 5, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Sensor Update Policies", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[sensorUpdatePolicies]}}", + "name": "sensorUpdatePolicies", + "pluginConfigId": "{{configId}}" + }, + "scope": { + "scope": "{{scopes.[Host Groups]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Host Group]}}" + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "name", + "platform_name", + "enabled", + "settings.build", + "modified_timestamp" + ], + "hiddenColumns": ["id", "description", "created_timestamp"] + } + } + } + } + }, + { + "i": "5f770e25-522c-45a7-9a30-00a61d60bf8f", + "x": 0, + "y": 9, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Alerts", + "description": "Alerts created within the dashboard timeframe", + "activePluginConfigIds": ["{{configId}}"], + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[alerts]}}", + "name": "alerts", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host Group]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Host Groups]}}" + } + }, + "group": { "by": [], "aggregate": [{ "type": "count" }] } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + } + } + }, + { + "i": "58019020-2915-4a38-b2d4-aa9dcc543683", + "x": 1, + "y": 9, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Avg Detection Latency", + "description": "Average time between first behavior and alert creation", + "activePluginConfigIds": ["{{configId}}"], + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[alerts]}}", + "name": "alerts", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host Group]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Host Groups]}}" + } + }, + "group": { + "by": [], + "aggregate": [{ "type": "mean", "names": ["detectionLatencySeconds"] }] + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "detectionLatencySeconds_mean", + "comparisonColumn": "none" + } + } + } + } + }, + { + "i": "057ad2f6-b966-4db4-a7b7-89aa91ff1443", + "x": 2, + "y": 9, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Avg Response Latency", + "description": "Average time between alert creation and closure", + "activePluginConfigIds": ["{{configId}}"], + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[alerts]}}", + "name": "alerts", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host Group]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Host Groups]}}" + } + }, + "group": { + "by": [], + "aggregate": [{ "type": "mean", "names": ["responseLatencySeconds"] }] + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "responseLatencySeconds_mean", + "comparisonColumn": "none" + } + } + } + } + }, + { + "i": "ba1b75ab-b5b2-4399-82b1-60e83a2f5933", + "x": 0, + "y": 11, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Alerts by Severity", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[alerts]}}", + "name": "alerts", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host Group]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Host Groups]}}" + } + }, + "group": { + "by": [["severity_name", "uniqueValues"]], + "aggregate": [{ "type": "count" }] + } + }, + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count", + "labelColumn": "severity_name_uniqueValues", + "showValuesAsPercentage": true, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "7dd1e2c3-2fd5-44f6-b4bd-8906734381c6", + "x": 2, + "y": 11, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Alerts by Status", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[alerts]}}", + "name": "alerts", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host Group]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Host Groups]}}" + } + }, + "group": { + "by": [["status", "uniqueValues"]], + "aggregate": [{ "type": "count" }] + }, + "sort": { "by": [["count", "desc"]] } + }, + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "status_uniqueValues", + "yAxisData": ["count"], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "Alerts", + "showXAxisLabel": false, + "showYAxisLabel": true, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": true, + "grouping": false, + "range": { "type": "auto" } + } + } + } + } + }, + { + "i": "1f63766e-2731-4b7a-86f8-212928ffb45f", + "x": 0, + "y": 14, + "w": 4, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Recent Alerts", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[alerts]}}", + "name": "alerts", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host Group]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Host Groups]}}" + } + }, + "sort": { "by": [["created_timestamp", "desc"]], "top": 15 } + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "name", + "severity_name", + "status", + "device.hostname", + "tactic", + "technique", + "created_timestamp" + ], + "hiddenColumns": [ + "composite_id", + "device.device_id", + "device.platform_name", + "filename", + "filepath", + "cmdline", + "user_name", + "tags", + "description", + "product", + "type", + "confidence", + "severity", + "updated_timestamp", + "first_behavior", + "last_behavior", + "detectionLatencySeconds", + "responseLatencySeconds" + ] + } + } + } + } + }, + { + "i": "5f9f216f-f344-4450-8d07-ed382e3bf9d7", + "x": 0, + "y": 18, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Vulnerabilities by Severity", + "description": "Open vulnerabilities only", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[vulnerabilities]}}", + "name": "vulnerabilities", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host Group]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Host Groups]}}" + } + }, + "filter": { + "multiOperation": "and", + "filters": [{ "column": "status", "operation": "equals", "value": "open" }] + }, + "group": { + "by": [["cve.severity", "uniqueValues"]], + "aggregate": [{ "type": "count" }] + } + }, + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count", + "labelColumn": "cve.severity_uniqueValues", + "showValuesAsPercentage": true, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "cd0b6171-831f-4803-8de4-2718499dbfb9", + "x": 2, + "y": 18, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Top Vulnerable Hosts", + "description": "Open vulnerabilities with the highest CVSS score, in this group", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[vulnerabilities]}}", + "name": "vulnerabilities", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host Group]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Host Groups]}}" + } + }, + "filter": { + "multiOperation": "and", + "filters": [{ "column": "status", "operation": "equals", "value": "open" }] + }, + "sort": { "by": [["cve.base_score", "desc"]], "top": 10 } + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "cve.id", + "cve.severity", + "cve.base_score", + "host_info.hostname", + "app.product_name_version", + "created_timestamp" + ], + "hiddenColumns": [ + "id", + "aid", + "host_info.platform", + "host_info.local_ip", + "cve.exploit_status", + "cve.published_date", + "status", + "updated_timestamp", + "closed_timestamp", + "daysOpen" + ] + } + } + } + } + }, + { + "i": "0aff3eaf-1e0b-413b-bd5b-83c93012f193", + "x": 0, + "y": 22, + "w": 4, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Member Devices", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "variables": ["{{variables.[Host Group]}}"], + "dataStream": { + "id": "{{dataStreams.[devices]}}", + "name": "devices", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host Group]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Host Groups]}}" + } + }, + "sort": { "by": [["last_seen", "desc"]] } + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "hostname", + "platform_name", + "os_version", + "agent_version", + "status", + "local_ip", + "last_seen" + ], + "hiddenColumns": [ + "device_id", + "group_ids", + "mac_address", + "external_ip", + "machine_domain", + "serial_number", + "system_manufacturer", + "system_product_name", + "first_seen", + "tags", + "site_name", + "product_type_desc", + "reduced_functionality_mode", + "device_policies.prevention.applied", + "device_policies.sensor_update.applied" + ] + } + } + } + } + } + ] + } +} diff --git a/plugins/CrowdStrike/v1/defaultContent/hostPerspective.dash.json b/plugins/CrowdStrike/v1/defaultContent/hostPerspective.dash.json new file mode 100644 index 00000000..8f97fbc9 --- /dev/null +++ b/plugins/CrowdStrike/v1/defaultContent/hostPerspective.dash.json @@ -0,0 +1,231 @@ +{ + "name": "Host", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": ["{{variables.[Host]}}"], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "5a326895-b8cd-4f69-9859-58207ff7fe38", + "x": 0, + "y": 0, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Device Properties", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "variables": ["{{variables.[Host]}}"], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "scope": { + "scope": "{{scopes.[Hosts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Host]}}" + }, + "visualisation": { + "type": "data-stream-table", + "config": { "data-stream-table": { "transpose": true } } + } + } + }, + { + "i": "a5ce7ce3-c43c-4713-9b55-468a6abbd363", + "x": 2, + "y": 0, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Alert Volume Over Time", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "variables": ["{{variables.[Host]}}"], + "dataStream": { + "id": "{{dataStreams.[alerts]}}", + "name": "alerts", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Hosts]}}" + } + }, + "group": { + "by": [["created_timestamp", "byDay"]], + "aggregate": [{ "type": "count" }] + }, + "sort": { "by": [["created_timestamp_byDay", "asc"]] } + }, + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "created_timestamp_byDay", + "yAxisData": ["count"], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "Alerts", + "showXAxisLabel": false, + "showYAxisLabel": true, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { "type": "auto" } + } + } + } + } + }, + { + "i": "9dd38206-119e-42f7-8859-2465170f4c77", + "x": 0, + "y": 4, + "w": 4, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Alert Timeline", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "variables": ["{{variables.[Host]}}"], + "dataStream": { + "id": "{{dataStreams.[alerts]}}", + "name": "alerts", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Hosts]}}" + } + }, + "sort": { "by": [["created_timestamp", "desc"]], "top": 20 } + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "name", + "severity_name", + "status", + "tactic", + "technique", + "filename", + "user_name", + "created_timestamp" + ], + "hiddenColumns": [ + "composite_id", + "device.device_id", + "device.hostname", + "device.platform_name", + "filepath", + "cmdline", + "tags", + "description", + "product", + "type", + "confidence", + "severity", + "updated_timestamp", + "first_behavior", + "last_behavior", + "detectionLatencySeconds", + "responseLatencySeconds" + ] + } + } + } + } + }, + { + "i": "98877648-d423-4ad4-8aa7-c7d4ffc28d32", + "x": 0, + "y": 8, + "w": 4, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Vulnerabilities", + "description": "Open vulnerabilities for this device", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "variables": ["{{variables.[Host]}}"], + "dataStream": { + "id": "{{dataStreams.[vulnerabilities]}}", + "name": "vulnerabilities", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Host]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Hosts]}}" + } + }, + "filter": { + "multiOperation": "and", + "filters": [{ "column": "status", "operation": "equals", "value": "open" }] + }, + "sort": { "by": [["cve.base_score", "desc"]] } + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "cve.id", + "cve.severity", + "cve.base_score", + "app.product_name_version", + "cve.exploit_status", + "created_timestamp", + "daysOpen" + ], + "hiddenColumns": [ + "id", + "aid", + "host_info.hostname", + "host_info.platform", + "host_info.local_ip", + "cve.published_date", + "status", + "updated_timestamp", + "closed_timestamp" + ] + } + } + } + } + } + ] + } +} diff --git a/plugins/CrowdStrike/v1/defaultContent/manifest.json b/plugins/CrowdStrike/v1/defaultContent/manifest.json new file mode 100644 index 00000000..04688a6c --- /dev/null +++ b/plugins/CrowdStrike/v1/defaultContent/manifest.json @@ -0,0 +1,7 @@ +{ + "items": [ + { "name": "overview", "type": "dashboard" }, + { "name": "hostGroupPerspective", "type": "dashboard" }, + { "name": "hostPerspective", "type": "dashboard" } + ] +} diff --git a/plugins/CrowdStrike/v1/defaultContent/overview.dash.json b/plugins/CrowdStrike/v1/defaultContent/overview.dash.json new file mode 100644 index 00000000..bb0bcb8a --- /dev/null +++ b/plugins/CrowdStrike/v1/defaultContent/overview.dash.json @@ -0,0 +1,437 @@ +{ + "name": "Overview", + "schemaVersion": "1.5", + "timeframe": "last7days", + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "79e6e308-ec60-435d-9530-a21ddf4d87e7", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Total Hosts", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "dataStream": { + "id": "{{dataStreams.[devices]}}", + "name": "devices", + "pluginConfigId": "{{configId}}", + "group": { "by": [], "aggregate": [{ "type": "count" }] } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + } + } + }, + { + "i": "2d58c72d-1007-4ceb-9545-3b9e676eed1e", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Active Alerts", + "description": "Alerts not yet closed, created within the dashboard timeframe", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[alerts]}}", + "name": "alerts", + "pluginConfigId": "{{configId}}", + "filter": { + "multiOperation": "and", + "filters": [{ "column": "status", "operation": "notequals", "value": "closed" }] + }, + "group": { "by": [], "aggregate": [{ "type": "count" }] } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + } + } + }, + { + "i": "772c85e8-9199-4db4-8c86-cb9a4a21182d", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Open Critical/High Vulnerabilities", + "description": "Open vulnerabilities with a CVSS base score of 7.0 or above", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "dataStream": { + "id": "{{dataStreams.[vulnerabilities]}}", + "name": "vulnerabilities", + "pluginConfigId": "{{configId}}", + "filter": { + "multiOperation": "and", + "filters": [ + { "column": "status", "operation": "equals", "value": "open" }, + { "column": "cve.base_score", "operation": "greaterthan", "value": "6.9" } + ] + }, + "group": { "by": [], "aggregate": [{ "type": "count" }] } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + } + } + }, + { + "i": "6dc453e5-358f-439f-9a15-36a06444d52d", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Contained Hosts", + "description": "Hosts currently network-contained", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "dataStream": { + "id": "{{dataStreams.[devices]}}", + "name": "devices", + "pluginConfigId": "{{configId}}", + "filter": { + "multiOperation": "and", + "filters": [{ "column": "status", "operation": "equals", "value": "contained" }] + }, + "group": { "by": [], "aggregate": [{ "type": "count" }] } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + } + } + }, + { + "i": "497a187f-7f06-4395-8ff1-2ba3d2a9a2f6", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Hosts by Platform", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "dataStream": { + "id": "{{dataStreams.[devices]}}", + "name": "devices", + "pluginConfigId": "{{configId}}", + "group": { + "by": [["platform_name", "uniqueValues"]], + "aggregate": [{ "type": "count" }] + } + }, + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count", + "labelColumn": "platform_name_uniqueValues", + "showValuesAsPercentage": true, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "d34b48d7-a07a-434a-a86c-e94cf26beaa6", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Alerts by Severity", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[alerts]}}", + "name": "alerts", + "pluginConfigId": "{{configId}}", + "group": { + "by": [["severity_name", "uniqueValues"]], + "aggregate": [{ "type": "count" }] + } + }, + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count", + "labelColumn": "severity_name_uniqueValues", + "showValuesAsPercentage": true, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "bd32d0d4-022a-4c24-8683-f29c2d473cc3", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Alerts by Status", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[alerts]}}", + "name": "alerts", + "pluginConfigId": "{{configId}}", + "group": { + "by": [["status", "uniqueValues"]], + "aggregate": [{ "type": "count" }] + }, + "sort": { "by": [["count", "desc"]] } + }, + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "status_uniqueValues", + "yAxisData": ["count"], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "Alerts", + "showXAxisLabel": false, + "showYAxisLabel": true, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": true, + "grouping": false, + "range": { "type": "auto" } + } + } + } + } + }, + { + "i": "8cb63cf7-a111-438b-b114-bb3a6389b025", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Vulnerabilities by Severity", + "description": "Open vulnerabilities only", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "dataStream": { + "id": "{{dataStreams.[vulnerabilities]}}", + "name": "vulnerabilities", + "pluginConfigId": "{{configId}}", + "filter": { + "multiOperation": "and", + "filters": [{ "column": "status", "operation": "equals", "value": "open" }] + }, + "group": { + "by": [["cve.severity", "uniqueValues"]], + "aggregate": [{ "type": "count" }] + } + }, + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count", + "labelColumn": "cve.severity_uniqueValues", + "showValuesAsPercentage": true, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "7f0edf44-3986-4894-9225-80d025b6ec45", + "x": 0, + "y": 8, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Top Vulnerabilities", + "description": "Open vulnerabilities with the highest CVSS score, account-wide", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "dataStream": { + "id": "{{dataStreams.[vulnerabilities]}}", + "name": "vulnerabilities", + "pluginConfigId": "{{configId}}", + "filter": { + "multiOperation": "and", + "filters": [{ "column": "status", "operation": "equals", "value": "open" }] + }, + "sort": { "by": [["cve.base_score", "desc"]], "top": 10 } + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "cve.id", + "cve.severity", + "cve.base_score", + "host_info.hostname", + "host_info.platform", + "cve.exploit_status", + "status", + "created_timestamp" + ], + "hiddenColumns": [ + "id", + "aid", + "host_info.local_ip", + "app.product_name_version", + "cve.published_date", + "updated_timestamp", + "closed_timestamp", + "daysOpen" + ] + } + } + } + } + }, + { + "i": "fc1918d4-3d62-4fe9-aa54-e206e12b1130", + "x": 2, + "y": 8, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Device Inventory", + "description": "Most recently seen hosts, account-wide", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "none", + "dataStream": { + "id": "{{dataStreams.[devices]}}", + "name": "devices", + "pluginConfigId": "{{configId}}", + "sort": { "by": [["last_seen", "desc"]], "top": 20 } + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "hostname", + "platform_name", + "os_version", + "agent_version", + "status", + "last_seen", + "site_name" + ], + "hiddenColumns": [ + "device_id", + "group_ids", + "mac_address", + "external_ip", + "machine_domain", + "serial_number", + "system_manufacturer", + "system_product_name", + "first_seen", + "tags", + "product_type_desc", + "reduced_functionality_mode", + "device_policies.prevention.applied", + "device_policies.sensor_update.applied" + ] + } + } + } + } + }, + { + "i": "34f983b0-6cc3-4091-8e04-1870ade28cda", + "x": 0, + "y": 12, + "w": 4, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Sensor Usage", + "description": "Weekly average of unique sensors seen reporting", + "activePluginConfigIds": ["{{configId}}"], + "timeframe": "last30days", + "dataStream": { + "id": "{{dataStreams.[sensorUsage]}}", + "name": "sensorUsage", + "pluginConfigId": "{{configId}}" + }, + "visualisation": { + "type": "data-stream-table", + "config": { "data-stream-table": { "transpose": false } } + } + } + } + ] + } +} diff --git a/plugins/CrowdStrike/v1/defaultContent/scopes.json b/plugins/CrowdStrike/v1/defaultContent/scopes.json new file mode 100644 index 00000000..aebb5dd4 --- /dev/null +++ b/plugins/CrowdStrike/v1/defaultContent/scopes.json @@ -0,0 +1,26 @@ +[ + { + "name": "Host Groups", + "matches": { + "sourceType": { "type": "oneOf", "values": ["CrowdStrike Host Group"] } + }, + "variable": { + "name": "Host Group", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Hosts", + "matches": { + "sourceType": { "type": "oneOf", "values": ["CrowdStrike Host"] } + }, + "variable": { + "name": "Host", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + } +] diff --git a/plugins/CrowdStrike/v1/docs/README.md b/plugins/CrowdStrike/v1/docs/README.md new file mode 100644 index 00000000..ae137614 --- /dev/null +++ b/plugins/CrowdStrike/v1/docs/README.md @@ -0,0 +1,61 @@ +Monitor [CrowdStrike Falcon](https://www.crowdstrike.com) host coverage, detections & incidents, vulnerabilities, and policy compliance in SquaredUp, via the [CrowdStrike Falcon API](https://developer.crowdstrike.com). + +## Setup + +You will need a CrowdStrike Falcon **API client** with read scopes for Hosts, Alerts, Spotlight Vulnerabilities, and Sensor Update/Prevention Policies. + +1. Sign in to the [Falcon console](https://falcon.crowdstrike.com). +2. Go to **Support and resources → API clients and keys** and click **Add new API client**. +3. Give the client a name, and grant it **Read** scope for: **Hosts**, **Host Groups**, **Alerts**, **Spotlight Vulnerabilities**, **Sensor Update Policies**, **Prevention Policies**, and **Sensor Usage**. +4. Copy the generated **Client ID** and **Client Secret** — the secret is shown only once. +5. Note the **Cloud** your Falcon tenant runs in (shown on the same page, e.g. `api.us-2.crowdstrike.com`) and paste the three values into the fields below. + +## Configuration fields + +| Field | What it is | Where to find it | Required | +| ----- | ---------- | ----------------- | -------- | +| **CrowdStrike Cloud** | The regional API host your Falcon tenant is hosted in. | **Support and resources → API clients and keys** in the Falcon console. | Yes | +| **Client ID** | Identifies the API client used to authenticate requests. | **Support and resources → API clients and keys**. | Yes | +| **Client Secret** | Authenticates the API client via OAuth2 client-credentials. | Shown once when the API client is created. | Yes | + +On save, the plugin validates the credentials with a minimal Hosts query; an invalid Client ID/Secret, wrong Cloud region, or missing scope fails setup with an authentication error. + +## What this plugin monitors + +- **Host coverage** — enrolled endpoints, platform/OS breakdown, sensor version, containment status, and Host Group membership. +- **Detections and incidents** — a unified view of Falcon Alerts (severity, status, tactic/technique, affected host), with computed detection and response latency. +- **Vulnerabilities** — open Spotlight findings per host, with CVE, CVSS score, exploit status and days-open. +- **Policy coverage** — Prevention and Sensor Update policies assigned to each Host Group. +- **Sensor usage** — account-wide weekly average of unique sensors reporting. + +The out-of-the-box dashboards include an account-wide **Overview**, a **Host Group** perspective (select a Host Group/agency to see its coverage, alerts, vulnerabilities and policy compliance), and a **Host** perspective for a single device. + +## Data streams + +- **Devices** — host inventory (platform, OS, sensor version, network, group membership, policy applied state), account-wide or scoped to a Host or Host Group. +- **Alerts** — detections and incidents from the unified Falcon Alerts API, account-wide or scoped to a Host or Host Group, with a Status filter. +- **Vulnerabilities** — open Spotlight vulnerability findings, account-wide or scoped to a Host or Host Group, with a Status filter. +- **Prevention Policies** — Prevention policies assigned to a Host Group. +- **Sensor Update Policies** — Sensor Update policies assigned to a Host Group. +- **Sensor Usage** — weekly average unique sensor count, account-wide. + +## What gets indexed + +| Object type | API source | Represents | +| ----------- | ---------- | ---------- | +| **CrowdStrike Host Group** | `GET /devices/combined/host-groups/v1` | A Falcon Host Group (used here to represent an agency). | +| **CrowdStrike Host** | `GET /devices/combined/devices/v1` | An enrolled endpoint (workstation, server, etc.). | + +**Relationships:** each Host's `group_ids` property references the Host Group(s) it belongs to (a host can belong to more than one group). + +## Known limitations + +> ⚠️ **This build has not been tested against a live CrowdStrike tenant.** It was authored from CrowdStrike's published API documentation and an endpoint reference list, but no CrowdStrike API credentials were available during development, so no data stream has been exercised against real data and no import has been run. Every field name, filter expression, and response shape below should be verified — and adjusted if needed — against a real Falcon tenant before this plugin is relied on. +- **Incidents API not used** — the legacy `/incidents/*` API is deprecated (removed as of March 2026); this plugin uses the unified `/alerts/*` API for both detections and incidents. +- **Time-to-containment is not surfaced** — CrowdStrike's API exposes containment actions but not a completed-containment timestamp, so response-latency here is measured as alert `created` → `updated` (when closed), not true time-to-containment. +- **Host Group scoping for Alerts and Vulnerabilities is unverified** — filtering these by Host Group assumes the alert/vulnerability payload embeds the host's group membership (`device.groups` / `host_info.groups`); if CrowdStrike's response doesn't expose that field, Host-Group-scoped Alerts/Vulnerabilities tiles will need an alternate filter approach. +- **Sensor Usage column names are unverified** — the billing-dashboards-usage endpoint's exact response shape wasn't confirmed against live data; the stream surfaces whatever columns the API returns via a catch-all, so the default table tile may need column renaming once real data is seen. +- **Dashboard filters use assumed raw values** — the Overview KPI/donut tiles filter on assumed raw API values (alert `status` of `new`/`in_progress`/`closed`/`reopened`, device `status` of `contained`, a CVSS-score threshold as a proxy for "Critical/High" severity); these should be checked against real payloads and adjusted if CrowdStrike's actual values differ. +- **Account-wide tiles on unscoped consolidated streams** (Devices/Alerts/Vulnerabilities on the Overview dashboard) omit the scope binding entirely, per the documented pattern for an empty selection — if this throws a `nodeIds` error on a live tenant, the fix is to bind an explicit empty selection instead. +- **Read-only** — the plugin never creates, modifies, or deletes anything in CrowdStrike Falcon. +- **Requires a paid Falcon subscription with API access** — a trial account may not expose all the scopes this plugin requests (Hosts, Host Groups, Alerts, Spotlight Vulnerabilities, Sensor Update Policies, Prevention Policies, Sensor Usage). diff --git a/plugins/CrowdStrike/v1/icon.svg b/plugins/CrowdStrike/v1/icon.svg new file mode 100644 index 00000000..e05fdf5b --- /dev/null +++ b/plugins/CrowdStrike/v1/icon.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/plugins/CrowdStrike/v1/indexDefinitions/default.json b/plugins/CrowdStrike/v1/indexDefinitions/default.json new file mode 100644 index 00000000..cb2cfd5c --- /dev/null +++ b/plugins/CrowdStrike/v1/indexDefinitions/default.json @@ -0,0 +1,38 @@ +{ + "steps": [ + { + "name": "hostGroups", + "dataStream": { "name": "hostGroups", "config": {} }, + "timeframe": "none", + "objectMapping": { + "id": "id", + "name": "name", + "type": { "value": "CrowdStrike Host Group" }, + "properties": ["description", "group_type", "assignment_rule", "created_timestamp", "modified_timestamp"] + } + }, + { + "name": "devices", + "dataStream": { "name": "devices", "config": {} }, + "timeframe": "none", + "objectMapping": { + "id": "device_id", + "name": "hostname", + "type": { "value": "CrowdStrike Host" }, + "properties": [ + "platform_name", + "os_version", + "product_type_desc", + "agent_version", + "status", + "first_seen", + "last_seen", + "local_ip", + "external_ip", + "site_name", + "group_ids" + ] + } + } + ] +} diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json new file mode 100644 index 00000000..8247ab39 --- /dev/null +++ b/plugins/CrowdStrike/v1/metadata.json @@ -0,0 +1,34 @@ +{ + "name": "crowdstrike", + "displayName": "CrowdStrike", + "version": "1.0.0", + "author": { "name": "@JackTSquppy", "type": "community" }, + "description": "Monitor CrowdStrike Falcon host coverage, detections & incidents, vulnerabilities, and policy compliance in SquaredUp.", + "category": "Security", + "type": "hybrid", + "schemaVersion": "2.1", + "importNotSupported": false, + "restrictedToPlatforms": [], + "keywords": ["crowdstrike", "falcon", "edr", "endpoint", "security", "detections", "vulnerabilities", "host group"], + "objectTypes": ["CrowdStrike Host Group", "CrowdStrike Host"], + "links": [ + { + "category": "documentation", + "url": "https://github.com/squaredup/plugins/blob/main/plugins/CrowdStrike/v1/docs/README.md", + "label": "Help adding this plugin" + } + ], + "base": { + "plugin": "WebAPI", + "majorVersion": "1", + "config": { + "baseUrl": "{{cloudRegion}}", + "authMode": "oauth2", + "oauth2GrantType": "clientCredentials", + "oauth2TokenUrl": "{{cloudRegion}}/oauth2/token", + "oauth2ClientId": "{{clientId}}", + "oauth2ClientSecret": "{{clientSecret}}", + "oauth2ClientSecretLocationDuringAuth": "body" + } + } +} diff --git a/plugins/CrowdStrike/v1/ui.json b/plugins/CrowdStrike/v1/ui.json new file mode 100644 index 00000000..c8b2a8b2 --- /dev/null +++ b/plugins/CrowdStrike/v1/ui.json @@ -0,0 +1,32 @@ +[ + { + "type": "autocomplete", + "name": "cloudRegion", + "label": "CrowdStrike Cloud", + "help": "The CrowdStrike cloud your Falcon tenant is hosted in. Shown on the [API Clients and Keys](https://falcon.crowdstrike.com/support/api-clients-and-keys) page as the base URL.", + "validation": { "required": true }, + "data": { + "source": "fixed", + "values": [ + { "value": "https://api.crowdstrike.com", "label": "US-1" }, + { "value": "https://api.us-2.crowdstrike.com", "label": "US-2" }, + { "value": "https://api.eu-1.crowdstrike.com", "label": "EU-1" }, + { "value": "https://api.laggar.gcw.crowdstrike.com", "label": "US-GOV-1" } + ] + } + }, + { + "type": "text", + "name": "clientId", + "label": "Client ID", + "help": "The Client ID of your CrowdStrike API client. [More info](https://falcon.crowdstrike.com/support/api-clients-and-keys)", + "validation": { "required": true } + }, + { + "type": "password", + "name": "clientSecret", + "label": "Client Secret", + "help": "The Client Secret of your CrowdStrike API client. [More info](https://falcon.crowdstrike.com/support/api-clients-and-keys)", + "validation": { "required": true } + } +] From a60125ff882aaca33b1f64450917fc9caec10787 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Mon, 5 Oct 2026 14:27:37 -0400 Subject: [PATCH 02/27] CrowdStrike: restrict cloud region to a single selection The cloudRegion autocomplete defaulted to multi-select, so selecting several regions produced a malformed baseUrl and authentication failed. Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/ui.json | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/CrowdStrike/v1/ui.json b/plugins/CrowdStrike/v1/ui.json index c8b2a8b2..bb295153 100644 --- a/plugins/CrowdStrike/v1/ui.json +++ b/plugins/CrowdStrike/v1/ui.json @@ -5,6 +5,7 @@ "label": "CrowdStrike Cloud", "help": "The CrowdStrike cloud your Falcon tenant is hosted in. Shown on the [API Clients and Keys](https://falcon.crowdstrike.com/support/api-clients-and-keys) page as the base URL.", "validation": { "required": true }, + "isMulti": false, "data": { "source": "fixed", "values": [ From 6805a8f958cd5b97790124920468bcbe09a091b3 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Mon, 5 Oct 2026 15:43:35 -0400 Subject: [PATCH 03/27] CrowdStrike: handle cloudRegion autocomplete value being an object The token URL rendered as "[object Object]/oauth2/token" (ERR_INVALID_URL). Resolve .value when the autocomplete yields an object, and set a default. Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/metadata.json | 4 ++-- plugins/CrowdStrike/v1/ui.json | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json index 8247ab39..0218bd67 100644 --- a/plugins/CrowdStrike/v1/metadata.json +++ b/plugins/CrowdStrike/v1/metadata.json @@ -22,10 +22,10 @@ "plugin": "WebAPI", "majorVersion": "1", "config": { - "baseUrl": "{{cloudRegion}}", + "baseUrl": "{{ typeof cloudRegion === 'object' ? cloudRegion.value : cloudRegion }}", "authMode": "oauth2", "oauth2GrantType": "clientCredentials", - "oauth2TokenUrl": "{{cloudRegion}}/oauth2/token", + "oauth2TokenUrl": "{{ typeof cloudRegion === 'object' ? cloudRegion.value : cloudRegion }}/oauth2/token", "oauth2ClientId": "{{clientId}}", "oauth2ClientSecret": "{{clientSecret}}", "oauth2ClientSecretLocationDuringAuth": "body" diff --git a/plugins/CrowdStrike/v1/ui.json b/plugins/CrowdStrike/v1/ui.json index bb295153..6e603538 100644 --- a/plugins/CrowdStrike/v1/ui.json +++ b/plugins/CrowdStrike/v1/ui.json @@ -6,6 +6,8 @@ "help": "The CrowdStrike cloud your Falcon tenant is hosted in. Shown on the [API Clients and Keys](https://falcon.crowdstrike.com/support/api-clients-and-keys) page as the base URL.", "validation": { "required": true }, "isMulti": false, + "allowCustomValues": false, + "defaultValue": "https://api.crowdstrike.com", "data": { "source": "fixed", "values": [ From c628297021ff011f3c938722e048efa138e9674d Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Mon, 5 Oct 2026 15:45:45 -0400 Subject: [PATCH 04/27] CrowdStrike: resolve cloudRegion from string, object or array Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/metadata.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json index 0218bd67..f0d119a4 100644 --- a/plugins/CrowdStrike/v1/metadata.json +++ b/plugins/CrowdStrike/v1/metadata.json @@ -22,10 +22,10 @@ "plugin": "WebAPI", "majorVersion": "1", "config": { - "baseUrl": "{{ typeof cloudRegion === 'object' ? cloudRegion.value : cloudRegion }}", + "baseUrl": "{{ typeof cloudRegion === 'string' ? cloudRegion : (cloudRegion.value || cloudRegion[0].value) }}", "authMode": "oauth2", "oauth2GrantType": "clientCredentials", - "oauth2TokenUrl": "{{ typeof cloudRegion === 'object' ? cloudRegion.value : cloudRegion }}/oauth2/token", + "oauth2TokenUrl": "{{ typeof cloudRegion === 'string' ? cloudRegion : (cloudRegion.value || cloudRegion[0].value) }}/oauth2/token", "oauth2ClientId": "{{clientId}}", "oauth2ClientSecret": "{{clientSecret}}", "oauth2ClientSecretLocationDuringAuth": "body" From 11cdeed15ec8e59841e91129a1f947bd9ebc9851 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Wed, 7 Oct 2026 10:54:40 -0400 Subject: [PATCH 05/27] CrowdStrike: bump version to 1.0.1 Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json index f0d119a4..625780cf 100644 --- a/plugins/CrowdStrike/v1/metadata.json +++ b/plugins/CrowdStrike/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "crowdstrike", "displayName": "CrowdStrike", - "version": "1.0.0", + "version": "1.0.1", "author": { "name": "@JackTSquppy", "type": "community" }, "description": "Monitor CrowdStrike Falcon host coverage, detections & incidents, vulnerabilities, and policy compliance in SquaredUp.", "category": "Security", From 3534fa795333691290cbe8c22a1d4e4556032fb0 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Thu, 8 Oct 2026 13:32:09 -0400 Subject: [PATCH 06/27] CrowdStrike: fix duplicate limit and paging for devices, host groups, vulnerabilities - Remove limit from getArgs where paging.pageSize already sets it (400 'Multiple values specified in query string parameter limit'). - Page devices and vulnerabilities with the API's token (meta.pagination offset/after) instead of a numeric offset ('invalid offset supplied'). - Bump to 1.0.2. Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/dataStreams/devices.json | 9 ++------- plugins/CrowdStrike/v1/dataStreams/hostGroups.json | 1 - .../CrowdStrike/v1/dataStreams/vulnerabilities.json | 11 +++-------- plugins/CrowdStrike/v1/metadata.json | 2 +- 4 files changed, 6 insertions(+), 17 deletions(-) diff --git a/plugins/CrowdStrike/v1/dataStreams/devices.json b/plugins/CrowdStrike/v1/dataStreams/devices.json index 2b7b10bf..0e158683 100644 --- a/plugins/CrowdStrike/v1/dataStreams/devices.json +++ b/plugins/CrowdStrike/v1/dataStreams/devices.json @@ -8,20 +8,15 @@ "httpMethod": "get", "endpointPath": "/devices/combined/devices/v1", "getArgs": [ - { "key": "limit", "value": "500" }, { "key": "filter", "value": "{{(function(){var sel=(typeof scope!=='undefined'?scope:[])||[];if(!sel.length)return null;var unwrap=function(v){return Array.isArray(v)?v[0]:v;};var dev=[],grp=[];sel.forEach(function(o){var id=unwrap(o.rawId);if(o.type==='CrowdStrike Host Group'){grp.push(id);}else{dev.push(id);}});var parts=[];if(dev.length)parts.push(\"device_id:[\"+dev.map(function(i){return \"'\"+i+\"'\";}).join(\",\")+\"]\");if(grp.length)parts.push(\"group_ids:[\"+grp.map(function(i){return \"'\"+i+\"'\";}).join(\",\")+\"]\");return parts.length?parts.join(\"+\"):null;})()}}" } ], "paging": { - "mode": "offset", + "mode": "token", "pageSize": { "realm": "queryArg", "path": "limit", "value": "500" }, - "offset": { - "mode": "row", - "rowCountIn": { "realm": "payloadArraySize", "path": "resources" }, - "base": 0 - }, + "in": { "realm": "payload", "path": "meta.pagination.offset" }, "out": { "realm": "queryArg", "path": "offset" } }, "pathToData": "resources", diff --git a/plugins/CrowdStrike/v1/dataStreams/hostGroups.json b/plugins/CrowdStrike/v1/dataStreams/hostGroups.json index 52c4f838..41edcf0a 100644 --- a/plugins/CrowdStrike/v1/dataStreams/hostGroups.json +++ b/plugins/CrowdStrike/v1/dataStreams/hostGroups.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "get", "endpointPath": "/devices/combined/host-groups/v1", - "getArgs": [{ "key": "limit", "value": "500" }], "paging": { "mode": "offset", "pageSize": { "realm": "queryArg", "path": "limit", "value": "500" }, diff --git a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json index a1813b42..23a23aa6 100644 --- a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json +++ b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json @@ -8,7 +8,6 @@ "httpMethod": "get", "endpointPath": "/spotlight/combined/vulnerabilities/v1", "getArgs": [ - { "key": "limit", "value": "200" }, { "key": "facet", "value": "host_info" }, { "key": "filter", @@ -16,14 +15,10 @@ } ], "paging": { - "mode": "offset", + "mode": "token", "pageSize": { "realm": "queryArg", "path": "limit", "value": "200" }, - "offset": { - "mode": "row", - "rowCountIn": { "realm": "payloadArraySize", "path": "resources" }, - "base": 0 - }, - "out": { "realm": "queryArg", "path": "offset" } + "in": { "realm": "payload", "path": "meta.pagination.after" }, + "out": { "realm": "queryArg", "path": "after" } }, "pathToData": "resources", "expandInnerObjects": true diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json index 625780cf..a9397f26 100644 --- a/plugins/CrowdStrike/v1/metadata.json +++ b/plugins/CrowdStrike/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "crowdstrike", "displayName": "CrowdStrike", - "version": "1.0.1", + "version": "1.0.2", "author": { "name": "@JackTSquppy", "type": "community" }, "description": "Monitor CrowdStrike Falcon host coverage, detections & incidents, vulnerabilities, and policy compliance in SquaredUp.", "category": "Security", From 71708095a40012a8a5e4543c18d6b84d5c668332 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Thu, 8 Oct 2026 13:55:43 -0400 Subject: [PATCH 07/27] CrowdStrike: rewrite filter expressions without '}}' sequences The IIFE filter expressions contained '}});', which the template engine treats as the end of the expression, producing an invalid FQL filter on import ('Invalid filter expression supplied'). Rewrite as brace-free expressions for devices, alerts and vulnerabilities. Bump to 1.0.3. Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/dataStreams/alerts.json | 2 +- plugins/CrowdStrike/v1/dataStreams/devices.json | 2 +- plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json | 2 +- plugins/CrowdStrike/v1/metadata.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/CrowdStrike/v1/dataStreams/alerts.json b/plugins/CrowdStrike/v1/dataStreams/alerts.json index 5efb0008..20f3afc8 100644 --- a/plugins/CrowdStrike/v1/dataStreams/alerts.json +++ b/plugins/CrowdStrike/v1/dataStreams/alerts.json @@ -11,7 +11,7 @@ "limit": 100, "sort": "created_timestamp|desc", "after": "{{after || null}}", - "filter": "{{(function(){var parts=[];if(typeof timeframe!=='undefined'&&timeframe&&timeframe.start&&timeframe.end){parts.push(\"created_timestamp:>'\"+timeframe.start+\"'+created_timestamp:<'\"+timeframe.end+\"'\");}var sel=(typeof scope!=='undefined'?scope:[])||[];var unwrap=function(v){return Array.isArray(v)?v[0]:v;};if(sel.length){var dev=[],grp=[];sel.forEach(function(o){var id=unwrap(o.rawId);if(o.type==='CrowdStrike Host Group'){grp.push(id);}else{dev.push(id);}});if(dev.length)parts.push(\"device.device_id:[\"+dev.map(function(i){return \"'\"+i+\"'\";}).join(\",\")+\"]\");if(grp.length)parts.push(\"device.groups:[\"+grp.map(function(i){return \"'\"+i+\"'\";}).join(\",\")+\"]\");}var st=(typeof status!=='undefined'?status:[])||[];if(st.length)parts.push(\"status:[\"+st.map(function(s){return \"'\"+(s.value||s)+\"'\";}).join(\",\")+\"]\");return parts.length?parts.join(\"+\"):null;})()}}" + "filter": "{{ (typeof timeframe !== 'undefined' && timeframe && timeframe.start && timeframe.end ? [ \"created_timestamp:>'\" + timeframe.start + \"'+created_timestamp:<'\" + timeframe.end + \"'\" ] : []).concat((typeof scope === 'undefined' || !scope ? [] : [ [\"device.device_id\", scope.filter(o => o.type !== 'CrowdStrike Host Group')], [\"device.groups\", scope.filter(o => o.type === 'CrowdStrike Host Group')] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + [].concat(o.rawId)[0] + \"'\").join(\",\") + \"]\"))).concat((typeof status === 'undefined' || !status || !status.length ? [] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") || null }}" }, "paging": { "mode": "token", diff --git a/plugins/CrowdStrike/v1/dataStreams/devices.json b/plugins/CrowdStrike/v1/dataStreams/devices.json index 0e158683..6a78c1e4 100644 --- a/plugins/CrowdStrike/v1/dataStreams/devices.json +++ b/plugins/CrowdStrike/v1/dataStreams/devices.json @@ -10,7 +10,7 @@ "getArgs": [ { "key": "filter", - "value": "{{(function(){var sel=(typeof scope!=='undefined'?scope:[])||[];if(!sel.length)return null;var unwrap=function(v){return Array.isArray(v)?v[0]:v;};var dev=[],grp=[];sel.forEach(function(o){var id=unwrap(o.rawId);if(o.type==='CrowdStrike Host Group'){grp.push(id);}else{dev.push(id);}});var parts=[];if(dev.length)parts.push(\"device_id:[\"+dev.map(function(i){return \"'\"+i+\"'\";}).join(\",\")+\"]\");if(grp.length)parts.push(\"group_ids:[\"+grp.map(function(i){return \"'\"+i+\"'\";}).join(\",\")+\"]\");return parts.length?parts.join(\"+\"):null;})()}}" + "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"device_id\", scope.filter(o => o.type !== 'CrowdStrike Host Group')], [\"group_ids\", scope.filter(o => o.type === 'CrowdStrike Host Group')] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + [].concat(o.rawId)[0] + \"'\").join(\",\") + \"]\")).join(\"+\") || null }}" } ], "paging": { diff --git a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json index 23a23aa6..7ddf0ae3 100644 --- a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json +++ b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json @@ -11,7 +11,7 @@ { "key": "facet", "value": "host_info" }, { "key": "filter", - "value": "{{(function(){var parts=[];var sel=(typeof scope!=='undefined'?scope:[])||[];var unwrap=function(v){return Array.isArray(v)?v[0]:v;};if(sel.length){var dev=[],grp=[];sel.forEach(function(o){var id=unwrap(o.rawId);if(o.type==='CrowdStrike Host Group'){grp.push(id);}else{dev.push(id);}});if(dev.length)parts.push(\"aid:[\"+dev.map(function(i){return \"'\"+i+\"'\";}).join(\",\")+\"]\");if(grp.length)parts.push(\"host_info.groups:[\"+grp.map(function(i){return \"'\"+i+\"'\";}).join(\",\")+\"]\");}var st=(typeof status!=='undefined'?status:[])||[];if(st.length)parts.push(\"status:[\"+st.map(function(s){return \"'\"+(s.value||s)+\"'\";}).join(\",\")+\"]\");return parts.length?parts.join(\"+\"):null;})()}}" + "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"aid\", scope.filter(o => o.type !== 'CrowdStrike Host Group')], [\"host_info.groups\", scope.filter(o => o.type === 'CrowdStrike Host Group')] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + [].concat(o.rawId)[0] + \"'\").join(\",\") + \"]\")).concat((typeof status === 'undefined' || !status || !status.length ? [] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") || null }}" } ], "paging": { diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json index a9397f26..cc9a700f 100644 --- a/plugins/CrowdStrike/v1/metadata.json +++ b/plugins/CrowdStrike/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "crowdstrike", "displayName": "CrowdStrike", - "version": "1.0.2", + "version": "1.0.3", "author": { "name": "@JackTSquppy", "type": "community" }, "description": "Monitor CrowdStrike Falcon host coverage, detections & incidents, vulnerabilities, and policy compliance in SquaredUp.", "category": "Security", From 4a694efb7cec76dc1b581b49dd2d88a12461d527 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Thu, 8 Oct 2026 14:00:03 -0400 Subject: [PATCH 08/27] CrowdStrike: make host group import step optional Host groups are optional in Falcon; an empty result should not fail the whole import. Bump to 1.0.4. Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/indexDefinitions/default.json | 1 + plugins/CrowdStrike/v1/metadata.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/CrowdStrike/v1/indexDefinitions/default.json b/plugins/CrowdStrike/v1/indexDefinitions/default.json index cb2cfd5c..0ea6c450 100644 --- a/plugins/CrowdStrike/v1/indexDefinitions/default.json +++ b/plugins/CrowdStrike/v1/indexDefinitions/default.json @@ -4,6 +4,7 @@ "name": "hostGroups", "dataStream": { "name": "hostGroups", "config": {} }, "timeframe": "none", + "optional": true, "objectMapping": { "id": "id", "name": "name", diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json index cc9a700f..7d66e11e 100644 --- a/plugins/CrowdStrike/v1/metadata.json +++ b/plugins/CrowdStrike/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "crowdstrike", "displayName": "CrowdStrike", - "version": "1.0.3", + "version": "1.0.4", "author": { "name": "@JackTSquppy", "type": "community" }, "description": "Monitor CrowdStrike Falcon host coverage, detections & incidents, vulnerabilities, and policy compliance in SquaredUp.", "category": "Security", From eaffd638c7fc7957bf77ca8f22705d8757cfd75a Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Thu, 8 Oct 2026 14:26:57 -0400 Subject: [PATCH 09/27] CrowdStrike: smaller device pages, unpaged host groups - devices: 100 per page; 500 exceeded the 6MB response limit on import. - hostGroups: single request (limit 500) instead of offset paging, to avoid a trailing empty page failing the import step. - Bump to 1.0.5. Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/dataStreams/devices.json | 2 +- plugins/CrowdStrike/v1/dataStreams/hostGroups.json | 12 ++---------- plugins/CrowdStrike/v1/metadata.json | 2 +- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/plugins/CrowdStrike/v1/dataStreams/devices.json b/plugins/CrowdStrike/v1/dataStreams/devices.json index 6a78c1e4..42f0f5b4 100644 --- a/plugins/CrowdStrike/v1/dataStreams/devices.json +++ b/plugins/CrowdStrike/v1/dataStreams/devices.json @@ -15,7 +15,7 @@ ], "paging": { "mode": "token", - "pageSize": { "realm": "queryArg", "path": "limit", "value": "500" }, + "pageSize": { "realm": "queryArg", "path": "limit", "value": "100" }, "in": { "realm": "payload", "path": "meta.pagination.offset" }, "out": { "realm": "queryArg", "path": "offset" } }, diff --git a/plugins/CrowdStrike/v1/dataStreams/hostGroups.json b/plugins/CrowdStrike/v1/dataStreams/hostGroups.json index 41edcf0a..f079b79f 100644 --- a/plugins/CrowdStrike/v1/dataStreams/hostGroups.json +++ b/plugins/CrowdStrike/v1/dataStreams/hostGroups.json @@ -7,16 +7,8 @@ "config": { "httpMethod": "get", "endpointPath": "/devices/combined/host-groups/v1", - "paging": { - "mode": "offset", - "pageSize": { "realm": "queryArg", "path": "limit", "value": "500" }, - "offset": { - "mode": "row", - "rowCountIn": { "realm": "payloadArraySize", "path": "resources" }, - "base": 0 - }, - "out": { "realm": "queryArg", "path": "offset" } - }, + "getArgs": [{ "key": "limit", "value": "500" }], + "paging": { "mode": "none" }, "pathToData": "resources" }, "matches": "none", diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json index 7d66e11e..9fdda5b5 100644 --- a/plugins/CrowdStrike/v1/metadata.json +++ b/plugins/CrowdStrike/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "crowdstrike", "displayName": "CrowdStrike", - "version": "1.0.4", + "version": "1.0.5", "author": { "name": "@JackTSquppy", "type": "community" }, "description": "Monitor CrowdStrike Falcon host coverage, detections & incidents, vulnerabilities, and policy compliance in SquaredUp.", "category": "Security", From 925a069141b8c96cdd88dc918c86c4367b6affd0 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Thu, 8 Oct 2026 14:53:05 -0400 Subject: [PATCH 10/27] CrowdStrike: 250 devices per page, drop wildcard device columns 100 per page hit the platform's 220 call-chain limit on large fleets (~22k devices). Slim rows by removing the catch-all column pattern so larger pages fit under the 6MB response limit. Bump to 1.0.6. Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/dataStreams/devices.json | 5 ++--- plugins/CrowdStrike/v1/metadata.json | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/plugins/CrowdStrike/v1/dataStreams/devices.json b/plugins/CrowdStrike/v1/dataStreams/devices.json index 42f0f5b4..787df971 100644 --- a/plugins/CrowdStrike/v1/dataStreams/devices.json +++ b/plugins/CrowdStrike/v1/dataStreams/devices.json @@ -15,7 +15,7 @@ ], "paging": { "mode": "token", - "pageSize": { "realm": "queryArg", "path": "limit", "value": "100" }, + "pageSize": { "realm": "queryArg", "path": "limit", "value": "250" }, "in": { "realm": "payload", "path": "meta.pagination.offset" }, "out": { "realm": "queryArg", "path": "offset" } }, @@ -76,8 +76,7 @@ "name": "device_policies.sensor_update.applied", "displayName": "Sensor Update Policy Applied", "shape": "boolean" - }, - { "pattern": ".*" } + } ], "timeframes": false } diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json index 9fdda5b5..64d6133f 100644 --- a/plugins/CrowdStrike/v1/metadata.json +++ b/plugins/CrowdStrike/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "crowdstrike", "displayName": "CrowdStrike", - "version": "1.0.5", + "version": "1.0.6", "author": { "name": "@JackTSquppy", "type": "community" }, "description": "Monitor CrowdStrike Falcon host coverage, detections & incidents, vulnerabilities, and policy compliance in SquaredUp.", "category": "Security", From 6d24b80fd8aed0add3a20081123e3f747649a166 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Tue, 13 Oct 2026 09:55:00 -0400 Subject: [PATCH 11/27] CrowdStrike: page devices with meta.pagination.next, slim rows via fields Real responses show meta.pagination.offset is always empty and the next-page cursor is meta.pagination.next, so token paging re-fetched page 1 forever. Tenant has ~92.7k hosts, so use 1000 per page and request only the needed fields to stay under the 6MB response limit and 220 call-chain cap. Add a fixed sort for stable paging. Bump to 1.0.7. Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/dataStreams/devices.json | 6 ++++-- plugins/CrowdStrike/v1/metadata.json | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/CrowdStrike/v1/dataStreams/devices.json b/plugins/CrowdStrike/v1/dataStreams/devices.json index 787df971..8cd38d0b 100644 --- a/plugins/CrowdStrike/v1/dataStreams/devices.json +++ b/plugins/CrowdStrike/v1/dataStreams/devices.json @@ -8,6 +8,8 @@ "httpMethod": "get", "endpointPath": "/devices/combined/devices/v1", "getArgs": [ + { "key": "sort", "value": "device_id.asc" }, + { "key": "fields", "value": "device_id,hostname,platform_name,os_version,product_type_desc,agent_version,status,reduced_functionality_mode,first_seen,last_seen,local_ip,external_ip,mac_address,machine_domain,site_name,serial_number,system_manufacturer,system_product_name,group_ids,groups,tags,device_policies" }, { "key": "filter", "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"device_id\", scope.filter(o => o.type !== 'CrowdStrike Host Group')], [\"group_ids\", scope.filter(o => o.type === 'CrowdStrike Host Group')] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + [].concat(o.rawId)[0] + \"'\").join(\",\") + \"]\")).join(\"+\") || null }}" @@ -15,8 +17,8 @@ ], "paging": { "mode": "token", - "pageSize": { "realm": "queryArg", "path": "limit", "value": "250" }, - "in": { "realm": "payload", "path": "meta.pagination.offset" }, + "pageSize": { "realm": "queryArg", "path": "limit", "value": "1000" }, + "in": { "realm": "payload", "path": "meta.pagination.next" }, "out": { "realm": "queryArg", "path": "offset" } }, "pathToData": "resources", diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json index 64d6133f..258ca5a9 100644 --- a/plugins/CrowdStrike/v1/metadata.json +++ b/plugins/CrowdStrike/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "crowdstrike", "displayName": "CrowdStrike", - "version": "1.0.6", + "version": "1.0.7", "author": { "name": "@JackTSquppy", "type": "community" }, "description": "Monitor CrowdStrike Falcon host coverage, detections & incidents, vulnerabilities, and policy compliance in SquaredUp.", "category": "Security", From 99792a597d24467f992263bd5a84365b7b6c424c Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Tue, 13 Oct 2026 10:40:04 -0400 Subject: [PATCH 12/27] CrowdStrike: use 'groups' instead of invalid 'group_ids' device field CrowdStrike returns 400 'group_ids is not a valid device field'. Rename the column, filter field, index property, dashboard hidden columns and README. Bump to 1.0.8. Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/dataStreams/devices.json | 6 +++--- .../v1/defaultContent/hostGroupPerspective.dash.json | 2 +- plugins/CrowdStrike/v1/defaultContent/overview.dash.json | 2 +- plugins/CrowdStrike/v1/docs/README.md | 2 +- plugins/CrowdStrike/v1/indexDefinitions/default.json | 2 +- plugins/CrowdStrike/v1/metadata.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/CrowdStrike/v1/dataStreams/devices.json b/plugins/CrowdStrike/v1/dataStreams/devices.json index 8cd38d0b..d9e96a50 100644 --- a/plugins/CrowdStrike/v1/dataStreams/devices.json +++ b/plugins/CrowdStrike/v1/dataStreams/devices.json @@ -9,10 +9,10 @@ "endpointPath": "/devices/combined/devices/v1", "getArgs": [ { "key": "sort", "value": "device_id.asc" }, - { "key": "fields", "value": "device_id,hostname,platform_name,os_version,product_type_desc,agent_version,status,reduced_functionality_mode,first_seen,last_seen,local_ip,external_ip,mac_address,machine_domain,site_name,serial_number,system_manufacturer,system_product_name,group_ids,groups,tags,device_policies" }, + { "key": "fields", "value": "device_id,hostname,platform_name,os_version,product_type_desc,agent_version,status,reduced_functionality_mode,first_seen,last_seen,local_ip,external_ip,mac_address,machine_domain,site_name,serial_number,system_manufacturer,system_product_name,groups,tags,device_policies" }, { "key": "filter", - "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"device_id\", scope.filter(o => o.type !== 'CrowdStrike Host Group')], [\"group_ids\", scope.filter(o => o.type === 'CrowdStrike Host Group')] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + [].concat(o.rawId)[0] + \"'\").join(\",\") + \"]\")).join(\"+\") || null }}" + "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"device_id\", scope.filter(o => o.type !== 'CrowdStrike Host Group')], [\"groups\", scope.filter(o => o.type === 'CrowdStrike Host Group')] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + [].concat(o.rawId)[0] + \"'\").join(\",\") + \"]\")).join(\"+\") || null }}" } ], "paging": { @@ -67,7 +67,7 @@ { "name": "serial_number", "displayName": "Serial Number", "shape": "string" }, { "name": "system_manufacturer", "displayName": "Manufacturer", "shape": "string" }, { "name": "system_product_name", "displayName": "Model", "shape": "string" }, - { "name": "group_ids", "displayName": "Host Group IDs", "shape": "string", "visible": false }, + { "name": "groups", "displayName": "Host Group IDs", "shape": "string", "visible": false }, { "name": "tags", "displayName": "Tags", "shape": "string" }, { "name": "device_policies.prevention.applied", diff --git a/plugins/CrowdStrike/v1/defaultContent/hostGroupPerspective.dash.json b/plugins/CrowdStrike/v1/defaultContent/hostGroupPerspective.dash.json index 6f34b365..09906428 100644 --- a/plugins/CrowdStrike/v1/defaultContent/hostGroupPerspective.dash.json +++ b/plugins/CrowdStrike/v1/defaultContent/hostGroupPerspective.dash.json @@ -787,7 +787,7 @@ ], "hiddenColumns": [ "device_id", - "group_ids", + "groups", "mac_address", "external_ip", "machine_domain", diff --git a/plugins/CrowdStrike/v1/defaultContent/overview.dash.json b/plugins/CrowdStrike/v1/defaultContent/overview.dash.json index bb0bcb8a..0755a589 100644 --- a/plugins/CrowdStrike/v1/defaultContent/overview.dash.json +++ b/plugins/CrowdStrike/v1/defaultContent/overview.dash.json @@ -387,7 +387,7 @@ ], "hiddenColumns": [ "device_id", - "group_ids", + "groups", "mac_address", "external_ip", "machine_domain", diff --git a/plugins/CrowdStrike/v1/docs/README.md b/plugins/CrowdStrike/v1/docs/README.md index ae137614..072f48d1 100644 --- a/plugins/CrowdStrike/v1/docs/README.md +++ b/plugins/CrowdStrike/v1/docs/README.md @@ -46,7 +46,7 @@ The out-of-the-box dashboards include an account-wide **Overview**, a **Host Gro | **CrowdStrike Host Group** | `GET /devices/combined/host-groups/v1` | A Falcon Host Group (used here to represent an agency). | | **CrowdStrike Host** | `GET /devices/combined/devices/v1` | An enrolled endpoint (workstation, server, etc.). | -**Relationships:** each Host's `group_ids` property references the Host Group(s) it belongs to (a host can belong to more than one group). +**Relationships:** each Host's `groups` property references the Host Group(s) it belongs to (a host can belong to more than one group). ## Known limitations diff --git a/plugins/CrowdStrike/v1/indexDefinitions/default.json b/plugins/CrowdStrike/v1/indexDefinitions/default.json index 0ea6c450..664f1d5f 100644 --- a/plugins/CrowdStrike/v1/indexDefinitions/default.json +++ b/plugins/CrowdStrike/v1/indexDefinitions/default.json @@ -31,7 +31,7 @@ "local_ip", "external_ip", "site_name", - "group_ids" + "groups" ] } } diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json index 258ca5a9..88006b73 100644 --- a/plugins/CrowdStrike/v1/metadata.json +++ b/plugins/CrowdStrike/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "crowdstrike", "displayName": "CrowdStrike", - "version": "1.0.7", + "version": "1.0.8", "author": { "name": "@JackTSquppy", "type": "community" }, "description": "Monitor CrowdStrike Falcon host coverage, detections & incidents, vulnerabilities, and policy compliance in SquaredUp.", "category": "Security", From 51d697c07592c8ac025b7ab6d669bc61280f4370 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Tue, 13 Oct 2026 11:36:53 -0400 Subject: [PATCH 13/27] CrowdStrike: lean hostsIndex stream for import, smaller device pages An LCP import has no overall object limit; only a single page must stay under 6MB (and a step is capped at 220 paged calls). Import hosts with a lean stream carrying only the stored properties (750/page, ~124 calls for 93k hosts) and lower the devices stream to 500/page. Bump to 1.0.9. Co-Authored-By: Claude Sonnet 5.5 --- .../CrowdStrike/v1/dataStreams/devices.json | 2 +- .../v1/dataStreams/hostsIndex.json | 131 ++++++++++++++++++ .../v1/indexDefinitions/default.json | 2 +- plugins/CrowdStrike/v1/metadata.json | 2 +- 4 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 plugins/CrowdStrike/v1/dataStreams/hostsIndex.json diff --git a/plugins/CrowdStrike/v1/dataStreams/devices.json b/plugins/CrowdStrike/v1/dataStreams/devices.json index d9e96a50..0b79fc86 100644 --- a/plugins/CrowdStrike/v1/dataStreams/devices.json +++ b/plugins/CrowdStrike/v1/dataStreams/devices.json @@ -17,7 +17,7 @@ ], "paging": { "mode": "token", - "pageSize": { "realm": "queryArg", "path": "limit", "value": "1000" }, + "pageSize": { "realm": "queryArg", "path": "limit", "value": "500" }, "in": { "realm": "payload", "path": "meta.pagination.next" }, "out": { "realm": "queryArg", "path": "offset" } }, diff --git a/plugins/CrowdStrike/v1/dataStreams/hostsIndex.json b/plugins/CrowdStrike/v1/dataStreams/hostsIndex.json new file mode 100644 index 00000000..03aec2d7 --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/hostsIndex.json @@ -0,0 +1,131 @@ +{ + "name": "hostsIndex", + "displayName": "Hosts (index)", + "description": "Lean host list used only to import Host objects", + "tags": [ + "Security" + ], + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "/devices/combined/devices/v1", + "getArgs": [ + { + "key": "sort", + "value": "device_id.asc" + }, + { + "key": "fields", + "value": "device_id,hostname,platform_name,os_version,product_type_desc,agent_version,status,first_seen,last_seen,local_ip,external_ip,site_name,groups" + } + ], + "paging": { + "mode": "token", + "pageSize": { + "realm": "queryArg", + "path": "limit", + "value": "750" + }, + "in": { + "realm": "payload", + "path": "meta.pagination.next" + }, + "out": { + "realm": "queryArg", + "path": "offset" + } + }, + "pathToData": "resources" + }, + "matches": "none", + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "device_id", + "displayName": "Device ID", + "shape": "string", + "visible": false + }, + { + "name": "hostname", + "displayName": "Hostname", + "shape": "string", + "role": "label" + }, + { + "name": "platform_name", + "displayName": "Platform", + "shape": "string" + }, + { + "name": "os_version", + "displayName": "OS Version", + "shape": "string" + }, + { + "name": "product_type_desc", + "displayName": "Product Type", + "shape": "string" + }, + { + "name": "agent_version", + "displayName": "Sensor Version", + "shape": "string" + }, + { + "name": "status", + "displayName": "Containment Status", + "shape": [ + "state", + { + "map": { + "success": [ + "normal" + ], + "warning": [ + "containment_pending", + "lift_containment_pending" + ], + "error": [ + "contained" + ] + } + } + ] + }, + { + "name": "first_seen", + "displayName": "First Seen", + "shape": "date" + }, + { + "name": "last_seen", + "displayName": "Last Seen", + "shape": "date" + }, + { + "name": "local_ip", + "displayName": "Local IP", + "shape": "string" + }, + { + "name": "external_ip", + "displayName": "External IP", + "shape": "string" + }, + { + "name": "site_name", + "displayName": "Site", + "shape": "string" + }, + { + "name": "groups", + "displayName": "Host Group IDs", + "shape": "string", + "visible": false + } + ], + "timeframes": false +} diff --git a/plugins/CrowdStrike/v1/indexDefinitions/default.json b/plugins/CrowdStrike/v1/indexDefinitions/default.json index 664f1d5f..8063aedb 100644 --- a/plugins/CrowdStrike/v1/indexDefinitions/default.json +++ b/plugins/CrowdStrike/v1/indexDefinitions/default.json @@ -14,7 +14,7 @@ }, { "name": "devices", - "dataStream": { "name": "devices", "config": {} }, + "dataStream": { "name": "hostsIndex", "config": {} }, "timeframe": "none", "objectMapping": { "id": "device_id", diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json index 88006b73..c520fa49 100644 --- a/plugins/CrowdStrike/v1/metadata.json +++ b/plugins/CrowdStrike/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "crowdstrike", "displayName": "CrowdStrike", - "version": "1.0.8", + "version": "1.0.9", "author": { "name": "@JackTSquppy", "type": "community" }, "description": "Monitor CrowdStrike Falcon host coverage, detections & incidents, vulnerabilities, and policy compliance in SquaredUp.", "category": "Security", From 50f0164a7c7ef1c8038f561c9643e5a4e4766618 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Tue, 13 Oct 2026 11:40:40 -0400 Subject: [PATCH 14/27] CrowdStrike: import hosts 500 per page Smaller pages per review feedback; 500 keeps a ~93k host tenant within the 220 call-chain limit (~186 calls). Bump to 1.0.10. Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/dataStreams/hostsIndex.json | 2 +- plugins/CrowdStrike/v1/metadata.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/CrowdStrike/v1/dataStreams/hostsIndex.json b/plugins/CrowdStrike/v1/dataStreams/hostsIndex.json index 03aec2d7..4d3b03cd 100644 --- a/plugins/CrowdStrike/v1/dataStreams/hostsIndex.json +++ b/plugins/CrowdStrike/v1/dataStreams/hostsIndex.json @@ -24,7 +24,7 @@ "pageSize": { "realm": "queryArg", "path": "limit", - "value": "750" + "value": "500" }, "in": { "realm": "payload", diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json index c520fa49..2975f382 100644 --- a/plugins/CrowdStrike/v1/metadata.json +++ b/plugins/CrowdStrike/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "crowdstrike", "displayName": "CrowdStrike", - "version": "1.0.9", + "version": "1.0.10", "author": { "name": "@JackTSquppy", "type": "community" }, "description": "Monitor CrowdStrike Falcon host coverage, detections & incidents, vulnerabilities, and policy compliance in SquaredUp.", "category": "Security", From 8425dc171f79f1a182b4bfae39bf5b068966d991 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Wed, 14 Oct 2026 10:40:19 -0400 Subject: [PATCH 15/27] CrowdStrike: make host/group scope parsing robust to object shape Host Group dashboard returned 0 hosts. Do not assume scope objects expose type/rawId: detect groups from the object contents and read the id from rawId or sourceId (stripping the type prefix). Applies to devices, alerts and vulnerabilities. Bump to 1.0.11. Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/dataStreams/alerts.json | 2 +- plugins/CrowdStrike/v1/dataStreams/devices.json | 2 +- plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json | 2 +- plugins/CrowdStrike/v1/metadata.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/CrowdStrike/v1/dataStreams/alerts.json b/plugins/CrowdStrike/v1/dataStreams/alerts.json index 20f3afc8..e39b4779 100644 --- a/plugins/CrowdStrike/v1/dataStreams/alerts.json +++ b/plugins/CrowdStrike/v1/dataStreams/alerts.json @@ -11,7 +11,7 @@ "limit": 100, "sort": "created_timestamp|desc", "after": "{{after || null}}", - "filter": "{{ (typeof timeframe !== 'undefined' && timeframe && timeframe.start && timeframe.end ? [ \"created_timestamp:>'\" + timeframe.start + \"'+created_timestamp:<'\" + timeframe.end + \"'\" ] : []).concat((typeof scope === 'undefined' || !scope ? [] : [ [\"device.device_id\", scope.filter(o => o.type !== 'CrowdStrike Host Group')], [\"device.groups\", scope.filter(o => o.type === 'CrowdStrike Host Group')] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + [].concat(o.rawId)[0] + \"'\").join(\",\") + \"]\"))).concat((typeof status === 'undefined' || !status || !status.length ? [] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") || null }}" + "filter": "{{ (typeof timeframe !== 'undefined' && timeframe && timeframe.start && timeframe.end ? [ \"created_timestamp:>'\" + timeframe.start + \"'+created_timestamp:<'\" + timeframe.end + \"'\" ] : []).concat((typeof scope === 'undefined' || !scope ? [] : [ [\"device.device_id\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') < 0)], [\"device.groups\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\"))).concat((typeof status === 'undefined' || !status || !status.length ? [] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") || null }}" }, "paging": { "mode": "token", diff --git a/plugins/CrowdStrike/v1/dataStreams/devices.json b/plugins/CrowdStrike/v1/dataStreams/devices.json index 0b79fc86..553293af 100644 --- a/plugins/CrowdStrike/v1/dataStreams/devices.json +++ b/plugins/CrowdStrike/v1/dataStreams/devices.json @@ -12,7 +12,7 @@ { "key": "fields", "value": "device_id,hostname,platform_name,os_version,product_type_desc,agent_version,status,reduced_functionality_mode,first_seen,last_seen,local_ip,external_ip,mac_address,machine_domain,site_name,serial_number,system_manufacturer,system_product_name,groups,tags,device_policies" }, { "key": "filter", - "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"device_id\", scope.filter(o => o.type !== 'CrowdStrike Host Group')], [\"groups\", scope.filter(o => o.type === 'CrowdStrike Host Group')] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + [].concat(o.rawId)[0] + \"'\").join(\",\") + \"]\")).join(\"+\") || null }}" + "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"device_id\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') < 0)], [\"groups\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).join(\"+\") || null }}" } ], "paging": { diff --git a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json index 7ddf0ae3..9949b23e 100644 --- a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json +++ b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json @@ -11,7 +11,7 @@ { "key": "facet", "value": "host_info" }, { "key": "filter", - "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"aid\", scope.filter(o => o.type !== 'CrowdStrike Host Group')], [\"host_info.groups\", scope.filter(o => o.type === 'CrowdStrike Host Group')] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + [].concat(o.rawId)[0] + \"'\").join(\",\") + \"]\")).concat((typeof status === 'undefined' || !status || !status.length ? [] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") || null }}" + "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"aid\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') < 0)], [\"host_info.groups\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).concat((typeof status === 'undefined' || !status || !status.length ? [] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") || null }}" } ], "paging": { diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json index 2975f382..965193ca 100644 --- a/plugins/CrowdStrike/v1/metadata.json +++ b/plugins/CrowdStrike/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "crowdstrike", "displayName": "CrowdStrike", - "version": "1.0.10", + "version": "1.0.11", "author": { "name": "@JackTSquppy", "type": "community" }, "description": "Monitor CrowdStrike Falcon host coverage, detections & incidents, vulnerabilities, and policy compliance in SquaredUp.", "category": "Security", From 2145a3018af59169d75a03532bee4019a4df4520 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Wed, 14 Oct 2026 10:53:21 -0400 Subject: [PATCH 16/27] CrowdStrike: always send valid alert and vulnerability filters - alerts: drop redundant body 'after' (paging sets it), strip milliseconds from timeframe timestamps, fall back to a valid created_timestamp filter. - vulnerabilities: always send a filter (default status open/reopen); the Spotlight combined endpoint can reject an empty filter. Bump to 1.0.12. Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/dataStreams/alerts.json | 3 +-- plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json | 2 +- plugins/CrowdStrike/v1/metadata.json | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/plugins/CrowdStrike/v1/dataStreams/alerts.json b/plugins/CrowdStrike/v1/dataStreams/alerts.json index e39b4779..a17f727f 100644 --- a/plugins/CrowdStrike/v1/dataStreams/alerts.json +++ b/plugins/CrowdStrike/v1/dataStreams/alerts.json @@ -10,8 +10,7 @@ "postBody": { "limit": 100, "sort": "created_timestamp|desc", - "after": "{{after || null}}", - "filter": "{{ (typeof timeframe !== 'undefined' && timeframe && timeframe.start && timeframe.end ? [ \"created_timestamp:>'\" + timeframe.start + \"'+created_timestamp:<'\" + timeframe.end + \"'\" ] : []).concat((typeof scope === 'undefined' || !scope ? [] : [ [\"device.device_id\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') < 0)], [\"device.groups\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\"))).concat((typeof status === 'undefined' || !status || !status.length ? [] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") || null }}" + "filter": "{{ (typeof timeframe !== 'undefined' && timeframe && timeframe.start && timeframe.end ? [ \"created_timestamp:>'\" + timeframe.start.replace(/\\.\\d+Z$/, 'Z') + \"'+created_timestamp:<'\" + timeframe.end.replace(/\\.\\d+Z$/, 'Z') + \"'\" ] : []).concat((typeof scope === 'undefined' || !scope ? [] : [ [\"device.device_id\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') < 0)], [\"device.groups\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\"))).concat((typeof status === 'undefined' || !status || !status.length ? [] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") || \"created_timestamp:>'2000-01-01T00:00:00Z'\" }}" }, "paging": { "mode": "token", diff --git a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json index 9949b23e..71436fd6 100644 --- a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json +++ b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json @@ -11,7 +11,7 @@ { "key": "facet", "value": "host_info" }, { "key": "filter", - "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"aid\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') < 0)], [\"host_info.groups\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).concat((typeof status === 'undefined' || !status || !status.length ? [] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") || null }}" + "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"aid\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') < 0)], [\"host_info.groups\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).concat((typeof status === 'undefined' || !status || !status.length ? [ \"status:['open','reopen']\" ] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") }}" } ], "paging": { diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json index 965193ca..ba368d36 100644 --- a/plugins/CrowdStrike/v1/metadata.json +++ b/plugins/CrowdStrike/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "crowdstrike", "displayName": "CrowdStrike", - "version": "1.0.11", + "version": "1.0.12", "author": { "name": "@JackTSquppy", "type": "community" }, "description": "Monitor CrowdStrike Falcon host coverage, detections & incidents, vulnerabilities, and policy compliance in SquaredUp.", "category": "Security", From 2e18e599becf909eb60dfa2d0340399e03a5b918 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Wed, 14 Oct 2026 12:27:36 -0400 Subject: [PATCH 17/27] CrowdStrike: single-request count streams for Overview, surface API error messages Co-Authored-By: Claude Sonnet 5.5 --- .../CrowdStrike/v1/dataStreams/alerts.json | 213 +++++-- .../CrowdStrike/v1/dataStreams/devices.json | 175 +++++- .../CrowdStrike/v1/dataStreams/hostCount.json | 86 +++ .../v1/dataStreams/recentHosts.json | 119 ++++ .../scripts/errorHandling/alerts.js | 3 + .../scripts/errorHandling/devices.js | 3 + .../scripts/errorHandling/hostCount.js | 3 + .../scripts/errorHandling/vulnerabilities.js | 3 + .../errorHandling/vulnerabilityCount.js | 3 + .../v1/dataStreams/vulnerabilities.json | 165 ++++- .../v1/dataStreams/vulnerabilityCount.json | 105 ++++ .../hostGroupPerspective.dash.json | 399 +++++++++--- .../v1/defaultContent/overview.dash.json | 595 ++++++++++++------ plugins/CrowdStrike/v1/metadata.json | 2 +- 14 files changed, 1512 insertions(+), 362 deletions(-) create mode 100644 plugins/CrowdStrike/v1/dataStreams/hostCount.json create mode 100644 plugins/CrowdStrike/v1/dataStreams/recentHosts.json create mode 100644 plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/alerts.js create mode 100644 plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/devices.js create mode 100644 plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/hostCount.js create mode 100644 plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/vulnerabilities.js create mode 100644 plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/vulnerabilityCount.js create mode 100644 plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json diff --git a/plugins/CrowdStrike/v1/dataStreams/alerts.json b/plugins/CrowdStrike/v1/dataStreams/alerts.json index a17f727f..84a52970 100644 --- a/plugins/CrowdStrike/v1/dataStreams/alerts.json +++ b/plugins/CrowdStrike/v1/dataStreams/alerts.json @@ -2,24 +2,36 @@ "name": "alerts", "displayName": "Alerts", "description": "Detections and incidents from the unified Falcon Alerts API, one row per alert, with computed detection and response latency", - "tags": ["Security", "Alerts"], + "tags": [ + "Security", + "Alerts" + ], "baseDataSourceName": "httpRequestUnscoped", "config": { "httpMethod": "post", "endpointPath": "/alerts/combined/alerts/v1", "postBody": { - "limit": 100, + "limit": 1000, "sort": "created_timestamp|desc", "filter": "{{ (typeof timeframe !== 'undefined' && timeframe && timeframe.start && timeframe.end ? [ \"created_timestamp:>'\" + timeframe.start.replace(/\\.\\d+Z$/, 'Z') + \"'+created_timestamp:<'\" + timeframe.end.replace(/\\.\\d+Z$/, 'Z') + \"'\" ] : []).concat((typeof scope === 'undefined' || !scope ? [] : [ [\"device.device_id\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') < 0)], [\"device.groups\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\"))).concat((typeof status === 'undefined' || !status || !status.length ? [] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") || \"created_timestamp:>'2000-01-01T00:00:00Z'\" }}" }, "paging": { "mode": "token", - "pageSize": { "realm": "body", "path": "limit", "value": "100" }, - "in": { "realm": "payload", "path": "meta.pagination.after" }, - "out": { "realm": "body", "path": "after" } + "in": { + "realm": "payload", + "path": "meta.pagination.after" + }, + "out": { + "realm": "body", + "path": "after" + } }, "pathToData": "resources", - "expandInnerObjects": true + "expandInnerObjects": true, + "errorHandling": { + "type": "script", + "script": "errorHandling/alerts.js" + } }, "matches": "none", "ui": [ @@ -28,7 +40,13 @@ "name": "scope", "label": "Host or Host Group (optional)", "matches": { - "sourceType": { "type": "oneOf", "values": ["CrowdStrike Host", "CrowdStrike Host Group"] } + "sourceType": { + "type": "oneOf", + "values": [ + "CrowdStrike Host", + "CrowdStrike Host Group" + ] + } } }, { @@ -37,57 +55,178 @@ "label": "Status", "isMulti": true, "options": [ - { "value": "new", "label": "New" }, - { "value": "in_progress", "label": "In Progress" }, - { "value": "closed", "label": "Closed" }, - { "value": "reopened", "label": "Reopened" } + { + "value": "new", + "label": "New" + }, + { + "value": "in_progress", + "label": "In Progress" + }, + { + "value": "closed", + "label": "Closed" + }, + { + "value": "reopened", + "label": "Reopened" + } ] } ], "metadata": [ - { "name": "composite_id", "displayName": "ID", "shape": "string", "role": "id", "visible": false }, - { "name": "name", "displayName": "Name", "shape": "string", "role": "label" }, - { "name": "description", "displayName": "Description", "shape": "string" }, - { "name": "status", "displayName": "Status", "shape": "string" }, - { "name": "severity_name", "displayName": "Severity", "shape": "string" }, - { "name": "severity", "displayName": "Severity Score", "shape": "number" }, - { "name": "confidence", "displayName": "Confidence", "shape": "number" }, - { "name": "product", "displayName": "Product", "shape": "string" }, - { "name": "type", "displayName": "Alert Type", "shape": "string" }, - { "name": "tactic", "displayName": "Tactic", "shape": "string" }, - { "name": "technique", "displayName": "Technique", "shape": "string" }, - { "name": "device.device_id", "displayName": "Device ID", "shape": "string", "visible": false }, - { "name": "device.hostname", "displayName": "Hostname", "shape": "string" }, - { "name": "device.platform_name", "displayName": "Platform", "shape": "string" }, - { "name": "filename", "displayName": "File Name", "shape": "string" }, - { "name": "filepath", "displayName": "File Path", "shape": "string" }, - { "name": "cmdline", "displayName": "Command Line", "shape": "string" }, - { "name": "user_name", "displayName": "User", "shape": "string" }, - { "name": "tags", "displayName": "Tags", "shape": "string" }, - { "name": "created_timestamp", "displayName": "Created", "shape": "date", "role": "timestamp" }, - { "name": "updated_timestamp", "displayName": "Last Updated", "shape": "date" }, - { "name": "first_behavior", "displayName": "First Behavior", "shape": "date" }, - { "name": "last_behavior", "displayName": "Last Behavior", "shape": "date" }, + { + "name": "composite_id", + "displayName": "ID", + "shape": "string", + "role": "id", + "visible": false + }, + { + "name": "name", + "displayName": "Name", + "shape": "string", + "role": "label" + }, + { + "name": "description", + "displayName": "Description", + "shape": "string" + }, + { + "name": "status", + "displayName": "Status", + "shape": "string" + }, + { + "name": "severity_name", + "displayName": "Severity", + "shape": "string" + }, + { + "name": "severity", + "displayName": "Severity Score", + "shape": "number" + }, + { + "name": "confidence", + "displayName": "Confidence", + "shape": "number" + }, + { + "name": "product", + "displayName": "Product", + "shape": "string" + }, + { + "name": "type", + "displayName": "Alert Type", + "shape": "string" + }, + { + "name": "tactic", + "displayName": "Tactic", + "shape": "string" + }, + { + "name": "technique", + "displayName": "Technique", + "shape": "string" + }, + { + "name": "device.device_id", + "displayName": "Device ID", + "shape": "string", + "visible": false + }, + { + "name": "device.hostname", + "displayName": "Hostname", + "shape": "string" + }, + { + "name": "device.platform_name", + "displayName": "Platform", + "shape": "string" + }, + { + "name": "filename", + "displayName": "File Name", + "shape": "string" + }, + { + "name": "filepath", + "displayName": "File Path", + "shape": "string" + }, + { + "name": "cmdline", + "displayName": "Command Line", + "shape": "string" + }, + { + "name": "user_name", + "displayName": "User", + "shape": "string" + }, + { + "name": "tags", + "displayName": "Tags", + "shape": "string" + }, + { + "name": "created_timestamp", + "displayName": "Created", + "shape": "date", + "role": "timestamp" + }, + { + "name": "updated_timestamp", + "displayName": "Last Updated", + "shape": "date" + }, + { + "name": "first_behavior", + "displayName": "First Behavior", + "shape": "date" + }, + { + "name": "last_behavior", + "displayName": "Last Behavior", + "shape": "date" + }, { "name": "detectionLatencySeconds", "displayName": "Detection Latency", "computed": true, "valueExpression": "{{ ($['first_behavior'] && $['created_timestamp']) ? Math.max(0, (new Date($['created_timestamp']) - new Date($['first_behavior'])) / 1000) : null }}", - "shape": ["seconds", { "formatDuration": true }] + "shape": [ + "seconds", + { + "formatDuration": true + } + ] }, { "name": "responseLatencySeconds", "displayName": "Response Latency", "computed": true, "valueExpression": "{{ ($['status'] === 'closed' && $['updated_timestamp'] && $['created_timestamp']) ? Math.max(0, (new Date($['updated_timestamp']) - new Date($['created_timestamp'])) / 1000) : null }}", - "shape": ["seconds", { "formatDuration": true }] + "shape": [ + "seconds", + { + "formatDuration": true + } + ] }, { "sourceId": "device.device_id", "sourceType": "CrowdStrike Host", "name": "device.hostname" }, - { "pattern": ".*" } + { + "pattern": ".*" + } ], "timeframes": true } diff --git a/plugins/CrowdStrike/v1/dataStreams/devices.json b/plugins/CrowdStrike/v1/dataStreams/devices.json index 553293af..1bb71705 100644 --- a/plugins/CrowdStrike/v1/dataStreams/devices.json +++ b/plugins/CrowdStrike/v1/dataStreams/devices.json @@ -2,14 +2,23 @@ "name": "devices", "displayName": "Devices", "description": "Host inventory with platform, sensor, network, group membership and policy assignment detail, one row per device", - "tags": ["Security", "Hosts"], + "tags": [ + "Security", + "Hosts" + ], "baseDataSourceName": "httpRequestUnscoped", "config": { "httpMethod": "get", "endpointPath": "/devices/combined/devices/v1", "getArgs": [ - { "key": "sort", "value": "device_id.asc" }, - { "key": "fields", "value": "device_id,hostname,platform_name,os_version,product_type_desc,agent_version,status,reduced_functionality_mode,first_seen,last_seen,local_ip,external_ip,mac_address,machine_domain,site_name,serial_number,system_manufacturer,system_product_name,groups,tags,device_policies" }, + { + "key": "sort", + "value": "device_id.asc" + }, + { + "key": "fields", + "value": "device_id,hostname,platform_name,os_version,product_type_desc,agent_version,status,reduced_functionality_mode,first_seen,last_seen,local_ip,external_ip,mac_address,machine_domain,site_name,serial_number,system_manufacturer,system_product_name,groups,tags,device_policies" + }, { "key": "filter", "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"device_id\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') < 0)], [\"groups\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).join(\"+\") || null }}" @@ -17,12 +26,26 @@ ], "paging": { "mode": "token", - "pageSize": { "realm": "queryArg", "path": "limit", "value": "500" }, - "in": { "realm": "payload", "path": "meta.pagination.next" }, - "out": { "realm": "queryArg", "path": "offset" } + "pageSize": { + "realm": "queryArg", + "path": "limit", + "value": "500" + }, + "in": { + "realm": "payload", + "path": "meta.pagination.next" + }, + "out": { + "realm": "queryArg", + "path": "offset" + } }, "pathToData": "resources", - "expandInnerObjects": true + "expandInnerObjects": true, + "errorHandling": { + "type": "script", + "script": "errorHandling/devices.js" + } }, "matches": "none", "ui": [ @@ -31,17 +54,49 @@ "name": "scope", "label": "Host or Host Group (optional)", "matches": { - "sourceType": { "type": "oneOf", "values": ["CrowdStrike Host", "CrowdStrike Host Group"] } + "sourceType": { + "type": "oneOf", + "values": [ + "CrowdStrike Host", + "CrowdStrike Host Group" + ] + } } } ], "metadata": [ - { "name": "device_id", "displayName": "Device ID", "shape": "string", "visible": false }, - { "name": "hostname", "displayName": "Hostname", "shape": "string", "role": "label" }, - { "name": "platform_name", "displayName": "Platform", "shape": "string" }, - { "name": "os_version", "displayName": "OS Version", "shape": "string" }, - { "name": "product_type_desc", "displayName": "Product Type", "shape": "string" }, - { "name": "agent_version", "displayName": "Sensor Version", "shape": "string" }, + { + "name": "device_id", + "displayName": "Device ID", + "shape": "string", + "visible": false + }, + { + "name": "hostname", + "displayName": "Hostname", + "shape": "string", + "role": "label" + }, + { + "name": "platform_name", + "displayName": "Platform", + "shape": "string" + }, + { + "name": "os_version", + "displayName": "OS Version", + "shape": "string" + }, + { + "name": "product_type_desc", + "displayName": "Product Type", + "shape": "string" + }, + { + "name": "agent_version", + "displayName": "Sensor Version", + "shape": "string" + }, { "name": "status", "displayName": "Containment Status", @@ -49,26 +104,86 @@ "state", { "map": { - "success": ["normal"], - "warning": ["containment_pending", "lift_containment_pending"], - "error": ["contained"] + "success": [ + "normal" + ], + "warning": [ + "containment_pending", + "lift_containment_pending" + ], + "error": [ + "contained" + ] } } ] }, - { "name": "reduced_functionality_mode", "displayName": "Reduced Functionality Mode", "shape": "string" }, - { "name": "first_seen", "displayName": "First Seen", "shape": "date" }, - { "name": "last_seen", "displayName": "Last Seen", "shape": "date" }, - { "name": "local_ip", "displayName": "Local IP", "shape": "string" }, - { "name": "external_ip", "displayName": "External IP", "shape": "string" }, - { "name": "mac_address", "displayName": "MAC Address", "shape": "string" }, - { "name": "machine_domain", "displayName": "Domain", "shape": "string" }, - { "name": "site_name", "displayName": "Site", "shape": "string" }, - { "name": "serial_number", "displayName": "Serial Number", "shape": "string" }, - { "name": "system_manufacturer", "displayName": "Manufacturer", "shape": "string" }, - { "name": "system_product_name", "displayName": "Model", "shape": "string" }, - { "name": "groups", "displayName": "Host Group IDs", "shape": "string", "visible": false }, - { "name": "tags", "displayName": "Tags", "shape": "string" }, + { + "name": "reduced_functionality_mode", + "displayName": "Reduced Functionality Mode", + "shape": "string" + }, + { + "name": "first_seen", + "displayName": "First Seen", + "shape": "date" + }, + { + "name": "last_seen", + "displayName": "Last Seen", + "shape": "date" + }, + { + "name": "local_ip", + "displayName": "Local IP", + "shape": "string" + }, + { + "name": "external_ip", + "displayName": "External IP", + "shape": "string" + }, + { + "name": "mac_address", + "displayName": "MAC Address", + "shape": "string" + }, + { + "name": "machine_domain", + "displayName": "Domain", + "shape": "string" + }, + { + "name": "site_name", + "displayName": "Site", + "shape": "string" + }, + { + "name": "serial_number", + "displayName": "Serial Number", + "shape": "string" + }, + { + "name": "system_manufacturer", + "displayName": "Manufacturer", + "shape": "string" + }, + { + "name": "system_product_name", + "displayName": "Model", + "shape": "string" + }, + { + "name": "groups", + "displayName": "Host Group IDs", + "shape": "string", + "visible": false + }, + { + "name": "tags", + "displayName": "Tags", + "shape": "string" + }, { "name": "device_policies.prevention.applied", "displayName": "Prevention Policy Applied", diff --git a/plugins/CrowdStrike/v1/dataStreams/hostCount.json b/plugins/CrowdStrike/v1/dataStreams/hostCount.json new file mode 100644 index 00000000..ae0f2b08 --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/hostCount.json @@ -0,0 +1,86 @@ +{ + "name": "hostCount", + "displayName": "Host Count", + "description": "Number of hosts, optionally filtered by platform or containment status. Uses a single request, so it is fast on large tenants.", + "tags": [ + "Security" + ], + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "/devices/queries/devices/v1", + "getArgs": [ + { + "key": "limit", + "value": "1" + }, + { + "key": "filter", + "value": "{{ [ (typeof platform === 'undefined' || !platform ? [] : [].concat(platform).map(x => String(x && x.value !== undefined ? x.value : x))).map(v => \"platform_name:'\" + v + \"'\").join(\",\"), (typeof hostStatus === 'undefined' || !hostStatus ? [] : [].concat(hostStatus).map(x => String(x && x.value !== undefined ? x.value : x))).map(v => \"status:'\" + v + \"'\").join(\",\") ].filter(s => s).join(\"+\") || null }}" + } + ], + "paging": { + "mode": "none" + }, + "pathToData": "meta.pagination.total", + "errorHandling": { + "type": "script", + "script": "errorHandling/hostCount.js" + } + }, + "matches": "none", + "ui": [ + { + "type": "choiceChips", + "name": "platform", + "label": "Platform", + "isMulti": false, + "options": [ + { + "value": "Windows", + "label": "Windows" + }, + { + "value": "Mac", + "label": "Mac" + }, + { + "value": "Linux", + "label": "Linux" + } + ] + }, + { + "type": "choiceChips", + "name": "hostStatus", + "label": "Containment status", + "isMulti": false, + "options": [ + { + "value": "normal", + "label": "Normal" + }, + { + "value": "contained", + "label": "Contained" + }, + { + "value": "containment_pending", + "label": "Containment pending" + }, + { + "value": "lift_containment_pending", + "label": "Lift containment pending" + } + ] + } + ], + "metadata": [ + { + "name": "result", + "displayName": "Hosts", + "shape": "number" + } + ], + "timeframes": false +} diff --git a/plugins/CrowdStrike/v1/dataStreams/recentHosts.json b/plugins/CrowdStrike/v1/dataStreams/recentHosts.json new file mode 100644 index 00000000..44ac2c67 --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/recentHosts.json @@ -0,0 +1,119 @@ +{ + "name": "recentHosts", + "displayName": "Recently Seen Hosts", + "description": "The 100 most recently seen hosts. A single request, so it is fast on large tenants.", + "tags": [ + "Security" + ], + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "/devices/combined/devices/v1", + "getArgs": [ + { + "key": "limit", + "value": "100" + }, + { + "key": "sort", + "value": "last_seen.desc" + }, + { + "key": "fields", + "value": "device_id,hostname,platform_name,os_version,product_type_desc,agent_version,status,first_seen,last_seen,local_ip,external_ip,site_name,groups" + } + ], + "paging": { + "mode": "none" + }, + "pathToData": "resources" + }, + "matches": "none", + "metadata": [ + { + "name": "device_id", + "displayName": "Device ID", + "shape": "string", + "visible": false + }, + { + "name": "hostname", + "displayName": "Hostname", + "shape": "string", + "role": "label" + }, + { + "name": "platform_name", + "displayName": "Platform", + "shape": "string" + }, + { + "name": "os_version", + "displayName": "OS Version", + "shape": "string" + }, + { + "name": "product_type_desc", + "displayName": "Product Type", + "shape": "string" + }, + { + "name": "agent_version", + "displayName": "Sensor Version", + "shape": "string" + }, + { + "name": "status", + "displayName": "Containment Status", + "shape": [ + "state", + { + "map": { + "success": [ + "normal" + ], + "warning": [ + "containment_pending", + "lift_containment_pending" + ], + "error": [ + "contained" + ] + } + } + ] + }, + { + "name": "first_seen", + "displayName": "First Seen", + "shape": "date" + }, + { + "name": "last_seen", + "displayName": "Last Seen", + "shape": "date" + }, + { + "name": "local_ip", + "displayName": "Local IP", + "shape": "string" + }, + { + "name": "external_ip", + "displayName": "External IP", + "shape": "string" + }, + { + "name": "site_name", + "displayName": "Site", + "shape": "string" + }, + { + "name": "groups", + "displayName": "Host Group IDs", + "shape": "string", + "visible": false + } + ], + "timeframes": false +} diff --git a/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/alerts.js b/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/alerts.js new file mode 100644 index 00000000..bb83e2c1 --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/alerts.js @@ -0,0 +1,3 @@ +const e = data && data.errors && data.errors[0]; + +result = (e && e.message) || (data && data.message) || ('Request failed with HTTP ' + response.status); diff --git a/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/devices.js b/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/devices.js new file mode 100644 index 00000000..bb83e2c1 --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/devices.js @@ -0,0 +1,3 @@ +const e = data && data.errors && data.errors[0]; + +result = (e && e.message) || (data && data.message) || ('Request failed with HTTP ' + response.status); diff --git a/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/hostCount.js b/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/hostCount.js new file mode 100644 index 00000000..bb83e2c1 --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/hostCount.js @@ -0,0 +1,3 @@ +const e = data && data.errors && data.errors[0]; + +result = (e && e.message) || (data && data.message) || ('Request failed with HTTP ' + response.status); diff --git a/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/vulnerabilities.js b/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/vulnerabilities.js new file mode 100644 index 00000000..bb83e2c1 --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/vulnerabilities.js @@ -0,0 +1,3 @@ +const e = data && data.errors && data.errors[0]; + +result = (e && e.message) || (data && data.message) || ('Request failed with HTTP ' + response.status); diff --git a/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/vulnerabilityCount.js b/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/vulnerabilityCount.js new file mode 100644 index 00000000..bb83e2c1 --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/vulnerabilityCount.js @@ -0,0 +1,3 @@ +const e = data && data.errors && data.errors[0]; + +result = (e && e.message) || (data && data.message) || ('Request failed with HTTP ' + response.status); diff --git a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json index 71436fd6..562a920c 100644 --- a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json +++ b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json @@ -2,13 +2,19 @@ "name": "vulnerabilities", "displayName": "Vulnerabilities", "description": "Open Spotlight vulnerabilities with CVE, severity and remediation detail, one row per vulnerability finding", - "tags": ["Security", "Vulnerabilities"], + "tags": [ + "Security", + "Vulnerabilities" + ], "baseDataSourceName": "httpRequestUnscoped", "config": { "httpMethod": "get", "endpointPath": "/spotlight/combined/vulnerabilities/v1", "getArgs": [ - { "key": "facet", "value": "host_info" }, + { + "key": "facet", + "value": "host_info" + }, { "key": "filter", "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"aid\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') < 0)], [\"host_info.groups\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).concat((typeof status === 'undefined' || !status || !status.length ? [ \"status:['open','reopen']\" ] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") }}" @@ -16,12 +22,26 @@ ], "paging": { "mode": "token", - "pageSize": { "realm": "queryArg", "path": "limit", "value": "200" }, - "in": { "realm": "payload", "path": "meta.pagination.after" }, - "out": { "realm": "queryArg", "path": "after" } + "pageSize": { + "realm": "queryArg", + "path": "limit", + "value": "200" + }, + "in": { + "realm": "payload", + "path": "meta.pagination.after" + }, + "out": { + "realm": "queryArg", + "path": "after" + } }, "pathToData": "resources", - "expandInnerObjects": true + "expandInnerObjects": true, + "errorHandling": { + "type": "script", + "script": "errorHandling/vulnerabilities.js" + } }, "matches": "none", "ui": [ @@ -30,7 +50,13 @@ "name": "scope", "label": "Host or Host Group (optional)", "matches": { - "sourceType": { "type": "oneOf", "values": ["CrowdStrike Host", "CrowdStrike Host Group"] } + "sourceType": { + "type": "oneOf", + "values": [ + "CrowdStrike Host", + "CrowdStrike Host Group" + ] + } } }, { @@ -39,29 +65,106 @@ "label": "Status", "isMulti": true, "options": [ - { "value": "open", "label": "Open" }, - { "value": "closed", "label": "Closed" }, - { "value": "reopen", "label": "Reopened" }, - { "value": "expired", "label": "Expired" } + { + "value": "open", + "label": "Open" + }, + { + "value": "closed", + "label": "Closed" + }, + { + "value": "reopen", + "label": "Reopened" + }, + { + "value": "expired", + "label": "Expired" + } ] } ], "metadata": [ - { "name": "id", "displayName": "ID", "shape": "string", "role": "id", "visible": false }, - { "name": "aid", "displayName": "Device ID", "shape": "string", "visible": false }, - { "name": "cve.id", "displayName": "CVE", "shape": "string", "role": "label" }, - { "name": "cve.severity", "displayName": "CVE Severity", "shape": "string" }, - { "name": "cve.base_score", "displayName": "CVSS Score", "shape": "number" }, - { "name": "cve.exploit_status", "displayName": "Exploit Status", "shape": "string" }, - { "name": "cve.published_date", "displayName": "CVE Published", "shape": "date" }, - { "name": "status", "displayName": "Status", "shape": "string" }, - { "name": "host_info.hostname", "displayName": "Hostname", "shape": "string" }, - { "name": "host_info.platform", "displayName": "Platform", "shape": "string" }, - { "name": "host_info.local_ip", "displayName": "Local IP", "shape": "string" }, - { "name": "app.product_name_version", "displayName": "Affected Product", "shape": "string" }, - { "name": "created_timestamp", "displayName": "First Found", "shape": "date", "role": "timestamp" }, - { "name": "updated_timestamp", "displayName": "Last Updated", "shape": "date" }, - { "name": "closed_timestamp", "displayName": "Closed", "shape": "date" }, + { + "name": "id", + "displayName": "ID", + "shape": "string", + "role": "id", + "visible": false + }, + { + "name": "aid", + "displayName": "Device ID", + "shape": "string", + "visible": false + }, + { + "name": "cve.id", + "displayName": "CVE", + "shape": "string", + "role": "label" + }, + { + "name": "cve.severity", + "displayName": "CVE Severity", + "shape": "string" + }, + { + "name": "cve.base_score", + "displayName": "CVSS Score", + "shape": "number" + }, + { + "name": "cve.exploit_status", + "displayName": "Exploit Status", + "shape": "string" + }, + { + "name": "cve.published_date", + "displayName": "CVE Published", + "shape": "date" + }, + { + "name": "status", + "displayName": "Status", + "shape": "string" + }, + { + "name": "host_info.hostname", + "displayName": "Hostname", + "shape": "string" + }, + { + "name": "host_info.platform", + "displayName": "Platform", + "shape": "string" + }, + { + "name": "host_info.local_ip", + "displayName": "Local IP", + "shape": "string" + }, + { + "name": "app.product_name_version", + "displayName": "Affected Product", + "shape": "string" + }, + { + "name": "created_timestamp", + "displayName": "First Found", + "shape": "date", + "role": "timestamp" + }, + { + "name": "updated_timestamp", + "displayName": "Last Updated", + "shape": "date" + }, + { + "name": "closed_timestamp", + "displayName": "Closed", + "shape": "date" + }, { "name": "daysOpen", "displayName": "Days Open", @@ -69,8 +172,14 @@ "valueExpression": "{{ $['created_timestamp'] ? Math.floor((Date.now() - new Date($['created_timestamp'])) / 86400000) : null }}", "shape": "number" }, - { "sourceId": "aid", "sourceType": "CrowdStrike Host", "name": "host_info.hostname" }, - { "pattern": ".*" } + { + "sourceId": "aid", + "sourceType": "CrowdStrike Host", + "name": "host_info.hostname" + }, + { + "pattern": ".*" + } ], "timeframes": false } diff --git a/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json b/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json new file mode 100644 index 00000000..654e8e0a --- /dev/null +++ b/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json @@ -0,0 +1,105 @@ +{ + "name": "vulnerabilityCount", + "displayName": "Vulnerability Count", + "description": "Number of Spotlight vulnerabilities, optionally filtered by host, host group, severity and status. Uses a single request, so it is fast on large tenants.", + "tags": [ + "Security", + "Vulnerabilities" + ], + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "/spotlight/combined/vulnerabilities/v1", + "getArgs": [ + { + "key": "limit", + "value": "1" + }, + { + "key": "filter", + "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"aid\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') < 0)], [\"host_info.groups\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).concat((typeof severity === 'undefined' || !severity ? [] : [].concat(severity).map(x => String(x && x.value !== undefined ? x.value : x))).length ? [ \"cve.severity:[\" + (typeof severity === 'undefined' || !severity ? [] : [].concat(severity).map(x => String(x && x.value !== undefined ? x.value : x))).map(v => \"'\" + v + \"'\").join(\",\") + \"]\" ] : []).concat((typeof status === 'undefined' || !status ? [] : [].concat(status).map(x => String(x && x.value !== undefined ? x.value : x))).length ? [ \"status:[\" + (typeof status === 'undefined' || !status ? [] : [].concat(status).map(x => String(x && x.value !== undefined ? x.value : x))).map(v => \"'\" + v + \"'\").join(\",\") + \"]\" ] : [ \"status:['open','reopen']\" ]).join(\"+\") }}" + } + ], + "paging": { + "mode": "none" + }, + "pathToData": "meta.pagination.total", + "errorHandling": { + "type": "script", + "script": "errorHandling/vulnerabilityCount.js" + } + }, + "matches": "none", + "ui": [ + { + "type": "objects", + "name": "scope", + "label": "Host or Host Group (optional)", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "CrowdStrike Host", + "CrowdStrike Host Group" + ] + } + } + }, + { + "type": "choiceChips", + "name": "severity", + "label": "Severity", + "isMulti": true, + "options": [ + { + "value": "CRITICAL", + "label": "Critical" + }, + { + "value": "HIGH", + "label": "High" + }, + { + "value": "MEDIUM", + "label": "Medium" + }, + { + "value": "LOW", + "label": "Low" + } + ] + }, + { + "type": "choiceChips", + "name": "status", + "label": "Status", + "isMulti": true, + "options": [ + { + "value": "open", + "label": "Open" + }, + { + "value": "closed", + "label": "Closed" + }, + { + "value": "reopen", + "label": "Reopened" + }, + { + "value": "expired", + "label": "Expired" + } + ] + } + ], + "metadata": [ + { + "name": "result", + "displayName": "Vulnerabilities", + "shape": "number" + } + ], + "timeframes": false +} diff --git a/plugins/CrowdStrike/v1/defaultContent/hostGroupPerspective.dash.json b/plugins/CrowdStrike/v1/defaultContent/hostGroupPerspective.dash.json index 09906428..05d28937 100644 --- a/plugins/CrowdStrike/v1/defaultContent/hostGroupPerspective.dash.json +++ b/plugins/CrowdStrike/v1/defaultContent/hostGroupPerspective.dash.json @@ -2,7 +2,9 @@ "name": "Host Group", "schemaVersion": "1.5", "timeframe": "last7days", - "variables": ["{{variables.[Host Group]}}"], + "variables": [ + "{{variables.[Host Group]}}" + ], "dashboard": { "_type": "layout/grid", "columns": 4, @@ -21,9 +23,13 @@ "_type": "tile/data-stream", "title": "Hosts", "description": "", - "activePluginConfigIds": ["{{configId}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], "timeframe": "none", - "variables": ["{{variables.[Host Group]}}"], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { "id": "{{dataStreams.[devices]}}", "name": "devices", @@ -35,11 +41,23 @@ "scope": "{{scopes.[Host Groups]}}" } }, - "group": { "by": [], "aggregate": [{ "type": "count" }] } + "group": { + "by": [], + "aggregate": [ + { + "type": "count" + } + ] + } }, "visualisation": { "type": "data-stream-scalar", - "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + "config": { + "data-stream-scalar": { + "value": "count", + "comparisonColumn": "none" + } + } } } }, @@ -56,9 +74,13 @@ "_type": "tile/data-stream", "title": "Prevention Policy Applied", "description": "Hosts with a prevention policy applied", - "activePluginConfigIds": ["{{configId}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], "timeframe": "none", - "variables": ["{{variables.[Host Group]}}"], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { "id": "{{dataStreams.[devices]}}", "name": "devices", @@ -73,14 +95,30 @@ "filter": { "multiOperation": "and", "filters": [ - { "column": "device_policies.prevention.applied", "operation": "equals", "value": "true" } + { + "column": "device_policies.prevention.applied", + "operation": "equals", + "value": "true" + } ] }, - "group": { "by": [], "aggregate": [{ "type": "count" }] } + "group": { + "by": [], + "aggregate": [ + { + "type": "count" + } + ] + } }, "visualisation": { "type": "data-stream-scalar", - "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + "config": { + "data-stream-scalar": { + "value": "count", + "comparisonColumn": "none" + } + } } } }, @@ -97,9 +135,13 @@ "_type": "tile/data-stream", "title": "Sensor Update Policy Applied", "description": "Hosts with a sensor update policy applied", - "activePluginConfigIds": ["{{configId}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], "timeframe": "none", - "variables": ["{{variables.[Host Group]}}"], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { "id": "{{dataStreams.[devices]}}", "name": "devices", @@ -121,11 +163,23 @@ } ] }, - "group": { "by": [], "aggregate": [{ "type": "count" }] } + "group": { + "by": [], + "aggregate": [ + { + "type": "count" + } + ] + } }, "visualisation": { "type": "data-stream-scalar", - "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + "config": { + "data-stream-scalar": { + "value": "count", + "comparisonColumn": "none" + } + } } } }, @@ -141,30 +195,37 @@ "config": { "_type": "tile/data-stream", "title": "Open Vulnerabilities", - "description": "", - "activePluginConfigIds": ["{{configId}}"], + "description": "Open vulnerabilities on hosts in this group", + "activePluginConfigIds": [ + "{{configId}}" + ], "timeframe": "none", - "variables": ["{{variables.[Host Group]}}"], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { - "id": "{{dataStreams.[vulnerabilities]}}", - "name": "vulnerabilities", + "id": "{{dataStreams.[vulnerabilityCount]}}", + "name": "vulnerabilityCount", "pluginConfigId": "{{configId}}", "dataSourceConfig": { "scope": { "variable": "{{variables.[Host Group]}}", "workspace": "{{workspaceId}}", "scope": "{{scopes.[Host Groups]}}" - } - }, - "filter": { - "multiOperation": "and", - "filters": [{ "column": "status", "operation": "equals", "value": "open" }] - }, - "group": { "by": [], "aggregate": [{ "type": "count" }] } + }, + "status": [ + "open" + ] + } }, "visualisation": { "type": "data-stream-scalar", - "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + "config": { + "data-stream-scalar": { + "value": "result", + "comparisonColumn": "none" + } + } } } }, @@ -181,9 +242,13 @@ "_type": "tile/data-stream", "title": "OS / Platform Breakdown", "description": "", - "activePluginConfigIds": ["{{configId}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], "timeframe": "none", - "variables": ["{{variables.[Host Group]}}"], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { "id": "{{dataStreams.[devices]}}", "name": "devices", @@ -196,8 +261,17 @@ } }, "group": { - "by": [["platform_name", "uniqueValues"]], - "aggregate": [{ "type": "count" }] + "by": [ + [ + "platform_name", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "count" + } + ] } }, "visualisation": { @@ -227,9 +301,13 @@ "_type": "tile/data-stream", "title": "Sensor Version Distribution", "description": "", - "activePluginConfigIds": ["{{configId}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], "timeframe": "none", - "variables": ["{{variables.[Host Group]}}"], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { "id": "{{dataStreams.[devices]}}", "name": "devices", @@ -242,8 +320,17 @@ } }, "group": { - "by": [["agent_version", "uniqueValues"]], - "aggregate": [{ "type": "count" }] + "by": [ + [ + "agent_version", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "count" + } + ] } }, "visualisation": { @@ -273,9 +360,13 @@ "_type": "tile/data-stream", "title": "Prevention Policies", "description": "", - "activePluginConfigIds": ["{{configId}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], "timeframe": "none", - "variables": ["{{variables.[Host Group]}}"], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { "id": "{{dataStreams.[preventionPolicies]}}", "name": "preventionPolicies", @@ -291,8 +382,17 @@ "config": { "data-stream-table": { "transpose": false, - "columnOrder": ["name", "platform_name", "enabled", "description", "modified_timestamp"], - "hiddenColumns": ["id", "created_timestamp"] + "columnOrder": [ + "name", + "platform_name", + "enabled", + "description", + "modified_timestamp" + ], + "hiddenColumns": [ + "id", + "created_timestamp" + ] } } } @@ -311,9 +411,13 @@ "_type": "tile/data-stream", "title": "Sensor Update Policies", "description": "", - "activePluginConfigIds": ["{{configId}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], "timeframe": "none", - "variables": ["{{variables.[Host Group]}}"], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { "id": "{{dataStreams.[sensorUpdatePolicies]}}", "name": "sensorUpdatePolicies", @@ -336,7 +440,11 @@ "settings.build", "modified_timestamp" ], - "hiddenColumns": ["id", "description", "created_timestamp"] + "hiddenColumns": [ + "id", + "description", + "created_timestamp" + ] } } } @@ -355,8 +463,12 @@ "_type": "tile/data-stream", "title": "Alerts", "description": "Alerts created within the dashboard timeframe", - "activePluginConfigIds": ["{{configId}}"], - "variables": ["{{variables.[Host Group]}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { "id": "{{dataStreams.[alerts]}}", "name": "alerts", @@ -368,11 +480,23 @@ "scope": "{{scopes.[Host Groups]}}" } }, - "group": { "by": [], "aggregate": [{ "type": "count" }] } + "group": { + "by": [], + "aggregate": [ + { + "type": "count" + } + ] + } }, "visualisation": { "type": "data-stream-scalar", - "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + "config": { + "data-stream-scalar": { + "value": "count", + "comparisonColumn": "none" + } + } } } }, @@ -389,8 +513,12 @@ "_type": "tile/data-stream", "title": "Avg Detection Latency", "description": "Average time between first behavior and alert creation", - "activePluginConfigIds": ["{{configId}}"], - "variables": ["{{variables.[Host Group]}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { "id": "{{dataStreams.[alerts]}}", "name": "alerts", @@ -404,7 +532,14 @@ }, "group": { "by": [], - "aggregate": [{ "type": "mean", "names": ["detectionLatencySeconds"] }] + "aggregate": [ + { + "type": "mean", + "names": [ + "detectionLatencySeconds" + ] + } + ] } }, "visualisation": { @@ -431,8 +566,12 @@ "_type": "tile/data-stream", "title": "Avg Response Latency", "description": "Average time between alert creation and closure", - "activePluginConfigIds": ["{{configId}}"], - "variables": ["{{variables.[Host Group]}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { "id": "{{dataStreams.[alerts]}}", "name": "alerts", @@ -446,7 +585,14 @@ }, "group": { "by": [], - "aggregate": [{ "type": "mean", "names": ["responseLatencySeconds"] }] + "aggregate": [ + { + "type": "mean", + "names": [ + "responseLatencySeconds" + ] + } + ] } }, "visualisation": { @@ -473,8 +619,12 @@ "_type": "tile/data-stream", "title": "Alerts by Severity", "description": "", - "activePluginConfigIds": ["{{configId}}"], - "variables": ["{{variables.[Host Group]}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { "id": "{{dataStreams.[alerts]}}", "name": "alerts", @@ -487,8 +637,17 @@ } }, "group": { - "by": [["severity_name", "uniqueValues"]], - "aggregate": [{ "type": "count" }] + "by": [ + [ + "severity_name", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "count" + } + ] } }, "visualisation": { @@ -518,8 +677,12 @@ "_type": "tile/data-stream", "title": "Alerts by Status", "description": "", - "activePluginConfigIds": ["{{configId}}"], - "variables": ["{{variables.[Host Group]}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { "id": "{{dataStreams.[alerts]}}", "name": "alerts", @@ -532,17 +695,35 @@ } }, "group": { - "by": [["status", "uniqueValues"]], - "aggregate": [{ "type": "count" }] + "by": [ + [ + "status", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "count" + } + ] }, - "sort": { "by": [["count", "desc"]] } + "sort": { + "by": [ + [ + "count", + "desc" + ] + ] + } }, "visualisation": { "type": "data-stream-bar-chart", "config": { "data-stream-bar-chart": { "xAxisData": "status_uniqueValues", - "yAxisData": ["count"], + "yAxisData": [ + "count" + ], "xAxisGroup": "none", "xAxisLabel": "", "yAxisLabel": "Alerts", @@ -556,7 +737,9 @@ "showTotals": false, "showValue": true, "grouping": false, - "range": { "type": "auto" } + "range": { + "type": "auto" + } } } } @@ -575,8 +758,12 @@ "_type": "tile/data-stream", "title": "Recent Alerts", "description": "", - "activePluginConfigIds": ["{{configId}}"], - "variables": ["{{variables.[Host Group]}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { "id": "{{dataStreams.[alerts]}}", "name": "alerts", @@ -588,7 +775,15 @@ "scope": "{{scopes.[Host Groups]}}" } }, - "sort": { "by": [["created_timestamp", "desc"]], "top": 15 } + "sort": { + "by": [ + [ + "created_timestamp", + "desc" + ] + ], + "top": 15 + } }, "visualisation": { "type": "data-stream-table", @@ -642,9 +837,13 @@ "_type": "tile/data-stream", "title": "Vulnerabilities by Severity", "description": "Open vulnerabilities only", - "activePluginConfigIds": ["{{configId}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], "timeframe": "none", - "variables": ["{{variables.[Host Group]}}"], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { "id": "{{dataStreams.[vulnerabilities]}}", "name": "vulnerabilities", @@ -658,11 +857,26 @@ }, "filter": { "multiOperation": "and", - "filters": [{ "column": "status", "operation": "equals", "value": "open" }] + "filters": [ + { + "column": "status", + "operation": "equals", + "value": "open" + } + ] }, "group": { - "by": [["cve.severity", "uniqueValues"]], - "aggregate": [{ "type": "count" }] + "by": [ + [ + "cve.severity", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "count" + } + ] } }, "visualisation": { @@ -692,9 +906,13 @@ "_type": "tile/data-stream", "title": "Top Vulnerable Hosts", "description": "Open vulnerabilities with the highest CVSS score, in this group", - "activePluginConfigIds": ["{{configId}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], "timeframe": "none", - "variables": ["{{variables.[Host Group]}}"], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { "id": "{{dataStreams.[vulnerabilities]}}", "name": "vulnerabilities", @@ -708,9 +926,23 @@ }, "filter": { "multiOperation": "and", - "filters": [{ "column": "status", "operation": "equals", "value": "open" }] + "filters": [ + { + "column": "status", + "operation": "equals", + "value": "open" + } + ] }, - "sort": { "by": [["cve.base_score", "desc"]], "top": 10 } + "sort": { + "by": [ + [ + "cve.base_score", + "desc" + ] + ], + "top": 10 + } }, "visualisation": { "type": "data-stream-table", @@ -755,9 +987,13 @@ "_type": "tile/data-stream", "title": "Member Devices", "description": "", - "activePluginConfigIds": ["{{configId}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], "timeframe": "none", - "variables": ["{{variables.[Host Group]}}"], + "variables": [ + "{{variables.[Host Group]}}" + ], "dataStream": { "id": "{{dataStreams.[devices]}}", "name": "devices", @@ -769,7 +1005,14 @@ "scope": "{{scopes.[Host Groups]}}" } }, - "sort": { "by": [["last_seen", "desc"]] } + "sort": { + "by": [ + [ + "last_seen", + "desc" + ] + ] + } }, "visualisation": { "type": "data-stream-table", diff --git a/plugins/CrowdStrike/v1/defaultContent/overview.dash.json b/plugins/CrowdStrike/v1/defaultContent/overview.dash.json index 0755a589..710d7ca4 100644 --- a/plugins/CrowdStrike/v1/defaultContent/overview.dash.json +++ b/plugins/CrowdStrike/v1/defaultContent/overview.dash.json @@ -20,17 +20,24 @@ "_type": "tile/data-stream", "title": "Total Hosts", "description": "", - "activePluginConfigIds": ["{{configId}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], "timeframe": "none", "dataStream": { - "id": "{{dataStreams.[devices]}}", - "name": "devices", + "id": "{{dataStreams.[hostCount]}}", + "name": "hostCount", "pluginConfigId": "{{configId}}", - "group": { "by": [], "aggregate": [{ "type": "count" }] } + "dataSourceConfig": {} }, "visualisation": { "type": "data-stream-scalar", - "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + "config": { + "data-stream-scalar": { + "value": "result", + "comparisonColumn": "none" + } + } } } }, @@ -47,20 +54,40 @@ "_type": "tile/data-stream", "title": "Active Alerts", "description": "Alerts not yet closed, created within the dashboard timeframe", - "activePluginConfigIds": ["{{configId}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], "dataStream": { "id": "{{dataStreams.[alerts]}}", "name": "alerts", "pluginConfigId": "{{configId}}", "filter": { "multiOperation": "and", - "filters": [{ "column": "status", "operation": "notequals", "value": "closed" }] + "filters": [ + { + "column": "status", + "operation": "notequals", + "value": "closed" + } + ] }, - "group": { "by": [], "aggregate": [{ "type": "count" }] } + "group": { + "by": [], + "aggregate": [ + { + "type": "count" + } + ] + } }, "visualisation": { "type": "data-stream-scalar", - "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + "config": { + "data-stream-scalar": { + "value": "count", + "comparisonColumn": "none" + } + } } } }, @@ -76,25 +103,33 @@ "config": { "_type": "tile/data-stream", "title": "Open Critical/High Vulnerabilities", - "description": "Open vulnerabilities with a CVSS base score of 7.0 or above", - "activePluginConfigIds": ["{{configId}}"], + "description": "Open vulnerabilities with Critical or High severity", + "activePluginConfigIds": [ + "{{configId}}" + ], "timeframe": "none", "dataStream": { - "id": "{{dataStreams.[vulnerabilities]}}", - "name": "vulnerabilities", + "id": "{{dataStreams.[vulnerabilityCount]}}", + "name": "vulnerabilityCount", "pluginConfigId": "{{configId}}", - "filter": { - "multiOperation": "and", - "filters": [ - { "column": "status", "operation": "equals", "value": "open" }, - { "column": "cve.base_score", "operation": "greaterthan", "value": "6.9" } + "dataSourceConfig": { + "severity": [ + "CRITICAL", + "HIGH" + ], + "status": [ + "open" ] - }, - "group": { "by": [], "aggregate": [{ "type": "count" }] } + } }, "visualisation": { "type": "data-stream-scalar", - "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } + "config": { + "data-stream-scalar": { + "value": "result", + "comparisonColumn": "none" + } + } } } }, @@ -111,57 +146,26 @@ "_type": "tile/data-stream", "title": "Contained Hosts", "description": "Hosts currently network-contained", - "activePluginConfigIds": ["{{configId}}"], - "timeframe": "none", - "dataStream": { - "id": "{{dataStreams.[devices]}}", - "name": "devices", - "pluginConfigId": "{{configId}}", - "filter": { - "multiOperation": "and", - "filters": [{ "column": "status", "operation": "equals", "value": "contained" }] - }, - "group": { "by": [], "aggregate": [{ "type": "count" }] } - }, - "visualisation": { - "type": "data-stream-scalar", - "config": { "data-stream-scalar": { "value": "count", "comparisonColumn": "none" } } - } - } - }, - { - "i": "497a187f-7f06-4395-8ff1-2ba3d2a9a2f6", - "x": 0, - "y": 2, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Hosts by Platform", - "description": "", - "activePluginConfigIds": ["{{configId}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], "timeframe": "none", "dataStream": { - "id": "{{dataStreams.[devices]}}", - "name": "devices", + "id": "{{dataStreams.[hostCount]}}", + "name": "hostCount", "pluginConfigId": "{{configId}}", - "group": { - "by": [["platform_name", "uniqueValues"]], - "aggregate": [{ "type": "count" }] + "dataSourceConfig": { + "hostStatus": [ + "contained" + ] } }, "visualisation": { - "type": "data-stream-donut-chart", + "type": "data-stream-scalar", "config": { - "data-stream-donut-chart": { - "valueColumn": "count", - "labelColumn": "platform_name_uniqueValues", - "showValuesAsPercentage": true, - "legendPosition": "auto", - "legendMode": "table" + "data-stream-scalar": { + "value": "result", + "comparisonColumn": "none" } } } @@ -169,8 +173,8 @@ }, { "i": "d34b48d7-a07a-434a-a86c-e94cf26beaa6", - "x": 2, - "y": 2, + "x": 0, + "y": 6, "w": 2, "h": 3, "moved": false, @@ -180,14 +184,25 @@ "_type": "tile/data-stream", "title": "Alerts by Severity", "description": "", - "activePluginConfigIds": ["{{configId}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], "dataStream": { "id": "{{dataStreams.[alerts]}}", "name": "alerts", "pluginConfigId": "{{configId}}", "group": { - "by": [["severity_name", "uniqueValues"]], - "aggregate": [{ "type": "count" }] + "by": [ + [ + "severity_name", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "count" + } + ] } }, "visualisation": { @@ -206,8 +221,8 @@ }, { "i": "bd32d0d4-022a-4c24-8683-f29c2d473cc3", - "x": 0, - "y": 5, + "x": 2, + "y": 6, "w": 2, "h": 3, "moved": false, @@ -217,23 +232,43 @@ "_type": "tile/data-stream", "title": "Alerts by Status", "description": "", - "activePluginConfigIds": ["{{configId}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], "dataStream": { "id": "{{dataStreams.[alerts]}}", "name": "alerts", "pluginConfigId": "{{configId}}", "group": { - "by": [["status", "uniqueValues"]], - "aggregate": [{ "type": "count" }] + "by": [ + [ + "status", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "count" + } + ] }, - "sort": { "by": [["count", "desc"]] } + "sort": { + "by": [ + [ + "count", + "desc" + ] + ] + } }, "visualisation": { "type": "data-stream-bar-chart", "config": { "data-stream-bar-chart": { "xAxisData": "status_uniqueValues", - "yAxisData": ["count"], + "yAxisData": [ + "count" + ], "xAxisGroup": "none", "xAxisLabel": "", "yAxisLabel": "Alerts", @@ -247,104 +282,9 @@ "showTotals": false, "showValue": true, "grouping": false, - "range": { "type": "auto" } - } - } - } - } - }, - { - "i": "8cb63cf7-a111-438b-b114-bb3a6389b025", - "x": 2, - "y": 5, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Vulnerabilities by Severity", - "description": "Open vulnerabilities only", - "activePluginConfigIds": ["{{configId}}"], - "timeframe": "none", - "dataStream": { - "id": "{{dataStreams.[vulnerabilities]}}", - "name": "vulnerabilities", - "pluginConfigId": "{{configId}}", - "filter": { - "multiOperation": "and", - "filters": [{ "column": "status", "operation": "equals", "value": "open" }] - }, - "group": { - "by": [["cve.severity", "uniqueValues"]], - "aggregate": [{ "type": "count" }] - } - }, - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "count", - "labelColumn": "cve.severity_uniqueValues", - "showValuesAsPercentage": true, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "7f0edf44-3986-4894-9225-80d025b6ec45", - "x": 0, - "y": 8, - "w": 2, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Top Vulnerabilities", - "description": "Open vulnerabilities with the highest CVSS score, account-wide", - "activePluginConfigIds": ["{{configId}}"], - "timeframe": "none", - "dataStream": { - "id": "{{dataStreams.[vulnerabilities]}}", - "name": "vulnerabilities", - "pluginConfigId": "{{configId}}", - "filter": { - "multiOperation": "and", - "filters": [{ "column": "status", "operation": "equals", "value": "open" }] - }, - "sort": { "by": [["cve.base_score", "desc"]], "top": 10 } - }, - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": false, - "columnOrder": [ - "cve.id", - "cve.severity", - "cve.base_score", - "host_info.hostname", - "host_info.platform", - "cve.exploit_status", - "status", - "created_timestamp" - ], - "hiddenColumns": [ - "id", - "aid", - "host_info.local_ip", - "app.product_name_version", - "cve.published_date", - "updated_timestamp", - "closed_timestamp", - "daysOpen" - ] + "range": { + "type": "auto" + } } } } @@ -352,24 +292,25 @@ }, { "i": "fc1918d4-3d62-4fe9-aa54-e206e12b1130", - "x": 2, - "y": 8, - "w": 2, + "x": 0, + "y": 9, + "w": 4, "h": 4, "moved": false, "static": false, "z": 0, "config": { "_type": "tile/data-stream", - "title": "Device Inventory", - "description": "Most recently seen hosts, account-wide", - "activePluginConfigIds": ["{{configId}}"], + "title": "Recently Seen Hosts", + "description": "The 100 most recently seen hosts", + "activePluginConfigIds": [ + "{{configId}}" + ], "timeframe": "none", "dataStream": { - "id": "{{dataStreams.[devices]}}", - "name": "devices", - "pluginConfigId": "{{configId}}", - "sort": { "by": [["last_seen", "desc"]], "top": 20 } + "id": "{{dataStreams.[recentHosts]}}", + "name": "recentHosts", + "pluginConfigId": "{{configId}}" }, "visualisation": { "type": "data-stream-table", @@ -409,7 +350,7 @@ { "i": "34f983b0-6cc3-4091-8e04-1870ade28cda", "x": 0, - "y": 12, + "y": 13, "w": 4, "h": 4, "moved": false, @@ -419,7 +360,9 @@ "_type": "tile/data-stream", "title": "Sensor Usage", "description": "Weekly average of unique sensors seen reporting", - "activePluginConfigIds": ["{{configId}}"], + "activePluginConfigIds": [ + "{{configId}}" + ], "timeframe": "last30days", "dataStream": { "id": "{{dataStreams.[sensorUsage]}}", @@ -428,7 +371,283 @@ }, "visualisation": { "type": "data-stream-table", - "config": { "data-stream-table": { "transpose": false } } + "config": { + "data-stream-table": { + "transpose": false + } + } + } + } + }, + { + "i": "05e64ee9-4701-4f45-8096-115643dee6f1", + "x": 0, + "y": 2, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Windows Hosts", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "timeframe": "none", + "dataStream": { + "id": "{{dataStreams.[hostCount]}}", + "name": "hostCount", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "platform": "Windows" + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "result", + "comparisonColumn": "none" + } + } + } + } + }, + { + "i": "094b40d1-c2dc-4324-b9bb-12404a56be1d", + "x": 1, + "y": 2, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Linux Hosts", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "timeframe": "none", + "dataStream": { + "id": "{{dataStreams.[hostCount]}}", + "name": "hostCount", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "platform": "Linux" + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "result", + "comparisonColumn": "none" + } + } + } + } + }, + { + "i": "2fea90b6-fe56-40cf-82c9-d19a915fd4a7", + "x": 2, + "y": 2, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Mac Hosts", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "timeframe": "none", + "dataStream": { + "id": "{{dataStreams.[hostCount]}}", + "name": "hostCount", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "platform": "Mac" + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "result", + "comparisonColumn": "none" + } + } + } + } + }, + { + "i": "a70a7c9e-13c4-4ab9-a08a-33f65df11770", + "x": 0, + "y": 4, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Critical Vulnerabilities", + "description": "Open vulnerabilities", + "activePluginConfigIds": [ + "{{configId}}" + ], + "timeframe": "none", + "dataStream": { + "id": "{{dataStreams.[vulnerabilityCount]}}", + "name": "vulnerabilityCount", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "severity": [ + "CRITICAL" + ], + "status": [ + "open" + ] + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "result", + "comparisonColumn": "none" + } + } + } + } + }, + { + "i": "316c45be-3af0-432e-8a04-0cbed91ee3f1", + "x": 1, + "y": 4, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "High Vulnerabilities", + "description": "Open vulnerabilities", + "activePluginConfigIds": [ + "{{configId}}" + ], + "timeframe": "none", + "dataStream": { + "id": "{{dataStreams.[vulnerabilityCount]}}", + "name": "vulnerabilityCount", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "severity": [ + "HIGH" + ], + "status": [ + "open" + ] + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "result", + "comparisonColumn": "none" + } + } + } + } + }, + { + "i": "1a1cda51-d119-471e-889d-a24a7d324492", + "x": 2, + "y": 4, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Medium Vulnerabilities", + "description": "Open vulnerabilities", + "activePluginConfigIds": [ + "{{configId}}" + ], + "timeframe": "none", + "dataStream": { + "id": "{{dataStreams.[vulnerabilityCount]}}", + "name": "vulnerabilityCount", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "severity": [ + "MEDIUM" + ], + "status": [ + "open" + ] + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "result", + "comparisonColumn": "none" + } + } + } + } + }, + { + "i": "7285d9e4-db98-479f-8e6a-5e3bee7f3975", + "x": 3, + "y": 4, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Low Vulnerabilities", + "description": "Open vulnerabilities", + "activePluginConfigIds": [ + "{{configId}}" + ], + "timeframe": "none", + "dataStream": { + "id": "{{dataStreams.[vulnerabilityCount]}}", + "name": "vulnerabilityCount", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "severity": [ + "LOW" + ], + "status": [ + "open" + ] + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "result", + "comparisonColumn": "none" + } + } } } } diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json index ba368d36..8b4797ae 100644 --- a/plugins/CrowdStrike/v1/metadata.json +++ b/plugins/CrowdStrike/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "crowdstrike", "displayName": "CrowdStrike", - "version": "1.0.12", + "version": "1.0.13", "author": { "name": "@JackTSquppy", "type": "community" }, "description": "Monitor CrowdStrike Falcon host coverage, detections & incidents, vulnerabilities, and policy compliance in SquaredUp.", "category": "Security", From 250e41103dec7e862f5f8eec7e6faf22bd1b3af0 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Wed, 14 Oct 2026 14:03:46 -0400 Subject: [PATCH 18/27] CrowdStrike: update README, require explicit cloud selection Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/docs/README.md | 11 ++++++++--- plugins/CrowdStrike/v1/ui.json | 1 - 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/plugins/CrowdStrike/v1/docs/README.md b/plugins/CrowdStrike/v1/docs/README.md index 072f48d1..5eff9a0f 100644 --- a/plugins/CrowdStrike/v1/docs/README.md +++ b/plugins/CrowdStrike/v1/docs/README.md @@ -8,7 +8,9 @@ You will need a CrowdStrike Falcon **API client** with read scopes for Hosts, Al 2. Go to **Support and resources → API clients and keys** and click **Add new API client**. 3. Give the client a name, and grant it **Read** scope for: **Hosts**, **Host Groups**, **Alerts**, **Spotlight Vulnerabilities**, **Sensor Update Policies**, **Prevention Policies**, and **Sensor Usage**. 4. Copy the generated **Client ID** and **Client Secret** — the secret is shown only once. -5. Note the **Cloud** your Falcon tenant runs in (shown on the same page, e.g. `api.us-2.crowdstrike.com`) and paste the three values into the fields below. +5. Note the **Cloud** your Falcon tenant runs in (US-1, US-2, EU-1 or US-GOV-1 / GovCloud) and select it in the form below, then enter the Client ID and Client Secret. + +> Each dashboard tile needs its own scope. A tile whose scope is missing shows "access denied, scope not permitted"; the rest of the dashboard still works. Hosts and Host Groups drive host counts and the Host Group perspective; Alerts drives alert tiles; Spotlight Vulnerabilities drives vulnerability tiles; the policy scopes drive the policy tiles. ## Configuration fields @@ -32,6 +34,9 @@ The out-of-the-box dashboards include an account-wide **Overview**, a **Host Gro ## Data streams +- **Host Count** — number of hosts, optionally by platform or containment status, from a single request (fast on large tenants). +- **Vulnerability Count** — number of Spotlight vulnerabilities by host/group, severity and status, from a single request. +- **Recently Seen Hosts** — the 100 most recently seen hosts. - **Devices** — host inventory (platform, OS, sensor version, network, group membership, policy applied state), account-wide or scoped to a Host or Host Group. - **Alerts** — detections and incidents from the unified Falcon Alerts API, account-wide or scoped to a Host or Host Group, with a Status filter. - **Vulnerabilities** — open Spotlight vulnerability findings, account-wide or scoped to a Host or Host Group, with a Status filter. @@ -50,12 +55,12 @@ The out-of-the-box dashboards include an account-wide **Overview**, a **Host Gro ## Known limitations -> ⚠️ **This build has not been tested against a live CrowdStrike tenant.** It was authored from CrowdStrike's published API documentation and an endpoint reference list, but no CrowdStrike API credentials were available during development, so no data stream has been exercised against real data and no import has been run. Every field name, filter expression, and response shape below should be verified — and adjusted if needed — against a real Falcon tenant before this plugin is relied on. +> ⚠️ **Tested at scale on one GovCloud (US-GOV-1) tenant of about 92,700 hosts.** Authentication, Host Group and Host import, host counts and the Host Group perspective's host tiles have been verified. Alerts, Vulnerabilities, policy and Sensor Usage streams could not be verified against live data because the test API client lacked those scopes, so their field names and filters follow CrowdStrike's documentation only. +- **Large tenants** — streams that list hosts, alerts or vulnerabilities page through every result, and one query can make at most 220 requests. Use the count streams for whole-tenant totals and scope list streams to a Host Group. - **Incidents API not used** — the legacy `/incidents/*` API is deprecated (removed as of March 2026); this plugin uses the unified `/alerts/*` API for both detections and incidents. - **Time-to-containment is not surfaced** — CrowdStrike's API exposes containment actions but not a completed-containment timestamp, so response-latency here is measured as alert `created` → `updated` (when closed), not true time-to-containment. - **Host Group scoping for Alerts and Vulnerabilities is unverified** — filtering these by Host Group assumes the alert/vulnerability payload embeds the host's group membership (`device.groups` / `host_info.groups`); if CrowdStrike's response doesn't expose that field, Host-Group-scoped Alerts/Vulnerabilities tiles will need an alternate filter approach. - **Sensor Usage column names are unverified** — the billing-dashboards-usage endpoint's exact response shape wasn't confirmed against live data; the stream surfaces whatever columns the API returns via a catch-all, so the default table tile may need column renaming once real data is seen. - **Dashboard filters use assumed raw values** — the Overview KPI/donut tiles filter on assumed raw API values (alert `status` of `new`/`in_progress`/`closed`/`reopened`, device `status` of `contained`, a CVSS-score threshold as a proxy for "Critical/High" severity); these should be checked against real payloads and adjusted if CrowdStrike's actual values differ. -- **Account-wide tiles on unscoped consolidated streams** (Devices/Alerts/Vulnerabilities on the Overview dashboard) omit the scope binding entirely, per the documented pattern for an empty selection — if this throws a `nodeIds` error on a live tenant, the fix is to bind an explicit empty selection instead. - **Read-only** — the plugin never creates, modifies, or deletes anything in CrowdStrike Falcon. - **Requires a paid Falcon subscription with API access** — a trial account may not expose all the scopes this plugin requests (Hosts, Host Groups, Alerts, Spotlight Vulnerabilities, Sensor Update Policies, Prevention Policies, Sensor Usage). diff --git a/plugins/CrowdStrike/v1/ui.json b/plugins/CrowdStrike/v1/ui.json index 6e603538..51d597cb 100644 --- a/plugins/CrowdStrike/v1/ui.json +++ b/plugins/CrowdStrike/v1/ui.json @@ -7,7 +7,6 @@ "validation": { "required": true }, "isMulti": false, "allowCustomValues": false, - "defaultValue": "https://api.crowdstrike.com", "data": { "source": "fixed", "values": [ From cdb493cb91e77043124f76f9ed9c9f94203bdc4c Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Wed, 14 Oct 2026 14:20:28 -0400 Subject: [PATCH 19/27] CrowdStrike: address review feedback (scope classification, README, placeholder) Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/dataStreams/alerts.json | 2 +- plugins/CrowdStrike/v1/dataStreams/currentUser.json | 2 +- plugins/CrowdStrike/v1/dataStreams/devices.json | 2 +- plugins/CrowdStrike/v1/dataStreams/sensorUsage.json | 2 +- plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json | 2 +- plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json | 2 +- plugins/CrowdStrike/v1/docs/README.md | 2 +- plugins/CrowdStrike/v1/metadata.json | 2 +- plugins/CrowdStrike/v1/ui.json | 1 + 9 files changed, 9 insertions(+), 8 deletions(-) diff --git a/plugins/CrowdStrike/v1/dataStreams/alerts.json b/plugins/CrowdStrike/v1/dataStreams/alerts.json index 84a52970..46d77700 100644 --- a/plugins/CrowdStrike/v1/dataStreams/alerts.json +++ b/plugins/CrowdStrike/v1/dataStreams/alerts.json @@ -13,7 +13,7 @@ "postBody": { "limit": 1000, "sort": "created_timestamp|desc", - "filter": "{{ (typeof timeframe !== 'undefined' && timeframe && timeframe.start && timeframe.end ? [ \"created_timestamp:>'\" + timeframe.start.replace(/\\.\\d+Z$/, 'Z') + \"'+created_timestamp:<'\" + timeframe.end.replace(/\\.\\d+Z$/, 'Z') + \"'\" ] : []).concat((typeof scope === 'undefined' || !scope ? [] : [ [\"device.device_id\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') < 0)], [\"device.groups\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\"))).concat((typeof status === 'undefined' || !status || !status.length ? [] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") || \"created_timestamp:>'2000-01-01T00:00:00Z'\" }}" + "filter": "{{ (typeof timeframe !== 'undefined' && timeframe && timeframe.start && timeframe.end ? [ \"created_timestamp:>'\" + timeframe.start.replace(/\\.\\d+Z$/, 'Z') + \"'+created_timestamp:<'\" + timeframe.end.replace(/\\.\\d+Z$/, 'Z') + \"'\" ] : []).concat((typeof scope === 'undefined' || !scope ? [] : [ [\"device.device_id\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') < 0)], [\"device.groups\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\"))).concat((typeof status === 'undefined' || !status || !status.length ? [] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") || \"created_timestamp:>'2000-01-01T00:00:00Z'\" }}" }, "paging": { "mode": "token", diff --git a/plugins/CrowdStrike/v1/dataStreams/currentUser.json b/plugins/CrowdStrike/v1/dataStreams/currentUser.json index 36714d86..10cc6411 100644 --- a/plugins/CrowdStrike/v1/dataStreams/currentUser.json +++ b/plugins/CrowdStrike/v1/dataStreams/currentUser.json @@ -1,6 +1,6 @@ { "name": "currentUser", - "displayName": "Current User", + "displayName": "Host IDs", "description": "A minimal Falcon Hosts query, used only to verify the configured credentials can reach the API", "tags": ["Security"], "baseDataSourceName": "httpRequestUnscoped", diff --git a/plugins/CrowdStrike/v1/dataStreams/devices.json b/plugins/CrowdStrike/v1/dataStreams/devices.json index 1bb71705..0aa1b0c3 100644 --- a/plugins/CrowdStrike/v1/dataStreams/devices.json +++ b/plugins/CrowdStrike/v1/dataStreams/devices.json @@ -21,7 +21,7 @@ }, { "key": "filter", - "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"device_id\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') < 0)], [\"groups\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).join(\"+\") || null }}" + "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"device_id\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') < 0)], [\"groups\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).join(\"+\") || null }}" } ], "paging": { diff --git a/plugins/CrowdStrike/v1/dataStreams/sensorUsage.json b/plugins/CrowdStrike/v1/dataStreams/sensorUsage.json index 0c92de4f..a1845b94 100644 --- a/plugins/CrowdStrike/v1/dataStreams/sensorUsage.json +++ b/plugins/CrowdStrike/v1/dataStreams/sensorUsage.json @@ -12,5 +12,5 @@ }, "matches": "none", "metadata": [{ "pattern": ".*" }], - "timeframes": ["last30days", "thisQuarter", "lastQuarter"] + "timeframes": false } diff --git a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json index 562a920c..5597930c 100644 --- a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json +++ b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json @@ -17,7 +17,7 @@ }, { "key": "filter", - "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"aid\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') < 0)], [\"host_info.groups\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).concat((typeof status === 'undefined' || !status || !status.length ? [ \"status:['open','reopen']\" ] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") }}" + "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"aid\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') < 0)], [\"host_info.groups\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).concat((typeof status === 'undefined' || !status || !status.length ? [ \"status:['open','reopen']\" ] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") }}" } ], "paging": { diff --git a/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json b/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json index 654e8e0a..889bd449 100644 --- a/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json +++ b/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json @@ -17,7 +17,7 @@ }, { "key": "filter", - "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"aid\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') < 0)], [\"host_info.groups\", scope.filter(o => JSON.stringify(o).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).concat((typeof severity === 'undefined' || !severity ? [] : [].concat(severity).map(x => String(x && x.value !== undefined ? x.value : x))).length ? [ \"cve.severity:[\" + (typeof severity === 'undefined' || !severity ? [] : [].concat(severity).map(x => String(x && x.value !== undefined ? x.value : x))).map(v => \"'\" + v + \"'\").join(\",\") + \"]\" ] : []).concat((typeof status === 'undefined' || !status ? [] : [].concat(status).map(x => String(x && x.value !== undefined ? x.value : x))).length ? [ \"status:[\" + (typeof status === 'undefined' || !status ? [] : [].concat(status).map(x => String(x && x.value !== undefined ? x.value : x))).map(v => \"'\" + v + \"'\").join(\",\") + \"]\" ] : [ \"status:['open','reopen']\" ]).join(\"+\") }}" + "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"aid\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') < 0)], [\"host_info.groups\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).concat((typeof severity === 'undefined' || !severity ? [] : [].concat(severity).map(x => String(x && x.value !== undefined ? x.value : x))).length ? [ \"cve.severity:[\" + (typeof severity === 'undefined' || !severity ? [] : [].concat(severity).map(x => String(x && x.value !== undefined ? x.value : x))).map(v => \"'\" + v + \"'\").join(\",\") + \"]\" ] : []).concat((typeof status === 'undefined' || !status ? [] : [].concat(status).map(x => String(x && x.value !== undefined ? x.value : x))).length ? [ \"status:[\" + (typeof status === 'undefined' || !status ? [] : [].concat(status).map(x => String(x && x.value !== undefined ? x.value : x))).map(v => \"'\" + v + \"'\").join(\",\") + \"]\" ] : [ \"status:['open','reopen']\" ]).join(\"+\") }}" } ], "paging": { diff --git a/plugins/CrowdStrike/v1/docs/README.md b/plugins/CrowdStrike/v1/docs/README.md index 5eff9a0f..57af5a50 100644 --- a/plugins/CrowdStrike/v1/docs/README.md +++ b/plugins/CrowdStrike/v1/docs/README.md @@ -61,6 +61,6 @@ The out-of-the-box dashboards include an account-wide **Overview**, a **Host Gro - **Time-to-containment is not surfaced** — CrowdStrike's API exposes containment actions but not a completed-containment timestamp, so response-latency here is measured as alert `created` → `updated` (when closed), not true time-to-containment. - **Host Group scoping for Alerts and Vulnerabilities is unverified** — filtering these by Host Group assumes the alert/vulnerability payload embeds the host's group membership (`device.groups` / `host_info.groups`); if CrowdStrike's response doesn't expose that field, Host-Group-scoped Alerts/Vulnerabilities tiles will need an alternate filter approach. - **Sensor Usage column names are unverified** — the billing-dashboards-usage endpoint's exact response shape wasn't confirmed against live data; the stream surfaces whatever columns the API returns via a catch-all, so the default table tile may need column renaming once real data is seen. -- **Dashboard filters use assumed raw values** — the Overview KPI/donut tiles filter on assumed raw API values (alert `status` of `new`/`in_progress`/`closed`/`reopened`, device `status` of `contained`, a CVSS-score threshold as a proxy for "Critical/High" severity); these should be checked against real payloads and adjusted if CrowdStrike's actual values differ. +- **Dashboard filters use assumed raw values** — the Overview tiles filter on assumed raw API values (alert `status` of `new`/`in_progress`/`closed`/`reopened`, host `status` of `contained`, and Spotlight severity values `CRITICAL`/`HIGH`/`MEDIUM`/`LOW` with status `open`); these should be checked against real payloads and adjusted if CrowdStrike's actual values differ. - **Read-only** — the plugin never creates, modifies, or deletes anything in CrowdStrike Falcon. - **Requires a paid Falcon subscription with API access** — a trial account may not expose all the scopes this plugin requests (Hosts, Host Groups, Alerts, Spotlight Vulnerabilities, Sensor Update Policies, Prevention Policies, Sensor Usage). diff --git a/plugins/CrowdStrike/v1/metadata.json b/plugins/CrowdStrike/v1/metadata.json index 8b4797ae..ee251d44 100644 --- a/plugins/CrowdStrike/v1/metadata.json +++ b/plugins/CrowdStrike/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "crowdstrike", "displayName": "CrowdStrike", - "version": "1.0.13", + "version": "1.0.14", "author": { "name": "@JackTSquppy", "type": "community" }, "description": "Monitor CrowdStrike Falcon host coverage, detections & incidents, vulnerabilities, and policy compliance in SquaredUp.", "category": "Security", diff --git a/plugins/CrowdStrike/v1/ui.json b/plugins/CrowdStrike/v1/ui.json index 51d597cb..67f63c8a 100644 --- a/plugins/CrowdStrike/v1/ui.json +++ b/plugins/CrowdStrike/v1/ui.json @@ -21,6 +21,7 @@ "type": "text", "name": "clientId", "label": "Client ID", + "placeholder": "Enter the CrowdStrike API client ID", "help": "The Client ID of your CrowdStrike API client. [More info](https://falcon.crowdstrike.com/support/api-clients-and-keys)", "validation": { "required": true } }, From 7509c52fca40fb5b95892d0b3b1f9c8ea4d9c2fb Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Wed, 14 Oct 2026 15:53:30 -0400 Subject: [PATCH 20/27] CrowdStrike: OR together Host and Host Group scope clauses Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/dataStreams/alerts.json | 2 +- plugins/CrowdStrike/v1/dataStreams/devices.json | 2 +- plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json | 2 +- plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/CrowdStrike/v1/dataStreams/alerts.json b/plugins/CrowdStrike/v1/dataStreams/alerts.json index 46d77700..96ad27b2 100644 --- a/plugins/CrowdStrike/v1/dataStreams/alerts.json +++ b/plugins/CrowdStrike/v1/dataStreams/alerts.json @@ -13,7 +13,7 @@ "postBody": { "limit": 1000, "sort": "created_timestamp|desc", - "filter": "{{ (typeof timeframe !== 'undefined' && timeframe && timeframe.start && timeframe.end ? [ \"created_timestamp:>'\" + timeframe.start.replace(/\\.\\d+Z$/, 'Z') + \"'+created_timestamp:<'\" + timeframe.end.replace(/\\.\\d+Z$/, 'Z') + \"'\" ] : []).concat((typeof scope === 'undefined' || !scope ? [] : [ [\"device.device_id\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') < 0)], [\"device.groups\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\"))).concat((typeof status === 'undefined' || !status || !status.length ? [] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") || \"created_timestamp:>'2000-01-01T00:00:00Z'\" }}" + "filter": "{{ (typeof timeframe !== 'undefined' && timeframe && timeframe.start && timeframe.end ? [ \"created_timestamp:>'\" + timeframe.start.replace(/\\.\\d+Z$/, 'Z') + \"'+created_timestamp:<'\" + timeframe.end.replace(/\\.\\d+Z$/, 'Z') + \"'\" ] : []).concat(((S => S.length > 1 ? [ \"(\" + S.join(\",\") + \")\" ] : S)((typeof scope === 'undefined' || !scope ? [] : [ [\"device.device_id\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') < 0)], [\"device.groups\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\"))))).concat((typeof status === 'undefined' || !status || !status.length ? [] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") || \"created_timestamp:>'2000-01-01T00:00:00Z'\" }}" }, "paging": { "mode": "token", diff --git a/plugins/CrowdStrike/v1/dataStreams/devices.json b/plugins/CrowdStrike/v1/dataStreams/devices.json index 0aa1b0c3..cff16dcd 100644 --- a/plugins/CrowdStrike/v1/dataStreams/devices.json +++ b/plugins/CrowdStrike/v1/dataStreams/devices.json @@ -21,7 +21,7 @@ }, { "key": "filter", - "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"device_id\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') < 0)], [\"groups\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).join(\"+\") || null }}" + "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"device_id\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') < 0)], [\"groups\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).join(\",\") || null }}" } ], "paging": { diff --git a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json index 5597930c..1ca58214 100644 --- a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json +++ b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json @@ -17,7 +17,7 @@ }, { "key": "filter", - "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"aid\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') < 0)], [\"host_info.groups\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).concat((typeof status === 'undefined' || !status || !status.length ? [ \"status:['open','reopen']\" ] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") }}" + "value": "{{ ((S => S.length > 1 ? [ \"(\" + S.join(\",\") + \")\" ] : S)((typeof scope === 'undefined' || !scope ? [] : [ [\"aid\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') < 0)], [\"host_info.groups\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")))).concat((typeof status === 'undefined' || !status || !status.length ? [ \"status:['open','reopen']\" ] : [ \"status:[\" + status.map(s => \"'\" + (s.value || s) + \"'\").join(\",\") + \"]\" ])).join(\"+\") }}" } ], "paging": { diff --git a/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json b/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json index 889bd449..01beed35 100644 --- a/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json +++ b/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json @@ -17,7 +17,7 @@ }, { "key": "filter", - "value": "{{ (typeof scope === 'undefined' || !scope ? [] : [ [\"aid\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') < 0)], [\"host_info.groups\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")).concat((typeof severity === 'undefined' || !severity ? [] : [].concat(severity).map(x => String(x && x.value !== undefined ? x.value : x))).length ? [ \"cve.severity:[\" + (typeof severity === 'undefined' || !severity ? [] : [].concat(severity).map(x => String(x && x.value !== undefined ? x.value : x))).map(v => \"'\" + v + \"'\").join(\",\") + \"]\" ] : []).concat((typeof status === 'undefined' || !status ? [] : [].concat(status).map(x => String(x && x.value !== undefined ? x.value : x))).length ? [ \"status:[\" + (typeof status === 'undefined' || !status ? [] : [].concat(status).map(x => String(x && x.value !== undefined ? x.value : x))).map(v => \"'\" + v + \"'\").join(\",\") + \"]\" ] : [ \"status:['open','reopen']\" ]).join(\"+\") }}" + "value": "{{ ((S => S.length > 1 ? [ \"(\" + S.join(\",\") + \")\" ] : S)((typeof scope === 'undefined' || !scope ? [] : [ [\"aid\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') < 0)], [\"host_info.groups\", scope.filter(o => (typeof o.type === 'string' ? o.type : JSON.stringify(o)).indexOf('Host Group') >= 0)] ].filter(p => p[1].length).map(p => p[0] + \":[\" + p[1].map(o => \"'\" + String([].concat(o.rawId !== undefined ? o.rawId : (o.sourceId || o.id))[0]).split('~').pop() + \"'\").join(\",\") + \"]\")))).concat((typeof severity === 'undefined' || !severity ? [] : [].concat(severity).map(x => String(x && x.value !== undefined ? x.value : x))).length ? [ \"cve.severity:[\" + (typeof severity === 'undefined' || !severity ? [] : [].concat(severity).map(x => String(x && x.value !== undefined ? x.value : x))).map(v => \"'\" + v + \"'\").join(\",\") + \"]\" ] : []).concat((typeof status === 'undefined' || !status ? [] : [].concat(status).map(x => String(x && x.value !== undefined ? x.value : x))).length ? [ \"status:[\" + (typeof status === 'undefined' || !status ? [] : [].concat(status).map(x => String(x && x.value !== undefined ? x.value : x))).map(v => \"'\" + v + \"'\").join(\",\") + \"]\" ] : [ \"status:['open','reopen']\" ]).join(\"+\") }}" } ], "paging": { From 79b6c69f10095080138dcc23c1d18563b912dfdf Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Wed, 14 Oct 2026 15:54:37 -0400 Subject: [PATCH 21/27] CrowdStrike: derive response latency from seconds_to_triaged Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/dataStreams/alerts.json | 2 +- plugins/CrowdStrike/v1/docs/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/CrowdStrike/v1/dataStreams/alerts.json b/plugins/CrowdStrike/v1/dataStreams/alerts.json index 96ad27b2..fa7b8e8f 100644 --- a/plugins/CrowdStrike/v1/dataStreams/alerts.json +++ b/plugins/CrowdStrike/v1/dataStreams/alerts.json @@ -211,7 +211,7 @@ "name": "responseLatencySeconds", "displayName": "Response Latency", "computed": true, - "valueExpression": "{{ ($['status'] === 'closed' && $['updated_timestamp'] && $['created_timestamp']) ? Math.max(0, (new Date($['updated_timestamp']) - new Date($['created_timestamp'])) / 1000) : null }}", + "valueExpression": "{{ ($['seconds_to_triaged'] !== undefined && $['seconds_to_triaged'] !== null && $['seconds_to_triaged'] !== '' && !isNaN(Number($['seconds_to_triaged']))) ? Math.max(0, Number($['seconds_to_triaged'])) : null }}", "shape": [ "seconds", { diff --git a/plugins/CrowdStrike/v1/docs/README.md b/plugins/CrowdStrike/v1/docs/README.md index 57af5a50..22653d6f 100644 --- a/plugins/CrowdStrike/v1/docs/README.md +++ b/plugins/CrowdStrike/v1/docs/README.md @@ -58,7 +58,7 @@ The out-of-the-box dashboards include an account-wide **Overview**, a **Host Gro > ⚠️ **Tested at scale on one GovCloud (US-GOV-1) tenant of about 92,700 hosts.** Authentication, Host Group and Host import, host counts and the Host Group perspective's host tiles have been verified. Alerts, Vulnerabilities, policy and Sensor Usage streams could not be verified against live data because the test API client lacked those scopes, so their field names and filters follow CrowdStrike's documentation only. - **Large tenants** — streams that list hosts, alerts or vulnerabilities page through every result, and one query can make at most 220 requests. Use the count streams for whole-tenant totals and scope list streams to a Host Group. - **Incidents API not used** — the legacy `/incidents/*` API is deprecated (removed as of March 2026); this plugin uses the unified `/alerts/*` API for both detections and incidents. -- **Time-to-containment is not surfaced** — CrowdStrike's API exposes containment actions but not a completed-containment timestamp, so response-latency here is measured as alert `created` → `updated` (when closed), not true time-to-containment. +- **Time-to-containment is not surfaced** — CrowdStrike's API exposes containment actions but not a completed-containment timestamp, so Response Latency here is the alert's `seconds_to_triaged` (time from creation to triage), not true time-to-containment. It is empty for alerts that haven't been triaged. - **Host Group scoping for Alerts and Vulnerabilities is unverified** — filtering these by Host Group assumes the alert/vulnerability payload embeds the host's group membership (`device.groups` / `host_info.groups`); if CrowdStrike's response doesn't expose that field, Host-Group-scoped Alerts/Vulnerabilities tiles will need an alternate filter approach. - **Sensor Usage column names are unverified** — the billing-dashboards-usage endpoint's exact response shape wasn't confirmed against live data; the stream surfaces whatever columns the API returns via a catch-all, so the default table tile may need column renaming once real data is seen. - **Dashboard filters use assumed raw values** — the Overview tiles filter on assumed raw API values (alert `status` of `new`/`in_progress`/`closed`/`reopened`, host `status` of `contained`, and Spotlight severity values `CRITICAL`/`HIGH`/`MEDIUM`/`LOW` with status `open`); these should be checked against real payloads and adjusted if CrowdStrike's actual values differ. From cf83791bb0d1d4da8fa1e856e8513f09a0085ca5 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Wed, 14 Oct 2026 15:55:32 -0400 Subject: [PATCH 22/27] CrowdStrike: stop Days Open counting at closure Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json index 1ca58214..87eccbed 100644 --- a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json +++ b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json @@ -169,7 +169,7 @@ "name": "daysOpen", "displayName": "Days Open", "computed": true, - "valueExpression": "{{ $['created_timestamp'] ? Math.floor((Date.now() - new Date($['created_timestamp'])) / 86400000) : null }}", + "valueExpression": "{{ $['created_timestamp'] ? Math.max(0, Math.floor((($['status'] === 'closed' && $['closed_timestamp'] ? new Date($['closed_timestamp']) : Date.now()) - new Date($['created_timestamp'])) / 86400000)) : null }}", "shape": "number" }, { From ec12559cd834f1f18451953f888f01805055f372 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Wed, 14 Oct 2026 15:56:14 -0400 Subject: [PATCH 23/27] CrowdStrike: single-sentence descriptions for count and recent hosts streams Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/dataStreams/hostCount.json | 2 +- plugins/CrowdStrike/v1/dataStreams/recentHosts.json | 2 +- plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/CrowdStrike/v1/dataStreams/hostCount.json b/plugins/CrowdStrike/v1/dataStreams/hostCount.json index ae0f2b08..4a7d778e 100644 --- a/plugins/CrowdStrike/v1/dataStreams/hostCount.json +++ b/plugins/CrowdStrike/v1/dataStreams/hostCount.json @@ -1,7 +1,7 @@ { "name": "hostCount", "displayName": "Host Count", - "description": "Number of hosts, optionally filtered by platform or containment status. Uses a single request, so it is fast on large tenants.", + "description": "Number of hosts, optionally filtered by platform or containment status, from a single request so it stays fast on large tenants", "tags": [ "Security" ], diff --git a/plugins/CrowdStrike/v1/dataStreams/recentHosts.json b/plugins/CrowdStrike/v1/dataStreams/recentHosts.json index 44ac2c67..59c69a70 100644 --- a/plugins/CrowdStrike/v1/dataStreams/recentHosts.json +++ b/plugins/CrowdStrike/v1/dataStreams/recentHosts.json @@ -1,7 +1,7 @@ { "name": "recentHosts", "displayName": "Recently Seen Hosts", - "description": "The 100 most recently seen hosts. A single request, so it is fast on large tenants.", + "description": "The 100 most recently seen hosts, from a single request so it stays fast on large tenants", "tags": [ "Security" ], diff --git a/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json b/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json index 01beed35..bb45021d 100644 --- a/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json +++ b/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json @@ -1,7 +1,7 @@ { "name": "vulnerabilityCount", "displayName": "Vulnerability Count", - "description": "Number of Spotlight vulnerabilities, optionally filtered by host, host group, severity and status. Uses a single request, so it is fast on large tenants.", + "description": "Number of Spotlight vulnerabilities, optionally filtered by host, host group, severity and status, from a single request so it stays fast on large tenants", "tags": [ "Security", "Vulnerabilities" From 140c57358565890ae677d05655292ba60a02cc5b Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Wed, 14 Oct 2026 15:56:59 -0400 Subject: [PATCH 24/27] CrowdStrike: clarify what setup validation checks Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CrowdStrike/v1/docs/README.md b/plugins/CrowdStrike/v1/docs/README.md index 22653d6f..2bae2186 100644 --- a/plugins/CrowdStrike/v1/docs/README.md +++ b/plugins/CrowdStrike/v1/docs/README.md @@ -20,7 +20,7 @@ You will need a CrowdStrike Falcon **API client** with read scopes for Hosts, Al | **Client ID** | Identifies the API client used to authenticate requests. | **Support and resources → API clients and keys**. | Yes | | **Client Secret** | Authenticates the API client via OAuth2 client-credentials. | Shown once when the API client is created. | Yes | -On save, the plugin validates the credentials with a minimal Hosts query; an invalid Client ID/Secret, wrong Cloud region, or missing scope fails setup with an authentication error. +On save, the plugin checks the credentials with a minimal Hosts query (`GET /devices/queries/devices/v1`); an invalid Client ID/Secret, wrong Cloud region, or missing Hosts scope fails setup with an authentication error. This check does not test the other scopes, so a missing Alerts, Spotlight Vulnerabilities, policy or Sensor Usage scope only shows up on the tiles that use it. ## What this plugin monitors From bd3fc1472327f6aef5f44b58f14a72c180f209b2 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Thu, 15 Oct 2026 12:38:10 -0400 Subject: [PATCH 25/27] CrowdStrike: share one errorHandling script between streams Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/dataStreams/alerts.json | 2 +- plugins/CrowdStrike/v1/dataStreams/devices.json | 2 +- plugins/CrowdStrike/v1/dataStreams/hostCount.json | 2 +- .../v1/dataStreams/scripts/errorHandling/devices.js | 3 --- .../scripts/errorHandling/{alerts.js => falconApiError.js} | 0 .../v1/dataStreams/scripts/errorHandling/hostCount.js | 3 --- .../v1/dataStreams/scripts/errorHandling/vulnerabilities.js | 3 --- .../v1/dataStreams/scripts/errorHandling/vulnerabilityCount.js | 3 --- plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json | 2 +- plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json | 2 +- 10 files changed, 5 insertions(+), 17 deletions(-) delete mode 100644 plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/devices.js rename plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/{alerts.js => falconApiError.js} (100%) delete mode 100644 plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/hostCount.js delete mode 100644 plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/vulnerabilities.js delete mode 100644 plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/vulnerabilityCount.js diff --git a/plugins/CrowdStrike/v1/dataStreams/alerts.json b/plugins/CrowdStrike/v1/dataStreams/alerts.json index fa7b8e8f..d7d4e527 100644 --- a/plugins/CrowdStrike/v1/dataStreams/alerts.json +++ b/plugins/CrowdStrike/v1/dataStreams/alerts.json @@ -30,7 +30,7 @@ "expandInnerObjects": true, "errorHandling": { "type": "script", - "script": "errorHandling/alerts.js" + "script": "errorHandling/falconApiError.js" } }, "matches": "none", diff --git a/plugins/CrowdStrike/v1/dataStreams/devices.json b/plugins/CrowdStrike/v1/dataStreams/devices.json index cff16dcd..ed88a1fb 100644 --- a/plugins/CrowdStrike/v1/dataStreams/devices.json +++ b/plugins/CrowdStrike/v1/dataStreams/devices.json @@ -44,7 +44,7 @@ "expandInnerObjects": true, "errorHandling": { "type": "script", - "script": "errorHandling/devices.js" + "script": "errorHandling/falconApiError.js" } }, "matches": "none", diff --git a/plugins/CrowdStrike/v1/dataStreams/hostCount.json b/plugins/CrowdStrike/v1/dataStreams/hostCount.json index 4a7d778e..ca740a27 100644 --- a/plugins/CrowdStrike/v1/dataStreams/hostCount.json +++ b/plugins/CrowdStrike/v1/dataStreams/hostCount.json @@ -25,7 +25,7 @@ "pathToData": "meta.pagination.total", "errorHandling": { "type": "script", - "script": "errorHandling/hostCount.js" + "script": "errorHandling/falconApiError.js" } }, "matches": "none", diff --git a/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/devices.js b/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/devices.js deleted file mode 100644 index bb83e2c1..00000000 --- a/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/devices.js +++ /dev/null @@ -1,3 +0,0 @@ -const e = data && data.errors && data.errors[0]; - -result = (e && e.message) || (data && data.message) || ('Request failed with HTTP ' + response.status); diff --git a/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/alerts.js b/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/falconApiError.js similarity index 100% rename from plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/alerts.js rename to plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/falconApiError.js diff --git a/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/hostCount.js b/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/hostCount.js deleted file mode 100644 index bb83e2c1..00000000 --- a/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/hostCount.js +++ /dev/null @@ -1,3 +0,0 @@ -const e = data && data.errors && data.errors[0]; - -result = (e && e.message) || (data && data.message) || ('Request failed with HTTP ' + response.status); diff --git a/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/vulnerabilities.js b/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/vulnerabilities.js deleted file mode 100644 index bb83e2c1..00000000 --- a/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/vulnerabilities.js +++ /dev/null @@ -1,3 +0,0 @@ -const e = data && data.errors && data.errors[0]; - -result = (e && e.message) || (data && data.message) || ('Request failed with HTTP ' + response.status); diff --git a/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/vulnerabilityCount.js b/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/vulnerabilityCount.js deleted file mode 100644 index bb83e2c1..00000000 --- a/plugins/CrowdStrike/v1/dataStreams/scripts/errorHandling/vulnerabilityCount.js +++ /dev/null @@ -1,3 +0,0 @@ -const e = data && data.errors && data.errors[0]; - -result = (e && e.message) || (data && data.message) || ('Request failed with HTTP ' + response.status); diff --git a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json index 87eccbed..6c45fde0 100644 --- a/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json +++ b/plugins/CrowdStrike/v1/dataStreams/vulnerabilities.json @@ -40,7 +40,7 @@ "expandInnerObjects": true, "errorHandling": { "type": "script", - "script": "errorHandling/vulnerabilities.js" + "script": "errorHandling/falconApiError.js" } }, "matches": "none", diff --git a/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json b/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json index bb45021d..e05320bd 100644 --- a/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json +++ b/plugins/CrowdStrike/v1/dataStreams/vulnerabilityCount.json @@ -26,7 +26,7 @@ "pathToData": "meta.pagination.total", "errorHandling": { "type": "script", - "script": "errorHandling/vulnerabilityCount.js" + "script": "errorHandling/falconApiError.js" } }, "matches": "none", From 6a9201931fc94ee421fa71f8362822a1e1fda38a Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Thu, 15 Oct 2026 12:39:32 -0400 Subject: [PATCH 26/27] CrowdStrike: drop redundant scope callout from README Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/docs/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/CrowdStrike/v1/docs/README.md b/plugins/CrowdStrike/v1/docs/README.md index 2bae2186..0e29d7db 100644 --- a/plugins/CrowdStrike/v1/docs/README.md +++ b/plugins/CrowdStrike/v1/docs/README.md @@ -10,8 +10,6 @@ You will need a CrowdStrike Falcon **API client** with read scopes for Hosts, Al 4. Copy the generated **Client ID** and **Client Secret** — the secret is shown only once. 5. Note the **Cloud** your Falcon tenant runs in (US-1, US-2, EU-1 or US-GOV-1 / GovCloud) and select it in the form below, then enter the Client ID and Client Secret. -> Each dashboard tile needs its own scope. A tile whose scope is missing shows "access denied, scope not permitted"; the rest of the dashboard still works. Hosts and Host Groups drive host counts and the Host Group perspective; Alerts drives alert tiles; Spotlight Vulnerabilities drives vulnerability tiles; the policy scopes drive the policy tiles. - ## Configuration fields | Field | What it is | Where to find it | Required | From de18eba332a5af07671c6193a219c50b1d24a360 Mon Sep 17 00:00:00 2001 From: JackTSquppy Date: Thu, 15 Oct 2026 12:39:49 -0400 Subject: [PATCH 27/27] CrowdStrike: drop tested-at-scale note from README Co-Authored-By: Claude Sonnet 5.5 --- plugins/CrowdStrike/v1/docs/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/CrowdStrike/v1/docs/README.md b/plugins/CrowdStrike/v1/docs/README.md index 0e29d7db..b4a7adfd 100644 --- a/plugins/CrowdStrike/v1/docs/README.md +++ b/plugins/CrowdStrike/v1/docs/README.md @@ -53,7 +53,6 @@ The out-of-the-box dashboards include an account-wide **Overview**, a **Host Gro ## Known limitations -> ⚠️ **Tested at scale on one GovCloud (US-GOV-1) tenant of about 92,700 hosts.** Authentication, Host Group and Host import, host counts and the Host Group perspective's host tiles have been verified. Alerts, Vulnerabilities, policy and Sensor Usage streams could not be verified against live data because the test API client lacked those scopes, so their field names and filters follow CrowdStrike's documentation only. - **Large tenants** — streams that list hosts, alerts or vulnerabilities page through every result, and one query can make at most 220 requests. Use the count streams for whole-tenant totals and scope list streams to a Host Group. - **Incidents API not used** — the legacy `/incidents/*` API is deprecated (removed as of March 2026); this plugin uses the unified `/alerts/*` API for both detections and incidents. - **Time-to-containment is not surfaced** — CrowdStrike's API exposes containment actions but not a completed-containment timestamp, so Response Latency here is the alert's `seconds_to_triaged` (time from creation to triage), not true time-to-containment. It is empty for alerts that haven't been triaged.