diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bd01f6bc5a7..911764481af 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -579,6 +579,7 @@ /packages/withsecure_elements @elastic/security-service-integrations /packages/wiz @elastic/security-service-integrations /packages/wmi @elastic/obs-infraobs-integrations +/packages/xm_cyber @elastic/security-service-integrations /packages/zeek @elastic/integration-experience /packages/zerofox @elastic/security-service-integrations /packages/zeronetworks @elastic/security-service-integrations diff --git a/packages/xm_cyber/_dev/build/build.yml b/packages/xm_cyber/_dev/build/build.yml new file mode 100644 index 00000000000..0435c2b2300 --- /dev/null +++ b/packages/xm_cyber/_dev/build/build.yml @@ -0,0 +1,3 @@ +dependencies: + ecs: + reference: 'git@v9.3.0' diff --git a/packages/xm_cyber/_dev/build/docs/README.md b/packages/xm_cyber/_dev/build/docs/README.md new file mode 100644 index 00000000000..a72fb32b6cb --- /dev/null +++ b/packages/xm_cyber/_dev/build/docs/README.md @@ -0,0 +1,109 @@ +# XM Cyber Integration + +## Overview + +[XM Cyber](https://www.xmcyber.com) is a **Continuous Threat Exposure Management (CTEM)** and attack path management platform. It continuously simulates attacker movement across hybrid environments including on-premises, cloud, and identity infrastructure — combining vulnerabilities, misconfigurations, and overly permissive access into prioritized attack paths that lead to **critical assets**. + +This integration collects data from the XM Cyber REST API using scheduled polling. It provides visibility into your organization's security posture across your environment. + +### Compatibility + +The XM Cyber integration is compatible with the API version **1.0.0**. + +### How it works + +The integration uses the Elastic Agent CEL (Common Expression Language) input to poll the XM Cyber REST API on a configurable schedule. Each poll: + +1. Authenticates with a two-step flow: exchanges the API key for a short-lived Bearer access token via `POST /api/auth` +2. Fetches data from the configured endpoint. +3. Emits each record as an individual event for ingestion and enrichment via the built-in ingest pipeline + +## What data does this integration collect? + +The XM Cyber integration collects the following types of data: + +| Data stream | Description | Endpoint | +|---|---|---| +| `product` | **Product-level** aggregates from VRM: one event per software product with fleet-wide counts (devices where it appears, choke-point presence, affected critical assets, products critical assets at risk, vulnerability count), vendor, and reported operating systems. | `/api/v2/vrm/public/products` | + +### Supported use cases + +- **Software exposure across the fleet**: Rank products by `product_vulnerabilities`, `devices_found_on`, and `choke_points_found_on`, and slice by `product_operating_systems` to align remediation with platform mix. +- **Critical-asset risk from products**: Use `affected_critical_assets` and `products_critical_assets_at_risk` with vendor and OS context to prioritize patch and upgrade work. + +## What do I need to use this integration? + +- **XM Cyber tenant**: An active XM Cyber deployment with access to `https://.clients.xmcyber.com` +- **API key**: An XM Cyber API key associated with a user holding at minimum the **Security Analyst** role. Create one in **Settings → API / Integrations** in your XM Cyber admin console (refer to the XM Cyber customer portal at https://customers.xmcyber.com for current navigation steps) +- **Elastic Agent**: Version 8.18+ or 9.0+ with Fleet enrollment + +## How do I deploy this integration? + +This integration supports both Elastic Agentless-based and Agent-based installations. + +### Agentless-based installation + +Agentless integrations allow you to collect data without having to manage Elastic Agent in your cloud. They make manual agent deployment unnecessary, so you can focus on your data instead of the agent that collects it. For more information, refer to [Agentless integrations](https://www.elastic.co/guide/en/serverless/current/security-agentless-integrations.html) and the [Agentless integrations FAQ](https://www.elastic.co/guide/en/serverless/current/agentless-integration-troubleshooting.html). + +Agentless deployments are only supported in Elastic Serverless and Elastic Cloud environments. This functionality is in beta and is subject to change. Beta features are not subject to the support SLA of official GA features. + +### Agent-based installation + +Elastic Agent must be installed. For more details, check the Elastic Agent [installation instructions](docs-content://reference/fleet/install-elastic-agents.md). You can install only one Elastic Agent per host. + +### Configure + +1. In Kibana, navigate to **Fleet → Integrations** and search for **XM Cyber** +2. Click **Add XM Cyber** +3. Configure the integration settings: + - **URL**: Your XM Cyber base URL, for example `https://your-org.clients.xmcyber.com` + - **API Key**: Your XM Cyber API key. + - **Interval**: How often to poll for new data (default: `24h`). +4. Select **Save and continue** to save the integration. + +### Validation + +#### Dashboard populated + +1. In the top search bar in Kibana, search for **Dashboards**. +2. In the search bar, type **XM Cyber**, and verify the dashboard information is populated. + +## Scaling + +For more information on architectures that can be used for scaling this integration, check the [Ingest Architectures](https://www.elastic.co/docs/manage-data/ingest/ingest-reference-architectures) documentation. + +## Troubleshooting + +- **Authentication failures**: Verify the API key is valid and the URL includes the full `https://` prefix with no trailing slash +- **No data collected**: Check the Elastic Agent logs for CEL program errors. Ensure your XM Cyber user has the Security Analyst role and API access is enabled in your tenant settings +- **Rate limiting**: XM Cyber API rate limits are not publicly documented. If you observe HTTP 429 responses in agent logs, increase the collection interval + +For help with Elastic ingest tools, check [Common problems](https://www.elastic.co/docs/troubleshoot/ingest/fleet/common-problems). + +## Reference + +### Product + +#### Product fields + +{{fields "product"}} + +### Example event + +#### Product + +{{event "product"}} + +### Inputs used + +{{ inputDocs }} + +### API usage + +These XM Cyber REST API endpoints are used by this integration: + +| Endpoint | Method | Data stream | Description | +|---|---|---|---| +| `/api/auth` | POST | all | Exchange API key for Bearer access token | +| `/api/refresh-token` | POST | all | Refresh an expired access token | +| `/api/v2/vrm/public/products` | GET | `product` | Paginated product-level exposure aggregates (counts and OS list per product) | diff --git a/packages/xm_cyber/_dev/deploy/docker/docker-compose.yml b/packages/xm_cyber/_dev/deploy/docker/docker-compose.yml new file mode 100644 index 00000000000..7e7632542af --- /dev/null +++ b/packages/xm_cyber/_dev/deploy/docker/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3.8' +services: + xm_cyber: + image: docker.elastic.co/observability/stream:v0.20.0 + hostname: xm_cyber + ports: + - 8090 + volumes: + - ./files:/files:ro + environment: + PORT: '8090' + command: + - http-server + - --addr=:8090 + - --config=/files/config.yml \ No newline at end of file diff --git a/packages/xm_cyber/_dev/deploy/docker/files/config.yml b/packages/xm_cyber/_dev/deploy/docker/files/config.yml new file mode 100644 index 00000000000..8b43afb8e74 --- /dev/null +++ b/packages/xm_cyber/_dev/deploy/docker/files/config.yml @@ -0,0 +1,96 @@ +rules: + # ----- Authentication ----- + - path: /api/auth + methods: ['POST'] + request_headers: + X-Api-Key: "mock-api-key" + responses: + - status_code: 200 + headers: + Content-Type: + - 'application/json' + body: |- + {{ minify_json ` + { + "accessToken": "mock-access-token-vuln", + "refreshToken": "mock-refresh-token-vuln" + } + `}} + + # ----- Refresh-token ----- + - path: /api/refresh-token + methods: ['POST'] + request_headers: + Content-Type: + - 'application/json' + request_body: /.*"refreshToken".*/ + responses: + - status_code: 200 + headers: + Content-Type: + - 'application/json' + body: |- + {{ minify_json ` + { + "accessToken": "mock-access-token-vuln-refreshed", + "refreshToken": "mock-refresh-token-vuln-refreshed" + } + `}} + + - path: /api/v2/vrm/public/products + methods: ['GET'] + query_params: + pageSize: '20' + request_headers: + Authorization: "Bearer mock-access-token-vuln" + responses: + - status_code: 200 + headers: + Content-Type: + - 'application/json' + body: |- + {{ minify_json ` + { + "data": [ + { + "affectedCriticalAssets": 2, + "chokePointsFoundOn": 0, + "devicesFoundOn": 2, + "productName": "wget", + "productOperatingSystems": ["Linux sles 12.5 Server"], + "productVulnerabilities": 1, + "productsCriticalAssetsAtRisk": 0, + "vendor": null + }, + { + "affectedCriticalAssets": 26, + "chokePointsFoundOn": 6, + "devicesFoundOn": 26, + "productName": ".net framework", + "productOperatingSystems": [ + "Windows 10 ver 1909", + "Windows Server 2012 R2", + "Windows 7 SP 1.0", + "Windows Server 2012 R2 (DC)", + "Windows Server 2019 (DC)" + ], + "productVulnerabilities": 71, + "productsCriticalAssetsAtRisk": 38, + "vendor": "microsoft" + }, + { + "affectedCriticalAssets": 1, + "chokePointsFoundOn": 1, + "devicesFoundOn": 1, + "productName": "ACME Secure Agent", + "productOperatingSystems": ["Windows Server 2019 (DC)", "Ubuntu 22.04"], + "productVulnerabilities": 4243, + "productsCriticalAssetsAtRisk": 12, + "vendor": "ACME" + } + ], + "meta": { + "next": null + } + } + `}} diff --git a/packages/xm_cyber/changelog.yml b/packages/xm_cyber/changelog.yml new file mode 100644 index 00000000000..debebbdc807 --- /dev/null +++ b/packages/xm_cyber/changelog.yml @@ -0,0 +1,11 @@ +# newer versions go on top +- version: 0.1.1 + changes: + - description: Add support for product data stream. + type: enhancement + link: https://github.com/elastic/integrations/pull/18993 +- version: 0.1.0 + changes: + - description: Add support for risk score data stream. + type: enhancement + link: https://github.com/elastic/integrations/pull/18749 diff --git a/packages/xm_cyber/data_stream/product/_dev/test/pipeline/test-common-config.yml b/packages/xm_cyber/data_stream/product/_dev/test/pipeline/test-common-config.yml new file mode 100644 index 00000000000..37e8fa225fd --- /dev/null +++ b/packages/xm_cyber/data_stream/product/_dev/test/pipeline/test-common-config.yml @@ -0,0 +1,3 @@ +fields: + tags: + - preserve_duplicate_custom_fields diff --git a/packages/xm_cyber/data_stream/product/_dev/test/pipeline/test-product.log b/packages/xm_cyber/data_stream/product/_dev/test/pipeline/test-product.log new file mode 100644 index 00000000000..3ca1ee5038d --- /dev/null +++ b/packages/xm_cyber/data_stream/product/_dev/test/pipeline/test-product.log @@ -0,0 +1,3 @@ +{"affectedCriticalAssets":2,"chokePointsFoundOn":0,"devicesFoundOn":2,"productName":"wget","productOperatingSystems":["Linux sles 12.5 Server"],"productVulnerabilities":1,"productsCriticalAssetsAtRisk":0,"vendor":null} +{"affectedCriticalAssets":26,"chokePointsFoundOn":6,"devicesFoundOn":26,"productName":".net framework","productOperatingSystems":["Windows 10 ver 1909","Windows Server 2012 R2","Windows 7 SP 1.0","Windows Server 2012 R2 (DC)","Windows Server 2019 (DC)"],"productVulnerabilities":71,"productsCriticalAssetsAtRisk":38,"vendor":"microsoft"} +{"affectedCriticalAssets":1,"chokePointsFoundOn":1,"devicesFoundOn":1,"productName":"ACME Secure Agent","productOperatingSystems":["Windows Server 2019 (DC)","Ubuntu 22.04"],"productVulnerabilities":4243,"productsCriticalAssetsAtRisk":12,"vendor":"ACME"} diff --git a/packages/xm_cyber/data_stream/product/_dev/test/pipeline/test-product.log-expected.json b/packages/xm_cyber/data_stream/product/_dev/test/pipeline/test-product.log-expected.json new file mode 100644 index 00000000000..d2155613638 --- /dev/null +++ b/packages/xm_cyber/data_stream/product/_dev/test/pipeline/test-product.log-expected.json @@ -0,0 +1,86 @@ +{ + "expected": [ + { + "ecs": { + "version": "9.3.0" + }, + "event": { + "kind": "event", + "original": "{\"affectedCriticalAssets\":2,\"chokePointsFoundOn\":0,\"devicesFoundOn\":2,\"productName\":\"wget\",\"productOperatingSystems\":[\"Linux sles 12.5 Server\"],\"productVulnerabilities\":1,\"productsCriticalAssetsAtRisk\":0,\"vendor\":null}" + }, + "tags": [ + "preserve_duplicate_custom_fields" + ], + "xm_cyber": { + "product": { + "affected_critical_assets": 2, + "choke_points_found_on": 0, + "devices_found_on": 2, + "product_name": "wget", + "product_operating_systems": [ + "Linux sles 12.5 Server" + ], + "product_vulnerabilities": 1, + "products_critical_assets_at_risk": 0 + } + } + }, + { + "ecs": { + "version": "9.3.0" + }, + "event": { + "kind": "event", + "original": "{\"affectedCriticalAssets\":26,\"chokePointsFoundOn\":6,\"devicesFoundOn\":26,\"productName\":\".net framework\",\"productOperatingSystems\":[\"Windows 10 ver 1909\",\"Windows Server 2012 R2\",\"Windows 7 SP 1.0\",\"Windows Server 2012 R2 (DC)\",\"Windows Server 2019 (DC)\"],\"productVulnerabilities\":71,\"productsCriticalAssetsAtRisk\":38,\"vendor\":\"microsoft\"}" + }, + "tags": [ + "preserve_duplicate_custom_fields" + ], + "xm_cyber": { + "product": { + "affected_critical_assets": 26, + "choke_points_found_on": 6, + "devices_found_on": 26, + "product_name": ".net framework", + "product_operating_systems": [ + "Windows 10 ver 1909", + "Windows Server 2012 R2", + "Windows 7 SP 1.0", + "Windows Server 2012 R2 (DC)", + "Windows Server 2019 (DC)" + ], + "product_vulnerabilities": 71, + "products_critical_assets_at_risk": 38, + "vendor": "microsoft" + } + } + }, + { + "ecs": { + "version": "9.3.0" + }, + "event": { + "kind": "event", + "original": "{\"affectedCriticalAssets\":1,\"chokePointsFoundOn\":1,\"devicesFoundOn\":1,\"productName\":\"ACME Secure Agent\",\"productOperatingSystems\":[\"Windows Server 2019 (DC)\",\"Ubuntu 22.04\"],\"productVulnerabilities\":4243,\"productsCriticalAssetsAtRisk\":12,\"vendor\":\"ACME\"}" + }, + "tags": [ + "preserve_duplicate_custom_fields" + ], + "xm_cyber": { + "product": { + "affected_critical_assets": 1, + "choke_points_found_on": 1, + "devices_found_on": 1, + "product_name": "ACME Secure Agent", + "product_operating_systems": [ + "Windows Server 2019 (DC)", + "Ubuntu 22.04" + ], + "product_vulnerabilities": 4243, + "products_critical_assets_at_risk": 12, + "vendor": "ACME" + } + } + } + ] +} diff --git a/packages/xm_cyber/data_stream/product/_dev/test/system/test-default-config.yml b/packages/xm_cyber/data_stream/product/_dev/test/system/test-default-config.yml new file mode 100644 index 00000000000..f15ddb80341 --- /dev/null +++ b/packages/xm_cyber/data_stream/product/_dev/test/system/test-default-config.yml @@ -0,0 +1,14 @@ +wait_for_data_timeout: 1m +input: cel +service: xm_cyber +vars: + url: http://{{Hostname}}:{{Port}} + api_key: mock-api-key +data_stream: + vars: + interval: 24h + page_size: 20 + preserve_original_event: true + preserve_duplicate_custom_fields: true +assert: + min_count: 2 diff --git a/packages/xm_cyber/data_stream/product/agent/stream/cel.yml.hbs b/packages/xm_cyber/data_stream/product/agent/stream/cel.yml.hbs new file mode 100644 index 00000000000..a60b31689ab --- /dev/null +++ b/packages/xm_cyber/data_stream/product/agent/stream/cel.yml.hbs @@ -0,0 +1,216 @@ +config_version: 2 +interval: {{interval}} +resource.tracer: + enabled: {{enable_request_tracer}} + filename: "../../logs/cel/http-request-trace-*.ndjson" + maxbackups: 5 +{{#if proxy_url}} +resource.proxy_url: {{proxy_url}} +{{/if}} +{{#if ssl}} +resource.ssl: {{ssl}} +{{/if}} +{{#if http_client_timeout}} +resource.timeout: {{http_client_timeout}} +{{/if}} +resource.url: {{url}} +state: + api_key: {{api_key}} + page_size: {{page_size}} +redact: + fields: + - api_key + - access_token + - refresh_token +program: | + state.url.trim_right("/").as(base, + ( + ( + state.?cursor.access_token.orValue("") == "" || state.?cursor.refresh_token.orValue("") == "" || + state.?cursor.need_reauth.orValue(false) + ) ? + post_request(base + "/api/auth", "application/json", "{}").with( + { + "Header": { + "X-Api-Key": [state.api_key], + "Content-Type": ["application/json"], + }, + } + ).do_request().as(authResp, + (authResp.StatusCode == 200) ? + authResp.Body.decode_json().as(ao, + { + "ok": true, + "access": string(ao.accessToken), + "refresh": string(ao.refreshToken), + } + ) + : + { + "ok": false, + "err_code": string(authResp.StatusCode), + "err_status": string(authResp.Status), + "err_body": (size(authResp.Body) != 0) ? string(authResp.Body) : string(authResp.Status), + } + ) + : + { + "ok": true, + "access": string(state.?cursor.access_token.orValue("")), + "refresh": string(state.?cursor.refresh_token.orValue("")), + } + ).as(tok, + !tok.ok ? + { + "events": { + "error": { + "code": tok.err_code, + "id": tok.err_status, + "message": "POST " + base + "/api/auth: " + tok.err_body, + }, + }, + "cursor": { + "access_token": "", + "refresh_token": "", + "need_reauth": true, + }, + "next_page": { + ?"link": state.?next_page.?link, + }, + "want_more": false, + } + : + ( + (state.?next_page.?link.orValue("") != "") ? + state.next_page.link.replace_all("http://", "https://") + : + base + "/api/v2/vrm/public/products?" + { + "pageSize": [string(int(state.?page_size.orValue(100)))], + }.format_query() + ).as(dataUrl, + request("GET", dataUrl).with( + { + "Header": { + "Authorization": ["Bearer " + tok.access], + "Accept": ["application/json"], + }, + } + ).do_request().as(resp, + (resp.StatusCode == 200) ? + resp.Body.decode_json().as(body, + { + "events": body.?data.orValue([]).map(e, {"message": e.encode_json()}), + "cursor": { + "access_token": tok.access, + "refresh_token": tok.refresh, + "need_reauth": false, + }, + "next_page": { + ?"link": ( + body.?meta != null && has(body.meta.next) && body.meta.next != null && + string(body.meta.next) != "" + ) ? optional.of(string(body.meta.next).replace_all("http://", "https://")) : optional.none(), + }, + "want_more": body.?meta != null && has(body.meta.next) && body.meta.next != null && + string(body.meta.next) != "", + } + ) + : (resp.StatusCode == 401 || resp.StatusCode == 419) ? + post_request( + base + "/api/refresh-token", + "application/json", + {"refreshToken": tok.refresh}.encode_json() + ).with( + { + "Header": {"Content-Type": ["application/json"]}, + } + ).do_request().as(refResp, + (refResp.StatusCode == 200) ? + refResp.Body.decode_json().as(ro, + { + "events": [{"message": "Refresh token successful"}], + "cursor": { + "access_token": string(ro.accessToken), + "refresh_token": string(ro.refreshToken), + "need_reauth": false, + }, + "next_page": { + ?"link": optional.of(dataUrl), + }, + "want_more": true, + } + ) + : + { + "events": [{"message": "Refresh token expired, forcing re-auth"}], + "cursor": { + "access_token": "", + "refresh_token": "", + "need_reauth": true, + }, + "next_page": { + ?"link": optional.of(dataUrl), + }, + "want_more": true, + } + ) + : (resp.StatusCode == 429) ? + { + "events": { + "error": { + "code": string(resp.StatusCode), + "id": string(resp.Status), + "message": "GET vrm/public/products: rate limited", + }, + }, + "cursor": { + "access_token": tok.access, + "refresh_token": tok.refresh, + "need_reauth": false, + }, + "next_page": { + ?"link": optional.of(dataUrl), + }, + "want_more": false, + } + : + { + "events": { + "error": { + "code": string(resp.StatusCode), + "id": string(resp.Status), + "message": "GET vrm/public/products: " + ((size(resp.Body) != 0) ? string(resp.Body) : string(resp.Status)), + }, + }, + "cursor": { + "access_token": tok.access, + "refresh_token": tok.refresh, + "need_reauth": false, + }, + "next_page": { + ?"link": optional.of(dataUrl), + }, + "want_more": false, + } + ) + ) + ) + ) + +tags: +{{#if preserve_original_event}} + - preserve_original_event +{{/if}} +{{#if preserve_duplicate_custom_fields}} + - preserve_duplicate_custom_fields +{{/if}} +{{#each tags as |tag|}} + - {{tag}} +{{/each}} +{{#contains "forwarded" tags}} +publisher_pipeline.disable_host: true +{{/contains}} +{{#if processors}} +processors: +{{processors}} +{{/if}} diff --git a/packages/xm_cyber/data_stream/product/elasticsearch/ingest_pipeline/default.yml b/packages/xm_cyber/data_stream/product/elasticsearch/ingest_pipeline/default.yml new file mode 100644 index 00000000000..9428b448fe2 --- /dev/null +++ b/packages/xm_cyber/data_stream/product/elasticsearch/ingest_pipeline/default.yml @@ -0,0 +1,228 @@ +--- +description: Pipeline for processing XM Cyber VRM products. +processors: + - set: + tag: set_ecs_version + field: ecs.version + value: 9.3.0 + - terminate: + description: Error message set and no data to process. + tag: terminate_data_collection_error + if: ctx.error?.message != null && ctx.message == null && ctx.event?.original == null + + - drop: + description: Drops CEL informational token-refresh success messages from the ingest stream. + tag: drop_cel_refresh_token_success + if: ctx.message instanceof String && ctx.message == 'Refresh token successful' + - drop: + description: Drops CEL informational expired-refresh messages from the ingest stream. + tag: drop_cel_refresh_token_force_reauth + if: ctx.message instanceof String && ctx.message == 'Refresh token expired, forcing re-auth' + + - remove: + description: Removes the fields added by Agentless as metadata, as they can collide with ECS fields. + tag: remove_agentless_tags + if: ctx.organization instanceof String && ctx.division instanceof String && ctx.team instanceof String + field: + - organization + - division + - team + ignore_missing: true + + - rename: + description: Renames the original `message` field to `event.original` to store a copy of the original message. + tag: rename_message_to_event_original + if: ctx.event?.original == null + field: message + target_field: event.original + ignore_missing: true + - remove: + description: The `message` field is no longer required if the document has an `event.original` field. + tag: remove_message + if: ctx.event?.original != null + field: message + ignore_missing: true + + - json: + tag: json_event_original_into_xm_cyber_product + field: event.original + target_field: xm_cyber.product + if: ctx.event?.original != null + + - set: + tag: set_event_kind_event + field: event.kind + value: event + + - script: + description: Convert field names from camelCase to snake_case recursively under xm_cyber.product. + tag: script_convert_camelcase_to_snake_case + lang: painless + source: |- + String camelToSnake(String str) { + def result = ""; + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (Character.isUpperCase(c)) { + if (i > 0 && Character.isLowerCase(str.charAt(i - 1))) { + result += "_"; + } + result += Character.toLowerCase(c); + } else { + result += c; + } + } + return result; + } + def convertToSnakeCase(def obj) { + if (obj instanceof Map) { + def newObj = [:]; + for (entry in obj.entrySet()) { + String newKey = camelToSnake(entry.getKey()); + newObj[newKey] = convertToSnakeCase(entry.getValue()); + } + return newObj; + } else if (obj instanceof List) { + def newList = []; + for (item in obj) { + newList.add(convertToSnakeCase(item)); + } + return newList; + } else { + return obj; + } + } + if (ctx.xm_cyber?.product != null) { + ctx.xm_cyber.product = convertToSnakeCase(ctx.xm_cyber.product); + } + on_failure: + - append: + tag: append_error_message_script_camel_to_snake + field: error.message + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + + - fingerprint: + tag: fingerprint_with_event_original + description: Stable document id from the canonical raw payload (product rows lack a unique id field). + fields: + - xm_cyber.product.product_name + target_field: _id + ignore_missing: true + + - convert: + tag: convert_affected_critical_assets_long + field: xm_cyber.product.affected_critical_assets + type: long + ignore_missing: true + if: ctx.xm_cyber?.product?.affected_critical_assets != '' + on_failure: + - remove: + field: xm_cyber.product.affected_critical_assets + ignore_missing: true + - append: + field: error.message + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - convert: + tag: convert_choke_points_found_on_long + field: xm_cyber.product.choke_points_found_on + type: long + ignore_missing: true + if: ctx.xm_cyber?.product?.choke_points_found_on != '' + on_failure: + - remove: + field: xm_cyber.product.choke_points_found_on + ignore_missing: true + - append: + field: error.message + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - convert: + tag: convert_devices_found_on_long + field: xm_cyber.product.devices_found_on + type: long + ignore_missing: true + if: ctx.xm_cyber?.product?.devices_found_on != '' + on_failure: + - remove: + field: xm_cyber.product.devices_found_on + ignore_missing: true + - append: + field: error.message + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - convert: + tag: convert_product_vulnerabilities_long + field: xm_cyber.product.product_vulnerabilities + type: long + ignore_missing: true + if: ctx.xm_cyber?.product?.product_vulnerabilities != '' + on_failure: + - remove: + field: xm_cyber.product.product_vulnerabilities + ignore_missing: true + - append: + field: error.message + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - convert: + tag: convert_products_critical_assets_at_risk_long + field: xm_cyber.product.products_critical_assets_at_risk + type: long + ignore_missing: true + if: ctx.xm_cyber?.product?.products_critical_assets_at_risk != '' + on_failure: + - remove: + field: xm_cyber.product.products_critical_assets_at_risk + ignore_missing: true + - append: + field: error.message + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + + - script: + tag: script_to_drop_null_values + lang: painless + description: This script processor iterates over the whole document to remove fields with null values. + source: |- + void handleMap(Map map) { + map.values().removeIf(v -> { + if (v instanceof Map) { + handleMap(v); + } else if (v instanceof List) { + handleList(v); + } + return v == null || v == '' || (v instanceof Map && v.size() == 0) || (v instanceof List && v.size() == 0) + }); + } + void handleList(List list) { + list.removeIf(v -> { + if (v instanceof Map) { + handleMap(v); + } else if (v instanceof List) { + handleList(v); + } + return v == null || v == '' || (v instanceof Map && v.size() == 0) || (v instanceof List && v.size() == 0) + }); + } + handleMap(ctx); + + - append: + tag: append_preserve_on_collector_error + field: tags + value: preserve_original_event + allow_duplicates: false + if: ctx.error?.message != null + +on_failure: + - append: + tag: pipeline_on_failure_error_message + field: error.message + value: >- + Processor '{{{ _ingest.on_failure_processor_type }}}' + {{{#_ingest.on_failure_processor_tag}}}with tag '{{{ _ingest.on_failure_processor_tag }}}' + {{{/_ingest.on_failure_processor_tag}}}failed with message '{{{ _ingest.on_failure_message }}}' + - set: + tag: set_pipeline_error_to_event_kind + field: event.kind + value: pipeline_error + - append: + tag: pipeline_on_failure_preserve_original + field: tags + value: preserve_original_event + allow_duplicates: false diff --git a/packages/xm_cyber/data_stream/product/fields/base-fields.yml b/packages/xm_cyber/data_stream/product/fields/base-fields.yml new file mode 100644 index 00000000000..567b1b84758 --- /dev/null +++ b/packages/xm_cyber/data_stream/product/fields/base-fields.yml @@ -0,0 +1,20 @@ +- name: data_stream.type + type: constant_keyword + description: Data stream type. +- name: data_stream.dataset + type: constant_keyword + description: Data stream dataset. +- name: data_stream.namespace + type: constant_keyword + description: Data stream namespace. +- name: event.module + type: constant_keyword + description: Event module. + value: xm_cyber +- name: event.dataset + type: constant_keyword + description: Event dataset. + value: xm_cyber.product +- name: '@timestamp' + type: date + description: Event timestamp. diff --git a/packages/xm_cyber/data_stream/product/fields/beats.yml b/packages/xm_cyber/data_stream/product/fields/beats.yml new file mode 100644 index 00000000000..4084f1dc7f5 --- /dev/null +++ b/packages/xm_cyber/data_stream/product/fields/beats.yml @@ -0,0 +1,6 @@ +- name: input.type + type: keyword + description: Type of filebeat input. +- name: log.offset + type: long + description: Log offset. diff --git a/packages/xm_cyber/data_stream/product/fields/ecs.yml b/packages/xm_cyber/data_stream/product/fields/ecs.yml new file mode 100644 index 00000000000..4ddf6ceaff1 --- /dev/null +++ b/packages/xm_cyber/data_stream/product/fields/ecs.yml @@ -0,0 +1,8 @@ +- name: observer.product + external: ecs + type: constant_keyword + value: Continuous Exposure Management +- name: observer.vendor + external: ecs + type: constant_keyword + value: XM Cyber diff --git a/packages/xm_cyber/data_stream/product/fields/fields.yml b/packages/xm_cyber/data_stream/product/fields/fields.yml new file mode 100644 index 00000000000..77bd5207fd9 --- /dev/null +++ b/packages/xm_cyber/data_stream/product/fields/fields.yml @@ -0,0 +1,27 @@ +- name: xm_cyber.product + type: group + fields: + - name: product_name + type: keyword + description: Product display name from the API. + - name: vendor + type: keyword + description: Software vendor when present. + - name: devices_found_on + type: long + description: Number of devices where this product is installed. + - name: choke_points_found_on + type: long + description: Count of choke-point contexts where this product appears. + - name: affected_critical_assets + type: long + description: Affected critical assets count for this product. + - name: products_critical_assets_at_risk + type: long + description: Critical assets at risk attributed to this product. + - name: product_vulnerabilities + type: long + description: Vulnerability count associated with this product. + - name: product_operating_systems + type: keyword + description: OS strings where the product is reported diff --git a/packages/xm_cyber/data_stream/product/manifest.yml b/packages/xm_cyber/data_stream/product/manifest.yml new file mode 100644 index 00000000000..b5b08fe5512 --- /dev/null +++ b/packages/xm_cyber/data_stream/product/manifest.yml @@ -0,0 +1,69 @@ +title: Product +type: logs +streams: + - input: cel + title: Product + description: Collect Product logs from XM Cyber. + template_path: cel.yml.hbs + vars: + - name: interval + type: text + title: Interval + description: How often to poll the XM Cyber Product API. Supported time units are s, m, h. + required: true + show_user: true + default: 24h + - name: page_size + type: integer + title: Page size + description: Number of results per page. Must be between 1 and 100. + required: true + show_user: false + default: 100 + - name: http_client_timeout + type: text + title: HTTP Client Timeout + description: Duration before the HTTP client request times out (e.g. 60s). + required: true + show_user: false + default: 60s + - name: enable_request_tracer + type: bool + title: Enable request tracing + description: Log HTTP request/response traces to the agent for debugging. Do not enable in production. + required: false + show_user: false + default: false + - name: tags + type: text + title: Tags + description: Tags to add to every collected event. + multi: true + required: true + show_user: true + default: + - forwarded + - xm_cyber-product + - name: preserve_original_event + type: bool + title: Preserve original event + description: Keep a copy of the raw event in `event.original`. + required: true + show_user: true + default: false + - name: preserve_duplicate_custom_fields + required: false + show_user: false + title: Preserve duplicate custom fields + description: Preserve xm_cyber.product fields that were copied to Elastic Common Schema (ECS) fields. + type: bool + multi: false + default: false + - name: processors + type: yaml + title: Processors + multi: false + required: false + show_user: false + description: >- + Processors are used to reduce the number of fields in the exported event or to enhance the event with metadata. This executes in the agent before the logs are parsed. See [Processors](https://www.elastic.co/guide/en/beats/filebeat/current/filtering-and-enhancing-data.html) for details. diff --git a/packages/xm_cyber/data_stream/product/sample_event.json b/packages/xm_cyber/data_stream/product/sample_event.json new file mode 100644 index 00000000000..c32e590d88b --- /dev/null +++ b/packages/xm_cyber/data_stream/product/sample_event.json @@ -0,0 +1,52 @@ +{ + "@timestamp": "2026-05-13T11:44:04.838Z", + "agent": { + "ephemeral_id": "13e22d2c-7ced-4d9a-afb5-e94d8b620438", + "id": "af2eda72-a3ff-4eb2-8bf9-ee73ee225eb9", + "name": "elastic-agent-64555", + "type": "filebeat", + "version": "8.18.0" + }, + "data_stream": { + "dataset": "xm_cyber.product", + "namespace": "15554", + "type": "logs" + }, + "ecs": { + "version": "9.3.0" + }, + "elastic_agent": { + "id": "af2eda72-a3ff-4eb2-8bf9-ee73ee225eb9", + "snapshot": false, + "version": "8.18.0" + }, + "event": { + "agent_id_status": "verified", + "dataset": "xm_cyber.product", + "ingested": "2026-05-13T11:44:07Z", + "kind": "event", + "original": "{\"affectedCriticalAssets\":2,\"chokePointsFoundOn\":0,\"devicesFoundOn\":2,\"productName\":\"wget\",\"productOperatingSystems\":[\"Linux sles 12.5 Server\"],\"productVulnerabilities\":1,\"productsCriticalAssetsAtRisk\":0,\"vendor\":null}" + }, + "input": { + "type": "cel" + }, + "tags": [ + "preserve_original_event", + "preserve_duplicate_custom_fields", + "forwarded", + "xm_cyber-product" + ], + "xm_cyber": { + "product": { + "affected_critical_assets": 2, + "choke_points_found_on": 0, + "devices_found_on": 2, + "product_name": "wget", + "product_operating_systems": [ + "Linux sles 12.5 Server" + ], + "product_vulnerabilities": 1, + "products_critical_assets_at_risk": 0 + } + } +} diff --git a/packages/xm_cyber/docs/README.md b/packages/xm_cyber/docs/README.md new file mode 100644 index 00000000000..d9cc6a7b8b5 --- /dev/null +++ b/packages/xm_cyber/docs/README.md @@ -0,0 +1,211 @@ +# XM Cyber Integration + +## Overview + +[XM Cyber](https://www.xmcyber.com) is a **Continuous Threat Exposure Management (CTEM)** and attack path management platform. It continuously simulates attacker movement across hybrid environments including on-premises, cloud, and identity infrastructure — combining vulnerabilities, misconfigurations, and overly permissive access into prioritized attack paths that lead to **critical assets**. + +This integration collects data from the XM Cyber REST API using scheduled polling. It provides visibility into your organization's security posture across your environment. + +### Compatibility + +The XM Cyber integration is compatible with the API version **1.0.0**. + +### How it works + +The integration uses the Elastic Agent CEL (Common Expression Language) input to poll the XM Cyber REST API on a configurable schedule. Each poll: + +1. Authenticates with a two-step flow: exchanges the API key for a short-lived Bearer access token via `POST /api/auth` +2. Fetches data from the configured endpoint. +3. Emits each record as an individual event for ingestion and enrichment via the built-in ingest pipeline + +## What data does this integration collect? + +The XM Cyber integration collects the following types of data: + +| Data stream | Description | Endpoint | +|---|---|---| +| `product` | **Product-level** aggregates from VRM: one event per software product with fleet-wide counts (devices where it appears, choke-point presence, affected critical assets, products critical assets at risk, vulnerability count), vendor, and reported operating systems. | `/api/v2/vrm/public/products` | + +### Supported use cases + +- **Software exposure across the fleet**: Rank products by `product_vulnerabilities`, `devices_found_on`, and `choke_points_found_on`, and slice by `product_operating_systems` to align remediation with platform mix. +- **Critical-asset risk from products**: Use `affected_critical_assets` and `products_critical_assets_at_risk` with vendor and OS context to prioritize patch and upgrade work. + +## What do I need to use this integration? + +- **XM Cyber tenant**: An active XM Cyber deployment with access to `https://.clients.xmcyber.com` +- **API key**: An XM Cyber API key associated with a user holding at minimum the **Security Analyst** role. Create one in **Settings → API / Integrations** in your XM Cyber admin console (refer to the XM Cyber customer portal at https://customers.xmcyber.com for current navigation steps) +- **Elastic Agent**: Version 8.18+ or 9.0+ with Fleet enrollment + +## How do I deploy this integration? + +This integration supports both Elastic Agentless-based and Agent-based installations. + +### Agentless-based installation + +Agentless integrations allow you to collect data without having to manage Elastic Agent in your cloud. They make manual agent deployment unnecessary, so you can focus on your data instead of the agent that collects it. For more information, refer to [Agentless integrations](https://www.elastic.co/guide/en/serverless/current/security-agentless-integrations.html) and the [Agentless integrations FAQ](https://www.elastic.co/guide/en/serverless/current/agentless-integration-troubleshooting.html). + +Agentless deployments are only supported in Elastic Serverless and Elastic Cloud environments. This functionality is in beta and is subject to change. Beta features are not subject to the support SLA of official GA features. + +### Agent-based installation + +Elastic Agent must be installed. For more details, check the Elastic Agent [installation instructions](docs-content://reference/fleet/install-elastic-agents.md). You can install only one Elastic Agent per host. + +### Configure + +1. In Kibana, navigate to **Fleet → Integrations** and search for **XM Cyber** +2. Click **Add XM Cyber** +3. Configure the integration settings: + - **URL**: Your XM Cyber base URL, for example `https://your-org.clients.xmcyber.com` + - **API Key**: Your XM Cyber API key. + - **Interval**: How often to poll for new data (default: `24h`). +4. Select **Save and continue** to save the integration. + +### Validation + +#### Dashboard populated + +1. In the top search bar in Kibana, search for **Dashboards**. +2. In the search bar, type **XM Cyber**, and verify the dashboard information is populated. + +## Scaling + +For more information on architectures that can be used for scaling this integration, check the [Ingest Architectures](https://www.elastic.co/docs/manage-data/ingest/ingest-reference-architectures) documentation. + +## Troubleshooting + +- **Authentication failures**: Verify the API key is valid and the URL includes the full `https://` prefix with no trailing slash +- **No data collected**: Check the Elastic Agent logs for CEL program errors. Ensure your XM Cyber user has the Security Analyst role and API access is enabled in your tenant settings +- **Rate limiting**: XM Cyber API rate limits are not publicly documented. If you observe HTTP 429 responses in agent logs, increase the collection interval + +For help with Elastic ingest tools, check [Common problems](https://www.elastic.co/docs/troubleshoot/ingest/fleet/common-problems). + +## Reference + +### Product + +#### Product fields + +**Exported fields** + +| Field | Description | Type | +|---|---|---| +| @timestamp | Event timestamp. | date | +| data_stream.dataset | Data stream dataset. | constant_keyword | +| data_stream.namespace | Data stream namespace. | constant_keyword | +| data_stream.type | Data stream type. | constant_keyword | +| event.dataset | Event dataset. | constant_keyword | +| event.module | Event module. | constant_keyword | +| input.type | Type of filebeat input. | keyword | +| log.offset | Log offset. | long | +| observer.product | The product name of the observer. | constant_keyword | +| observer.vendor | Vendor name of the observer. | constant_keyword | +| xm_cyber.product.affected_critical_assets | Affected critical assets count for this product. | long | +| xm_cyber.product.choke_points_found_on | Count of choke-point contexts where this product appears. | long | +| xm_cyber.product.devices_found_on | Number of devices where this product is installed. | long | +| xm_cyber.product.product_name | Product display name from the API. | keyword | +| xm_cyber.product.product_operating_systems | OS strings where the product is reported | keyword | +| xm_cyber.product.product_vulnerabilities | Vulnerability count associated with this product. | long | +| xm_cyber.product.products_critical_assets_at_risk | Critical assets at risk attributed to this product. | long | +| xm_cyber.product.vendor | Software vendor when present. | keyword | + + +### Example event + +#### Product + +An example event for `product` looks as following: + +```json +{ + "@timestamp": "2026-05-13T11:44:04.838Z", + "agent": { + "ephemeral_id": "13e22d2c-7ced-4d9a-afb5-e94d8b620438", + "id": "af2eda72-a3ff-4eb2-8bf9-ee73ee225eb9", + "name": "elastic-agent-64555", + "type": "filebeat", + "version": "8.18.0" + }, + "data_stream": { + "dataset": "xm_cyber.product", + "namespace": "15554", + "type": "logs" + }, + "ecs": { + "version": "9.3.0" + }, + "elastic_agent": { + "id": "af2eda72-a3ff-4eb2-8bf9-ee73ee225eb9", + "snapshot": false, + "version": "8.18.0" + }, + "event": { + "agent_id_status": "verified", + "dataset": "xm_cyber.product", + "ingested": "2026-05-13T11:44:07Z", + "kind": "event", + "original": "{\"affectedCriticalAssets\":2,\"chokePointsFoundOn\":0,\"devicesFoundOn\":2,\"productName\":\"wget\",\"productOperatingSystems\":[\"Linux sles 12.5 Server\"],\"productVulnerabilities\":1,\"productsCriticalAssetsAtRisk\":0,\"vendor\":null}" + }, + "input": { + "type": "cel" + }, + "tags": [ + "preserve_original_event", + "preserve_duplicate_custom_fields", + "forwarded", + "xm_cyber-product" + ], + "xm_cyber": { + "product": { + "affected_critical_assets": 2, + "choke_points_found_on": 0, + "devices_found_on": 2, + "product_name": "wget", + "product_operating_systems": [ + "Linux sles 12.5 Server" + ], + "product_vulnerabilities": 1, + "products_critical_assets_at_risk": 0 + } + } +} +``` + +### Inputs used + +These inputs can be used with this integration: +
+cel + +## Setup + +For more details about the CEL input settings, check the [Filebeat documentation](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-cel.html). + +Before configuring the CEL input, make sure you have: +- Network connectivity to the target API endpoint +- Valid authentication credentials (API keys, tokens, or certificates as required) +- Appropriate permissions to read from the target data source + +### Collecting logs from CEL + +To configure the CEL input, you must specify the `request.url` value pointing to the API endpoint. The interval parameter controls how frequently requests are made and is the primary way to balance data freshness with API rate limits and costs. Authentication is often configured through the `request.headers` section using the appropriate method for the service. + +NOTE: To access the API service, make sure you have the necessary API credentials and that the Filebeat instance can reach the endpoint URL. Some services may require IP whitelisting or VPN access. + +To collect logs via API endpoint, configure the following parameters: + +- API Endpoint URL +- API credentials (tokens, keys, or username/password) +- Request interval (how often to fetch data) +
+ + +### API usage + +These XM Cyber REST API endpoints are used by this integration: + +| Endpoint | Method | Data stream | Description | +|---|---|---|---| +| `/api/auth` | POST | all | Exchange API key for Bearer access token | +| `/api/refresh-token` | POST | all | Refresh an expired access token | +| `/api/v2/vrm/public/products` | GET | `product` | Paginated product-level exposure aggregates (counts and OS list per product) | diff --git a/packages/xm_cyber/img/xm_cyber-logo.svg b/packages/xm_cyber/img/xm_cyber-logo.svg new file mode 100644 index 00000000000..fc50863fd0e --- /dev/null +++ b/packages/xm_cyber/img/xm_cyber-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/xm_cyber/img/xm_cyber-product.png b/packages/xm_cyber/img/xm_cyber-product.png new file mode 100644 index 00000000000..1fc0d4ad24b Binary files /dev/null and b/packages/xm_cyber/img/xm_cyber-product.png differ diff --git a/packages/xm_cyber/kibana/dashboard/xm_cyber-8591539b-edd7-42bb-bfa0-2ea26a334900.json b/packages/xm_cyber/kibana/dashboard/xm_cyber-8591539b-edd7-42bb-bfa0-2ea26a334900.json new file mode 100644 index 00000000000..a7e2327b524 --- /dev/null +++ b/packages/xm_cyber/kibana/dashboard/xm_cyber-8591539b-edd7-42bb-bfa0-2ea26a334900.json @@ -0,0 +1,1765 @@ +{ + "attributes": { + "controlGroupInput": { + "chainingSystem": "HIERARCHICAL", + "controlStyle": "oneLine", + "ignoreParentSettingsJSON": { + "ignoreFilters": false, + "ignoreQuery": false, + "ignoreTimerange": false, + "ignoreValidations": false + }, + "panelsJSON": { + "33a0c6e8-2840-42e4-a30c-c062794054d3": { + "explicitInput": { + "dataViewId": "logs-*", + "fieldName": "xm_cyber.product.product_operating_systems", + "searchTechnique": "prefix", + "selectedOptions": [], + "sort": { + "by": "_count", + "direction": "desc" + }, + "title": "Operating System" + }, + "grow": true, + "order": 1, + "type": "optionsListControl", + "width": "medium" + }, + "5e9a6a6e-9c26-474c-afe5-3583d90882cb": { + "explicitInput": { + "dataViewId": "logs-*", + "fieldName": "xm_cyber.product.vendor", + "searchTechnique": "prefix", + "selectedOptions": [], + "sort": { + "by": "_count", + "direction": "desc" + }, + "title": "Vendor" + }, + "grow": true, + "order": 0, + "type": "optionsListControl", + "width": "medium" + }, + "a545fdb7-7c16-488c-868d-5d99761f0bb2": { + "explicitInput": { + "dataViewId": "logs-*", + "fieldName": "xm_cyber.product.product_name", + "searchTechnique": "prefix", + "selectedOptions": [], + "sort": { + "by": "_count", + "direction": "desc" + }, + "title": "Product Name" + }, + "grow": true, + "order": 2, + "type": "optionsListControl", + "width": "medium" + } + }, + "showApplySelections": false + }, + "description": "Overview of Vulnerable Product from XM Cyber.", + "kibanaSavedObjectMeta": { + "searchSourceJSON": { + "filter": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "query": { + "language": "kuery", + "query": "" + } + } + }, + "optionsJSON": { + "hidePanelTitles": false, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false, + "useMargins": true + }, + "panelsJSON": [ + { + "embeddableConfig": { + "attributes": { + "references": [ + { + "id": "logs-*", + "name": "indexpattern-datasource-layer-4294e47f-f288-40d2-8abd-6733f368b914", + "type": "index-pattern" + } + ], + "state": { + "adHocDataViews": {}, + "datasourceStates": { + "formBased": { + "currentIndexPatternId": "logs-*", + "layers": { + "4294e47f-f288-40d2-8abd-6733f368b914": { + "columnOrder": [ + "df3c70be-bb04-4022-92e3-b27e3b079939", + "0dd9a410-811d-4609-8647-08f350b376c4", + "71552fd8-1efa-44d0-ab27-ba0ec55b0edf" + ], + "columns": { + "0dd9a410-811d-4609-8647-08f350b376c4": { + "customLabel": true, + "dataType": "string", + "isBucketed": true, + "label": "Product Name", + "operationType": "terms", + "params": { + "exclude": [], + "excludeIsRegex": false, + "include": [], + "includeIsRegex": false, + "missingBucket": false, + "orderBy": { + "columnId": "71552fd8-1efa-44d0-ab27-ba0ec55b0edf", + "type": "column" + }, + "orderDirection": "desc", + "otherBucket": true, + "parentFormat": { + "id": "terms" + }, + "secondaryFields": [], + "size": 10 + }, + "scale": "ordinal", + "sourceField": "xm_cyber.product.product_name" + }, + "71552fd8-1efa-44d0-ab27-ba0ec55b0edf": { + "customLabel": true, + "dataType": "number", + "filter": { + "language": "kuery", + "query": "xm_cyber.product.product_vulnerabilities \u003e= 1" + }, + "isBucketed": false, + "label": "Count", + "operationType": "count", + "params": { + "emptyAsNull": false + }, + "scale": "ratio", + "sourceField": "___records___" + }, + "df3c70be-bb04-4022-92e3-b27e3b079939": { + "customLabel": true, + "dataType": "string", + "isBucketed": true, + "label": "Vendor", + "operationType": "terms", + "params": { + "exclude": [], + "excludeIsRegex": false, + "include": [], + "includeIsRegex": false, + "missingBucket": false, + "orderBy": { + "columnId": "71552fd8-1efa-44d0-ab27-ba0ec55b0edf", + "type": "column" + }, + "orderDirection": "desc", + "otherBucket": true, + "parentFormat": { + "id": "terms" + }, + "size": 10 + }, + "scale": "ordinal", + "sourceField": "xm_cyber.product.vendor" + } + }, + "ignoreGlobalFilters": false, + "incompleteColumns": {}, + "indexPatternId": "logs-*", + "sampling": 1 + } + } + }, + "indexpattern": { + "currentIndexPatternId": "logs-*", + "layers": {} + }, + "textBased": { + "indexPatternRefs": [ + { + "id": "logs-*", + "timeField": "@timestamp", + "title": "logs-*" + } + ], + "layers": {} + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "internalReferences": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "layers": [ + { + "accessors": [ + "71552fd8-1efa-44d0-ab27-ba0ec55b0edf" + ], + "colorMapping": { + "assignments": [], + "colorMode": { + "type": "categorical" + }, + "paletteId": "eui_amsterdam_color_blind", + "specialAssignments": [ + { + "color": { + "type": "loop" + }, + "rule": { + "type": "other" + }, + "touched": false + } + ] + }, + "layerId": "4294e47f-f288-40d2-8abd-6733f368b914", + "layerType": "data", + "position": "top", + "seriesType": "bar_horizontal_stacked", + "showGridlines": false, + "splitAccessor": "df3c70be-bb04-4022-92e3-b27e3b079939", + "xAccessor": "0dd9a410-811d-4609-8647-08f350b376c4" + } + ], + "legend": { + "isVisible": true, + "position": "right", + "shouldTruncate": false, + "showSingleSeries": true + }, + "preferredSeriesType": "bar_stacked", + "title": "Empty XY chart", + "valueLabels": "hide" + } + }, + "title": "", + "type": "lens", + "visualizationType": "lnsXY" + }, + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "query": { + "language": "kuery", + "query": "" + }, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false + }, + "gridData": { + "h": 15, + "i": "9ed22739-5452-4b6e-b482-e2bab51edda0", + "w": 24, + "x": 0, + "y": 23 + }, + "panelIndex": "9ed22739-5452-4b6e-b482-e2bab51edda0", + "title": "Vulnerable Products by Vendor", + "type": "lens" + }, + { + "embeddableConfig": { + "attributes": { + "references": [ + { + "id": "logs-*", + "name": "indexpattern-datasource-layer-4294e47f-f288-40d2-8abd-6733f368b914", + "type": "index-pattern" + } + ], + "state": { + "adHocDataViews": {}, + "datasourceStates": { + "formBased": { + "currentIndexPatternId": "logs-*", + "layers": { + "4294e47f-f288-40d2-8abd-6733f368b914": { + "columnOrder": [ + "0dd9a410-811d-4609-8647-08f350b376c4", + "71552fd8-1efa-44d0-ab27-ba0ec55b0edf" + ], + "columns": { + "0dd9a410-811d-4609-8647-08f350b376c4": { + "customLabel": true, + "dataType": "string", + "isBucketed": true, + "label": "Product Name", + "operationType": "terms", + "params": { + "exclude": [], + "excludeIsRegex": false, + "include": [], + "includeIsRegex": false, + "missingBucket": false, + "orderBy": { + "columnId": "71552fd8-1efa-44d0-ab27-ba0ec55b0edf", + "type": "column" + }, + "orderDirection": "desc", + "otherBucket": true, + "parentFormat": { + "id": "terms" + }, + "secondaryFields": [], + "size": 10 + }, + "scale": "ordinal", + "sourceField": "xm_cyber.product.product_name" + }, + "71552fd8-1efa-44d0-ab27-ba0ec55b0edf": { + "customLabel": true, + "dataType": "number", + "filter": null, + "isBucketed": false, + "label": "Devices Found On", + "operationType": "sum", + "params": { + "emptyAsNull": false + }, + "reducedTimeRange": null, + "scale": "ratio", + "sourceField": "xm_cyber.product.devices_found_on", + "timeScale": null, + "timeShift": null + } + }, + "ignoreGlobalFilters": false, + "incompleteColumns": {}, + "indexPatternId": "logs-*", + "sampling": 1 + } + } + }, + "indexpattern": { + "currentIndexPatternId": "logs-*", + "layers": {} + }, + "textBased": { + "indexPatternRefs": [ + { + "id": "logs-*", + "timeField": "@timestamp", + "title": "logs-*" + } + ], + "initialContext": null, + "layers": {} + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "internalReferences": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "layers": [ + { + "accessors": [ + "71552fd8-1efa-44d0-ab27-ba0ec55b0edf" + ], + "colorMapping": { + "assignments": [], + "colorMode": { + "type": "categorical" + }, + "paletteId": "eui_amsterdam_color_blind", + "specialAssignments": [ + { + "color": { + "type": "loop" + }, + "rule": { + "type": "other" + }, + "touched": false + } + ] + }, + "layerId": "4294e47f-f288-40d2-8abd-6733f368b914", + "layerType": "data", + "position": "top", + "seriesType": "bar_horizontal_stacked", + "showGridlines": false, + "xAccessor": "0dd9a410-811d-4609-8647-08f350b376c4" + } + ], + "legend": { + "isVisible": true, + "position": "right", + "shouldTruncate": false, + "showSingleSeries": false + }, + "preferredSeriesType": "bar_stacked", + "title": "Empty XY chart", + "valueLabels": "hide" + } + }, + "title": "", + "type": "lens", + "visualizationType": "lnsXY" + }, + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "query": { + "language": "kuery", + "query": "" + }, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false + }, + "gridData": { + "h": 15, + "i": "d4ad5093-460c-4c8f-af6b-761f737cbc15", + "w": 24, + "x": 24, + "y": 23 + }, + "panelIndex": "d4ad5093-460c-4c8f-af6b-761f737cbc15", + "title": "Products by Count of Devices Found on", + "type": "lens" + }, + { + "embeddableConfig": { + "attributes": { + "references": [ + { + "id": "logs-*", + "name": "indexpattern-datasource-layer-4294e47f-f288-40d2-8abd-6733f368b914", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "c1972e8e-2162-4727-b70b-102feb86b74f", + "type": "index-pattern" + } + ], + "state": { + "adHocDataViews": {}, + "datasourceStates": { + "formBased": { + "layers": { + "4294e47f-f288-40d2-8abd-6733f368b914": { + "columnOrder": [ + "0dd9a410-811d-4609-8647-08f350b376c4", + "71552fd8-1efa-44d0-ab27-ba0ec55b0edf" + ], + "columns": { + "0dd9a410-811d-4609-8647-08f350b376c4": { + "customLabel": true, + "dataType": "string", + "isBucketed": true, + "label": "Product Name", + "operationType": "terms", + "params": { + "exclude": [], + "excludeIsRegex": false, + "include": [], + "includeIsRegex": false, + "missingBucket": false, + "orderBy": { + "columnId": "71552fd8-1efa-44d0-ab27-ba0ec55b0edf", + "type": "column" + }, + "orderDirection": "desc", + "otherBucket": true, + "parentFormat": { + "id": "terms" + }, + "secondaryFields": [], + "size": 10 + }, + "scale": "ordinal", + "sourceField": "xm_cyber.product.product_name" + }, + "71552fd8-1efa-44d0-ab27-ba0ec55b0edf": { + "customLabel": true, + "dataType": "number", + "isBucketed": false, + "label": "Choke Points Found On", + "operationType": "sum", + "params": { + "emptyAsNull": false + }, + "scale": "ratio", + "sourceField": "xm_cyber.product.choke_points_found_on" + } + }, + "ignoreGlobalFilters": false, + "incompleteColumns": {}, + "sampling": 1 + } + } + }, + "indexpattern": { + "layers": {} + }, + "textBased": { + "layers": {} + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "c1972e8e-2162-4727-b70b-102feb86b74f", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "internalReferences": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "layers": [ + { + "accessors": [ + "71552fd8-1efa-44d0-ab27-ba0ec55b0edf" + ], + "colorMapping": { + "assignments": [], + "colorMode": { + "type": "categorical" + }, + "paletteId": "eui_amsterdam_color_blind", + "specialAssignments": [ + { + "color": { + "type": "loop" + }, + "rule": { + "type": "other" + }, + "touched": false + } + ] + }, + "layerId": "4294e47f-f288-40d2-8abd-6733f368b914", + "layerType": "data", + "position": "top", + "seriesType": "bar_horizontal_stacked", + "showGridlines": false, + "xAccessor": "0dd9a410-811d-4609-8647-08f350b376c4" + } + ], + "legend": { + "isVisible": true, + "position": "right", + "shouldTruncate": false, + "showSingleSeries": false + }, + "preferredSeriesType": "bar_stacked", + "title": "Empty XY chart", + "valueLabels": "hide" + } + }, + "title": "", + "type": "lens", + "visualizationType": "lnsXY" + }, + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "query": { + "language": "kuery", + "query": "" + }, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false + }, + "gridData": { + "h": 15, + "i": "437fd13a-d7f7-4d08-baff-ea3ef52c1c91", + "w": 24, + "x": 0, + "y": 38 + }, + "panelIndex": "437fd13a-d7f7-4d08-baff-ea3ef52c1c91", + "title": "Products by Count of Choke Points Found on", + "type": "lens" + }, + { + "embeddableConfig": { + "attributes": { + "references": [ + { + "id": "logs-*", + "name": "indexpattern-datasource-layer-4294e47f-f288-40d2-8abd-6733f368b914", + "type": "index-pattern" + } + ], + "state": { + "adHocDataViews": {}, + "datasourceStates": { + "formBased": { + "currentIndexPatternId": "logs-*", + "layers": { + "4294e47f-f288-40d2-8abd-6733f368b914": { + "columnOrder": [ + "b46a2316-dbc9-4254-aea5-cdd72f914019", + "0dd9a410-811d-4609-8647-08f350b376c4", + "71552fd8-1efa-44d0-ab27-ba0ec55b0edf" + ], + "columns": { + "0dd9a410-811d-4609-8647-08f350b376c4": { + "customLabel": true, + "dataType": "string", + "isBucketed": true, + "label": "Product Name", + "operationType": "terms", + "params": { + "exclude": [], + "excludeIsRegex": false, + "include": [], + "includeIsRegex": false, + "missingBucket": false, + "orderBy": { + "columnId": "71552fd8-1efa-44d0-ab27-ba0ec55b0edf", + "type": "column" + }, + "orderDirection": "desc", + "otherBucket": true, + "parentFormat": { + "id": "terms" + }, + "secondaryFields": [], + "size": 10 + }, + "scale": "ordinal", + "sourceField": "xm_cyber.product.product_name" + }, + "71552fd8-1efa-44d0-ab27-ba0ec55b0edf": { + "customLabel": true, + "dataType": "number", + "filter": { + "language": "kuery", + "query": "xm_cyber.product.product_vulnerabilities \u003e= 1" + }, + "isBucketed": false, + "label": "Count", + "operationType": "count", + "params": { + "emptyAsNull": false + }, + "scale": "ratio", + "sourceField": "___records___" + }, + "b46a2316-dbc9-4254-aea5-cdd72f914019": { + "customLabel": true, + "dataType": "string", + "isBucketed": true, + "label": "Operating System", + "operationType": "terms", + "params": { + "exclude": [], + "excludeIsRegex": false, + "include": [], + "includeIsRegex": false, + "missingBucket": false, + "orderBy": { + "columnId": "71552fd8-1efa-44d0-ab27-ba0ec55b0edf", + "type": "column" + }, + "orderDirection": "desc", + "otherBucket": false, + "parentFormat": { + "id": "terms" + }, + "size": 10 + }, + "scale": "ordinal", + "sourceField": "xm_cyber.product.product_operating_systems" + } + }, + "ignoreGlobalFilters": false, + "incompleteColumns": {}, + "indexPatternId": "logs-*", + "sampling": 1 + } + } + }, + "indexpattern": { + "currentIndexPatternId": "logs-*", + "layers": {} + }, + "textBased": { + "indexPatternRefs": [ + { + "id": "logs-*", + "timeField": "@timestamp", + "title": "logs-*" + } + ], + "layers": {} + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "internalReferences": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "layers": [ + { + "accessors": [ + "71552fd8-1efa-44d0-ab27-ba0ec55b0edf" + ], + "colorMapping": { + "assignments": [], + "colorMode": { + "type": "categorical" + }, + "paletteId": "eui_amsterdam_color_blind", + "specialAssignments": [ + { + "color": { + "type": "loop" + }, + "rule": { + "type": "other" + }, + "touched": false + } + ] + }, + "layerId": "4294e47f-f288-40d2-8abd-6733f368b914", + "layerType": "data", + "position": "top", + "seriesType": "bar_horizontal_stacked", + "showGridlines": false, + "splitAccessor": "b46a2316-dbc9-4254-aea5-cdd72f914019", + "xAccessor": "0dd9a410-811d-4609-8647-08f350b376c4" + } + ], + "legend": { + "isVisible": true, + "position": "right", + "shouldTruncate": false, + "showSingleSeries": true + }, + "preferredSeriesType": "bar_stacked", + "title": "Empty XY chart", + "valueLabels": "hide" + } + }, + "title": "", + "type": "lens", + "visualizationType": "lnsXY" + }, + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "query": { + "language": "kuery", + "query": "" + }, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false + }, + "gridData": { + "h": 15, + "i": "9b9e0c91-f4fe-4c81-b437-2fbf7cf1f145", + "w": 24, + "x": 24, + "y": 38 + }, + "panelIndex": "9b9e0c91-f4fe-4c81-b437-2fbf7cf1f145", + "title": "Vulnerable Products by Operating System", + "type": "lens" + }, + { + "embeddableConfig": { + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "savedVis": { + "data": { + "aggs": [], + "searchSource": { + "filter": [], + "query": { + "language": "kuery", + "query": "" + } + } + }, + "description": "", + "id": "", + "params": { + "fontSize": 12, + "markdown": "**Overview**\n\nThe XM Cyber Product dashboard surfaces a single-pane view of software exposure reported by XM Cyber VRM over time, with breakdowns by vendor, operating system, how widely each title appears across the fleet, how often it aligns with choke-point context, and how vulnerability burden stacks up so teams can see which products concentrate risk and where remediation would have the broadest reach.\n\nKPI tiles for total products, total vulnerability count across those products, and total critical assets at risk help analysts quickly size the backlog and stress business impact in one glance. Controls for vendor, operating system, and product name make it easy to narrow the board to a specific cohort, a time series shows how activity trends through the selected window, and horizontal bar views rank products by vendor mix, device footprint, choke-point presence, and platform mix to support prioritization and ongoing visibility across the XM Cyber environment.\n\n\n**[Integration Page](/app/integrations/detail/xm_cyber)**", + "openLinksInNewTab": false + }, + "title": "", + "type": "markdown", + "uiState": {} + } + }, + "gridData": { + "h": 23, + "i": "585201f8-1fa4-460e-aca4-8c61fe95c73f", + "w": 13, + "x": 0, + "y": 0 + }, + "panelIndex": "585201f8-1fa4-460e-aca4-8c61fe95c73f", + "type": "visualization" + }, + { + "embeddableConfig": { + "attributes": { + "references": [ + { + "id": "logs-*", + "name": "indexpattern-datasource-layer-7d7a51c3-a665-4e72-bc0d-3c0793bcd571", + "type": "index-pattern" + } + ], + "state": { + "adHocDataViews": {}, + "datasourceStates": { + "formBased": { + "currentIndexPatternId": "logs-*", + "layers": { + "7d7a51c3-a665-4e72-bc0d-3c0793bcd571": { + "columnOrder": [ + "96df7ab9-c862-4bbc-af83-0a2fd2050c07" + ], + "columns": { + "96df7ab9-c862-4bbc-af83-0a2fd2050c07": { + "customLabel": true, + "dataType": "number", + "isBucketed": false, + "label": "Total Product Vulnerabilities", + "operationType": "sum", + "params": { + "emptyAsNull": false + }, + "scale": "ratio", + "sourceField": "xm_cyber.product.product_vulnerabilities" + } + }, + "ignoreGlobalFilters": false, + "incompleteColumns": {}, + "indexPatternId": "logs-*", + "sampling": 1 + } + } + }, + "indexpattern": { + "currentIndexPatternId": "logs-*", + "layers": {} + }, + "textBased": { + "indexPatternRefs": [ + { + "id": "logs-*", + "timeField": "@timestamp", + "title": "logs-*" + } + ], + "layers": {} + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "internalReferences": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "color": "#6092C0", + "layerId": "7d7a51c3-a665-4e72-bc0d-3c0793bcd571", + "layerType": "data", + "metricAccessor": "96df7ab9-c862-4bbc-af83-0a2fd2050c07" + } + }, + "title": "", + "type": "lens", + "visualizationType": "lnsMetric" + }, + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "hidePanelTitles": true, + "query": { + "language": "kuery", + "query": "" + }, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false + }, + "gridData": { + "h": 10, + "i": "ec243de5-d057-44be-8dc3-688f3eed9bf4", + "w": 11, + "x": 13, + "y": 0 + }, + "panelIndex": "ec243de5-d057-44be-8dc3-688f3eed9bf4", + "title": "", + "type": "lens" + }, + { + "embeddableConfig": { + "attributes": { + "references": [ + { + "id": "logs-*", + "name": "indexpattern-datasource-layer-7d7a51c3-a665-4e72-bc0d-3c0793bcd571", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "38980937-c23d-4434-85a3-3df58f586fad", + "type": "index-pattern" + } + ], + "state": { + "adHocDataViews": {}, + "datasourceStates": { + "formBased": { + "layers": { + "7d7a51c3-a665-4e72-bc0d-3c0793bcd571": { + "columnOrder": [ + "96df7ab9-c862-4bbc-af83-0a2fd2050c07" + ], + "columns": { + "96df7ab9-c862-4bbc-af83-0a2fd2050c07": { + "customLabel": true, + "dataType": "number", + "isBucketed": false, + "label": "Total Products", + "operationType": "count", + "params": { + "emptyAsNull": false + }, + "scale": "ratio", + "sourceField": "___records___" + } + }, + "ignoreGlobalFilters": false, + "incompleteColumns": {}, + "sampling": 1 + } + } + }, + "indexpattern": { + "layers": {} + }, + "textBased": { + "layers": {} + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "38980937-c23d-4434-85a3-3df58f586fad", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "internalReferences": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "color": "#6092C0", + "layerId": "7d7a51c3-a665-4e72-bc0d-3c0793bcd571", + "layerType": "data", + "metricAccessor": "96df7ab9-c862-4bbc-af83-0a2fd2050c07" + } + }, + "title": "", + "type": "lens", + "visualizationType": "lnsMetric" + }, + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "hidePanelTitles": true, + "query": { + "language": "kuery", + "query": "" + }, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false + }, + "gridData": { + "h": 10, + "i": "0eed2f10-c5f9-4a5d-a22e-57e142821c6c", + "w": 12, + "x": 24, + "y": 0 + }, + "panelIndex": "0eed2f10-c5f9-4a5d-a22e-57e142821c6c", + "title": "", + "type": "lens" + }, + { + "embeddableConfig": { + "attributes": { + "references": [ + { + "id": "logs-*", + "name": "indexpattern-datasource-layer-7d7a51c3-a665-4e72-bc0d-3c0793bcd571", + "type": "index-pattern" + } + ], + "state": { + "adHocDataViews": {}, + "datasourceStates": { + "formBased": { + "currentIndexPatternId": "logs-*", + "layers": { + "7d7a51c3-a665-4e72-bc0d-3c0793bcd571": { + "columnOrder": [ + "96df7ab9-c862-4bbc-af83-0a2fd2050c07" + ], + "columns": { + "96df7ab9-c862-4bbc-af83-0a2fd2050c07": { + "customLabel": true, + "dataType": "number", + "filter": null, + "isBucketed": false, + "label": "Total Products Critical Assets at Risk", + "operationType": "sum", + "params": { + "emptyAsNull": false + }, + "reducedTimeRange": null, + "scale": "ratio", + "sourceField": "xm_cyber.product.products_critical_assets_at_risk", + "timeScale": null, + "timeShift": null + } + }, + "ignoreGlobalFilters": false, + "incompleteColumns": {}, + "indexPatternId": "logs-*", + "sampling": 1 + } + } + }, + "indexpattern": { + "currentIndexPatternId": "logs-*", + "layers": {} + }, + "textBased": { + "indexPatternRefs": [ + { + "id": "logs-*", + "timeField": "@timestamp", + "title": "logs-*" + } + ], + "initialContext": null, + "layers": {} + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "internalReferences": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "color": "#6092C0", + "layerId": "7d7a51c3-a665-4e72-bc0d-3c0793bcd571", + "layerType": "data", + "metricAccessor": "96df7ab9-c862-4bbc-af83-0a2fd2050c07" + } + }, + "title": "", + "type": "lens", + "visualizationType": "lnsMetric" + }, + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "hidePanelTitles": true, + "query": { + "language": "kuery", + "query": "" + }, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false + }, + "gridData": { + "h": 10, + "i": "8c45b013-7a36-4689-ba26-bab832ca93aa", + "w": 12, + "x": 36, + "y": 0 + }, + "panelIndex": "8c45b013-7a36-4689-ba26-bab832ca93aa", + "title": "", + "type": "lens" + }, + { + "embeddableConfig": { + "attributes": { + "references": [ + { + "id": "logs-*", + "name": "indexpattern-datasource-layer-5ebb0180-4bf4-47b4-b303-2172b248b089", + "type": "index-pattern" + } + ], + "state": { + "adHocDataViews": {}, + "datasourceStates": { + "formBased": { + "currentIndexPatternId": "logs-*", + "layers": { + "5ebb0180-4bf4-47b4-b303-2172b248b089": { + "columnOrder": [ + "ba0a568d-b10c-4003-8c5a-9044850a3e71", + "4f827543-250d-4125-a61e-1d0a96ffa9d3" + ], + "columns": { + "4f827543-250d-4125-a61e-1d0a96ffa9d3": { + "customLabel": true, + "dataType": "number", + "filter": { + "language": "kuery", + "query": "xm_cyber.product.product_vulnerabilities \u003e= 1" + }, + "isBucketed": false, + "label": "Count", + "operationType": "count", + "params": { + "emptyAsNull": false + }, + "scale": "ratio", + "sourceField": "___records___" + }, + "ba0a568d-b10c-4003-8c5a-9044850a3e71": { + "dataType": "date", + "isBucketed": true, + "label": "@timestamp", + "operationType": "date_histogram", + "params": { + "dropPartials": false, + "includeEmptyRows": true, + "interval": "auto" + }, + "scale": "interval", + "sourceField": "@timestamp" + } + }, + "ignoreGlobalFilters": false, + "incompleteColumns": {}, + "indexPatternId": "logs-*", + "sampling": 1 + } + } + }, + "indexpattern": { + "currentIndexPatternId": "logs-*", + "layers": {} + }, + "textBased": { + "indexPatternRefs": [ + { + "id": "logs-*", + "timeField": "@timestamp", + "title": "logs-*" + } + ], + "layers": {} + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "internalReferences": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "layers": [ + { + "accessors": [ + "4f827543-250d-4125-a61e-1d0a96ffa9d3" + ], + "colorMapping": { + "assignments": [], + "colorMode": { + "type": "categorical" + }, + "paletteId": "eui_amsterdam_color_blind", + "specialAssignments": [ + { + "color": { + "type": "loop" + }, + "rule": { + "type": "other" + }, + "touched": false + } + ] + }, + "layerId": "5ebb0180-4bf4-47b4-b303-2172b248b089", + "layerType": "data", + "position": "top", + "seriesType": "line", + "showGridlines": false, + "xAccessor": "ba0a568d-b10c-4003-8c5a-9044850a3e71" + } + ], + "legend": { + "isVisible": true, + "position": "right", + "shouldTruncate": false + }, + "preferredSeriesType": "line", + "title": "Empty XY chart", + "valueLabels": "hide" + } + }, + "title": "", + "type": "lens", + "visualizationType": "lnsXY" + }, + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "index": "logs-*", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "xm_cyber.product" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "xm_cyber.product" + } + } + } + ], + "query": { + "language": "kuery", + "query": "" + }, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false + }, + "gridData": { + "h": 13, + "i": "9b6df5dc-5230-4873-be1f-31f9775b4bb0", + "w": 35, + "x": 13, + "y": 10 + }, + "panelIndex": "9b6df5dc-5230-4873-be1f-31f9775b4bb0", + "title": "Vulnerable Products over Time", + "type": "lens" + } + ], + "timeRestore": false, + "title": "[Logs XM Cyber] Product", + "version": 3 + }, + "coreMigrationVersion": "8.8.0", + "created_at": "2026-05-13T12:12:05.185Z", + "created_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", + "id": "xm_cyber-8591539b-edd7-42bb-bfa0-2ea26a334900", + "references": [ + { + "id": "logs-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "9ed22739-5452-4b6e-b482-e2bab51edda0:indexpattern-datasource-layer-4294e47f-f288-40d2-8abd-6733f368b914", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "d4ad5093-460c-4c8f-af6b-761f737cbc15:indexpattern-datasource-layer-4294e47f-f288-40d2-8abd-6733f368b914", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "437fd13a-d7f7-4d08-baff-ea3ef52c1c91:indexpattern-datasource-layer-4294e47f-f288-40d2-8abd-6733f368b914", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "437fd13a-d7f7-4d08-baff-ea3ef52c1c91:c1972e8e-2162-4727-b70b-102feb86b74f", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "9b9e0c91-f4fe-4c81-b437-2fbf7cf1f145:indexpattern-datasource-layer-4294e47f-f288-40d2-8abd-6733f368b914", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "ec243de5-d057-44be-8dc3-688f3eed9bf4:indexpattern-datasource-layer-7d7a51c3-a665-4e72-bc0d-3c0793bcd571", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "0eed2f10-c5f9-4a5d-a22e-57e142821c6c:indexpattern-datasource-layer-7d7a51c3-a665-4e72-bc0d-3c0793bcd571", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "0eed2f10-c5f9-4a5d-a22e-57e142821c6c:38980937-c23d-4434-85a3-3df58f586fad", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "8c45b013-7a36-4689-ba26-bab832ca93aa:indexpattern-datasource-layer-7d7a51c3-a665-4e72-bc0d-3c0793bcd571", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "9b6df5dc-5230-4873-be1f-31f9775b4bb0:indexpattern-datasource-layer-5ebb0180-4bf4-47b4-b303-2172b248b089", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "controlGroup_5e9a6a6e-9c26-474c-afe5-3583d90882cb:optionsListDataView", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "controlGroup_33a0c6e8-2840-42e4-a30c-c062794054d3:optionsListDataView", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "controlGroup_a545fdb7-7c16-488c-868d-5d99761f0bb2:optionsListDataView", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", + "type": "index-pattern" + } + ], + "type": "dashboard", + "typeMigrationVersion": "10.2.0", + "updated_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0" +} \ No newline at end of file diff --git a/packages/xm_cyber/manifest.yml b/packages/xm_cyber/manifest.yml new file mode 100644 index 00000000000..7380ba438a4 --- /dev/null +++ b/packages/xm_cyber/manifest.yml @@ -0,0 +1,69 @@ +format_version: "3.4.2" +name: xm_cyber +title: XM Cyber +version: 0.1.1 +description: Collect logs from XM Cyber with Elastic Agent. +type: integration +categories: + - security +conditions: + kibana: + version: "^8.19.0 || ^9.1.0" + elastic: + subscription: basic +screenshots: + - src: /img/xm_cyber-product.png + title: Product Dashboard + size: 600x600 + type: image/png +icons: + - src: /img/xm_cyber-logo.svg + title: XM Cyber logo + size: 32x32 + type: image/svg+xml +policy_templates: + - name: xm_cyber + title: XM Cyber + description: Collect logs from XM Cyber. + deployment_modes: + default: + enabled: true + agentless: + enabled: true + organization: security + division: engineering + team: security-service-integrations + inputs: + - type: cel + title: Collect logs from XM Cyber API + description: Collecting logs via XM Cyber API. + vars: + - name: url + type: url + title: XM Cyber Base URL + description: 'Full URL of your XM Cyber instance (e.g. https://myorg.clients.xmcyber.com). Do not include /api.' + show_user: true + required: true + - name: api_key + type: password + title: API Key + description: 'API key for XM Cyber authentication.' + show_user: true + required: true + secret: true + - name: proxy_url + type: url + title: Proxy URL + description: 'URL to proxy connections in the form of http[s]://:@:. Please ensure your username and password are in URL encoded format.' + show_user: false + required: false + - name: ssl + type: yaml + title: TLS Configuration + description: 'i.e. certificate_authorities, supported_protocols, verification_mode etc, more examples found in the [documentation](https://www.elastic.co/guide/en/beats/filebeat/current/configuration-ssl.html#ssl-common-config-reference).' + show_user: false + required: false + multi: false +owner: + github: elastic/security-service-integrations + type: elastic diff --git a/packages/xm_cyber/validation.yml b/packages/xm_cyber/validation.yml new file mode 100644 index 00000000000..1189aa63c89 --- /dev/null +++ b/packages/xm_cyber/validation.yml @@ -0,0 +1,3 @@ +errors: + exclude_checks: + - SVR00004 # References in dashboards.