From d393c1d46586e0a277d8fd27465c225d0f6939d3 Mon Sep 17 00:00:00 2001 From: Philipp L Date: Wed, 8 Jul 2026 10:24:09 +0200 Subject: [PATCH 1/4] [FIX] Sanitize remaining customer-view columns and preserve raw sort/filter values - 'owner' (case owner username) and 'asset_type' were left unsanitized by the previous sanitation pass in this same table config. - sanitizeHTML was being applied unconditionally for every DataTables render call (display/sort/filter/type), causing the search box and sort order to operate on the HTML-encoded value instead of the raw one. Sanitize only for the 'display' type via a shared helper. - Guard asset_type/owner renderers against a null value (asset_type_id and case owner are both nullable). --- ui/src/pages/view.customers.js | 47 ++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/ui/src/pages/view.customers.js b/ui/src/pages/view.customers.js index 80833617a..dcee9340e 100644 --- a/ui/src/pages/view.customers.js +++ b/ui/src/pages/view.customers.js @@ -113,6 +113,15 @@ function refresh_client_users(customer_id) { }) } +// Sanitize only for the 'display' render type — DataTables also calls +// render() with 'sort'/'filter'/'type' to build its internal index, and +// those should compare against the raw value rather than the +// HTML-encoded one, or search/sort silently stops matching values that +// contain HTML-significant characters. +function safeTextRender(data, type) { + return type === 'display' ? sanitizeHTML(data) : data; +} + $(document).ready(function() { let customer_id = $('#customer_id').val(); @@ -134,16 +143,12 @@ $(document).ready(function() { }, { "data": "user_name", - "render": function(data, type, row) { - return sanitizeHTML(data); - } + "render": safeTextRender }, { "data": "user_login", - "render": function(data, type, row) { - return sanitizeHTML(data); - } + "render": safeTextRender }, { "data": "is_service_account", @@ -160,28 +165,24 @@ $(document).ready(function() { "columns": [ { "data": "asset_name", - "render": function(data, type, row) { - return sanitizeHTML(data); - } + "render": safeTextRender }, { "data": "asset_description", - "render": function(data, type, row) { - return sanitizeHTML(data); - } - + "render": safeTextRender }, { "data": "asset_type", "render": function(data, type, row) { - return sanitizeHTML(data.asset_name); + if (!data) { + return ''; + } + return type === 'display' ? sanitizeHTML(data.asset_name) : data.asset_name; } }, { "data": "asset_ip", - "render": function(data, type, row) { - return sanitizeHTML(data); - } + "render": safeTextRender }, { "data": "case_id", @@ -241,7 +242,7 @@ $(document).ready(function() { a_anchor.text(data); return a_anchor.prop('outerHTML'); } - return sanitizeHTML(data); + return data; } }, { @@ -253,17 +254,19 @@ $(document).ready(function() { { "data": "state", "render": function(data, type, row) { - if (data !== null) { - return data.state_name; - } else { + if (data === null) { return 'Unknown'; } + return type === 'display' ? sanitizeHTML(data.state_name) : data.state_name; } }, { "data": "owner", "render": function(data, type, row) { - return data.user_name; + if (!data) { + return ''; + } + return type === 'display' ? sanitizeHTML(data.user_name) : data.user_name; } } ], From 6a5b72b961f7d3a8599b277d7e7dacbd7130da36 Mon Sep 17 00:00:00 2001 From: Philipp L Date: Wed, 8 Jul 2026 10:25:01 +0200 Subject: [PATCH 2/4] [FIX] Sanitize modification-history entries in alert history modal user and action come from modification_history, which embeds the acting user's username verbatim. They were appended as raw HTML via jQuery .append(), so a username containing HTML/script executed when an analyst opened the alert history modal. --- ui/src/pages/alerts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/pages/alerts.js b/ui/src/pages/alerts.js index f5720e2d5..83dce6e64 100644 --- a/ui/src/pages/alerts.js +++ b/ui/src/pages/alerts.js @@ -1294,7 +1294,7 @@ async function showAlertHistory(alertId) { let date = new Date(Math.floor(entry) * 1000); let dateStr = date.toLocaleString(); let entryStr = alertData.modification_history[entry]; - entryDiv.append('
' + dateStr + '
' + entryStr.user + '
'+ entryStr.action +'
'); + entryDiv.append('
' + dateStr + '
' + sanitizeHTML(entryStr.user) + '
'+ sanitizeHTML(entryStr.action) +'
'); } From f05c9a6ce8f4685efbdbe2e5c296f92979885d1a Mon Sep 17 00:00:00 2001 From: Philipp L Date: Wed, 8 Jul 2026 10:25:16 +0200 Subject: [PATCH 3/4] [FIX] Sanitize alert title in asset linked-alerts popover alert_title was only quote-escaped before being embedded in the popover's HTML content, so a title containing unquoted HTML (e.g. an img tag with an onerror handler) still executed. Run it through sanitizeHTML before the quote-escaping used for the attribute context. --- ui/src/pages/case.asset.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/pages/case.asset.js b/ui/src/pages/case.asset.js index 4e83fd283..0e3241ff8 100644 --- a/ui/src/pages/case.asset.js +++ b/ui/src/pages/case.asset.js @@ -401,7 +401,7 @@ $(document).ready(function(){ let alerts_content = ""; row.alerts.forEach(alert => { - alerts_content += `#${alert.alert_id} - ${alert.alert_title.replace(/'/g, "'").replace(/"/g, """)}
`; + alerts_content += `#${alert.alert_id} - ${sanitizeHTML(alert.alert_title).replace(/'/g, "'").replace(/"/g, """)}
`; } ); alerts_content += `More..`; From 831740dc31e056e78deb2901e27fd3750680017b Mon Sep 17 00:00:00 2001 From: Philipp L Date: Wed, 8 Jul 2026 10:33:45 +0200 Subject: [PATCH 4/4] [FIX] Align 'state' column null-guard with sibling owner/asset_type columns Use the same falsy check (!data) as the owner/asset_type renderers instead of a strict === null comparison, so an undefined state value falls back to 'Unknown' instead of throwing on data.state_name. --- ui/src/pages/view.customers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/pages/view.customers.js b/ui/src/pages/view.customers.js index dcee9340e..09bd5135a 100644 --- a/ui/src/pages/view.customers.js +++ b/ui/src/pages/view.customers.js @@ -254,7 +254,7 @@ $(document).ready(function() { { "data": "state", "render": function(data, type, row) { - if (data === null) { + if (!data) { return 'Unknown'; } return type === 'display' ? sanitizeHTML(data.state_name) : data.state_name;