From b87f4ffe3583af59b2a25e7f51d0c21c6e4efa29 Mon Sep 17 00:00:00 2001 From: CAWilson94 Date: Thu, 2 Apr 2026 15:00:33 +0100 Subject: [PATCH 1/2] Security Solution] Fix string spread bug when syncing watchlists to entity store Fixes a bug where single-string values in the Entity Store were being incorrectly parsed and spread into an array of individual characters during sync. If the Entity Store contained a single string value instead of an array (e.g., ), the sync logic would destructure it via , resulting in an array of characters . This commit adds defensive checks in both (when reading from Elasticsearch) and (before mutating) to ensure is always safely coerced into an array of strings before any spread operations occur. --- .../entity_analytics/watchlists/entities/service.ts | 10 ++++++++-- .../entity_sources/sync/entity_store_sync.ts | 8 ++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/watchlists/entities/service.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/watchlists/entities/service.ts index 34c46df8ed4ff..3fc76e878d9bb 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/watchlists/entities/service.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/watchlists/entities/service.ts @@ -101,9 +101,15 @@ export const createWatchlistEntitiesService = ({ acc.entityIdsByType[entityType].push(euid); - const watchlists = get(record, 'entity.attributes.watchlists') as string[] | undefined; + const rawWatchlists = get(record, 'entity.attributes.watchlists'); + const watchlists = Array.isArray(rawWatchlists) + ? rawWatchlists + : typeof rawWatchlists === 'string' + ? [rawWatchlists] + : undefined; + if (watchlists) { - acc.watchlistsByEuid.set(euid, watchlists); + acc.watchlistsByEuid.set(euid, watchlists as string[]); } if (!isIndexSync) { diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/watchlists/entity_sources/sync/entity_store_sync.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/watchlists/entity_sources/sync/entity_store_sync.ts index 39ff9cc9e4c21..bc26d4766be53 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/watchlists/entity_sources/sync/entity_store_sync.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/watchlists/entity_sources/sync/entity_store_sync.ts @@ -34,7 +34,11 @@ export const addWatchlistAttributeToStore = async ({ if (entityRefs.length === 0) return; const objects = entityRefs.map(({ euid, type, currentWatchlists }) => { - const watchlists = currentWatchlists ?? []; + const watchlists = Array.isArray(currentWatchlists) + ? currentWatchlists + : typeof currentWatchlists === 'string' + ? [currentWatchlists] + : []; const updated = watchlists.includes(watchlistId) ? watchlists : [...watchlists, watchlistId]; return { @@ -73,7 +77,7 @@ export const removeWatchlistAttributeFromStore = async ({ }): Promise => { // Only update entities whose current watchlists are known — if we don't have the current value we'd blindly write an empty array to the store. const knownRefs = entityRefs.filter((ref): ref is EntityRef & { currentWatchlists: string[] } => - Boolean(ref.currentWatchlists) + Boolean(ref.currentWatchlists) && Array.isArray(ref.currentWatchlists) ); if (knownRefs.length === 0) return; From 375c5e24c720a5cad3e0ad5466a5131cd4b4bec7 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 2 Apr 2026 14:31:49 +0000 Subject: [PATCH 2/2] Changes from node scripts/eslint_all_files --no-cache --fix --- .../watchlists/entity_sources/sync/entity_store_sync.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/watchlists/entity_sources/sync/entity_store_sync.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/watchlists/entity_sources/sync/entity_store_sync.ts index bc26d4766be53..3b1efa9063e22 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/watchlists/entity_sources/sync/entity_store_sync.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/watchlists/entity_sources/sync/entity_store_sync.ts @@ -76,8 +76,9 @@ export const removeWatchlistAttributeFromStore = async ({ watchlistId: string; }): Promise => { // Only update entities whose current watchlists are known — if we don't have the current value we'd blindly write an empty array to the store. - const knownRefs = entityRefs.filter((ref): ref is EntityRef & { currentWatchlists: string[] } => - Boolean(ref.currentWatchlists) && Array.isArray(ref.currentWatchlists) + const knownRefs = entityRefs.filter( + (ref): ref is EntityRef & { currentWatchlists: string[] } => + Boolean(ref.currentWatchlists) && Array.isArray(ref.currentWatchlists) ); if (knownRefs.length === 0) return;