fix(#M5-QA): address security findings from code review

Fixes 2 important-level security issues identified in M5 QA:

1. XSS Protection (SearchResults.tsx):
   - Add DOMPurify sanitization for search result snippets
   - Configure to allow only <mark> tags for highlighting
   - Provides defense-in-depth against potential XSS

2. Error State (SearchPage):
   - Add user-facing error message when search fails
   - Display friendly error notification instead of silent failure
   - Improves UX by informing users of temporary issues

Testing:
- All 32 search component tests passing
- TypeScript typecheck passing
- DOMPurify properly sanitizes HTML while preserving highlighting

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
This commit is contained in:
Jason Woltje
2026-02-02 16:50:38 -06:00
co-authored by Claude Sonnet 4.5
parent 0e64dc8525
commit 6e63508f97
4 changed files with 60 additions and 5 deletions
+34 -3
View File
@@ -271,6 +271,12 @@ importers:
bullmq:
specifier: ^5.67.2
version: 5.67.2
class-transformer:
specifier: ^0.5.1
version: 0.5.1
class-validator:
specifier: ^0.14.1
version: 0.14.3
dockerode:
specifier: ^4.0.2
version: 4.0.9
@@ -344,6 +350,9 @@ importers:
'@tanstack/react-query':
specifier: ^5.90.20
version: 5.90.20([email protected])
'@types/dompurify':
specifier: ^3.2.0
version: 3.2.0
'@xyflow/react':
specifier: ^12.5.3
version: 12.10.0(@types/[email protected])([email protected]([email protected]))([email protected])
@@ -353,6 +362,9 @@ importers:
date-fns:
specifier: ^4.1.0
version: 4.1.0
dompurify:
specifier: ^3.3.1
version: 3.3.1
elkjs:
specifier: ^0.9.3
version: 0.9.3
@@ -2780,6 +2792,10 @@ packages:
'@types/[email protected]':
resolution: {integrity: sha512-ShM1mz7rCjdssXt7Xz0u1/R2BJC7piWa3SJpUBiVjCf2A3XNn4cP6pUVaD8bLanpPVVn4IKzJuw3dOvkJ8IbYw==}
'@types/[email protected]':
resolution: {integrity: sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg==}
deprecated: This is a stub types definition. dompurify provides its own type definitions, so you do not need this installed.
'@types/[email protected]':
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
@@ -6938,7 +6954,7 @@ snapshots:
chalk: 5.6.2
commander: 12.1.0
dotenv: 17.2.3
drizzle-orm: 0.41.0(@opentelemetry/[email protected])(@prisma/client@6.19.2([email protected]([email protected])([email protected]))([email protected]))(@types/[email protected])([email protected])([email protected])([email protected])([email protected]([email protected])([email protected]))
drizzle-orm: 0.41.0(@opentelemetry/[email protected])(@prisma/client@5.22.0([email protected]([email protected])([email protected])))(@types/[email protected])([email protected])([email protected])([email protected])([email protected]([email protected])([email protected]))
open: 10.2.0
pg: 8.17.2
prettier: 3.8.1
@@ -9164,6 +9180,10 @@ snapshots:
'@types/node': 22.19.7
'@types/ssh2': 1.15.5
'@types/[email protected]':
dependencies:
dompurify: 3.3.1
'@types/[email protected]':
dependencies:
'@types/eslint': 9.6.1
@@ -9823,7 +9843,7 @@ snapshots:
optionalDependencies:
'@prisma/client': 5.22.0([email protected]([email protected])([email protected]))
better-sqlite3: 12.6.2
drizzle-orm: 0.41.0(@opentelemetry/[email protected])(@prisma/client@6.19.2([email protected]([email protected])([email protected]))([email protected]))(@types/[email protected])([email protected])([email protected])([email protected])([email protected]([email protected])([email protected]))
drizzle-orm: 0.41.0(@opentelemetry/[email protected])(@prisma/client@5.22.0([email protected]([email protected])([email protected])))(@types/[email protected])([email protected])([email protected])([email protected])([email protected]([email protected])([email protected]))
next: 16.1.6(@babel/[email protected])(@opentelemetry/[email protected])([email protected]([email protected]))([email protected])
pg: 8.17.2
prisma: 6.19.2([email protected])([email protected])
@@ -9848,7 +9868,7 @@ snapshots:
optionalDependencies:
'@prisma/client': 6.19.2([email protected]([email protected])([email protected]))([email protected])
better-sqlite3: 12.6.2
drizzle-orm: 0.41.0(@opentelemetry/[email protected])(@prisma/client@6.19.2([email protected]([email protected])([email protected]))([email protected]))(@types/[email protected])([email protected])([email protected])([email protected])([email protected]([email protected])([email protected]))
drizzle-orm: 0.41.0(@opentelemetry/[email protected])(@prisma/client@5.22.0([email protected]([email protected])([email protected])))(@types/[email protected])([email protected])([email protected])([email protected])([email protected]([email protected])([email protected]))
next: 16.1.6(@babel/[email protected])(@opentelemetry/[email protected])([email protected]([email protected]))([email protected])
pg: 8.17.2
prisma: 6.19.2([email protected])([email protected])
@@ -10596,6 +10616,16 @@ snapshots:
[email protected]: {}
[email protected](@opentelemetry/[email protected])(@prisma/[email protected]([email protected]([email protected])([email protected])))(@types/[email protected])([email protected])([email protected])([email protected])([email protected]([email protected])([email protected])):
optionalDependencies:
'@opentelemetry/api': 1.9.0
'@prisma/client': 5.22.0([email protected]([email protected])([email protected]))
'@types/pg': 8.16.0
better-sqlite3: 12.6.2
kysely: 0.28.10
pg: 8.17.2
prisma: 6.19.2([email protected])([email protected])
[email protected](@opentelemetry/[email protected])(@prisma/[email protected]([email protected]([email protected])([email protected]))([email protected]))(@types/[email protected])([email protected])([email protected])([email protected])([email protected]([email protected])([email protected])):
optionalDependencies:
'@opentelemetry/api': 1.9.0
@@ -10605,6 +10635,7 @@ snapshots:
kysely: 0.28.10
pg: 8.17.2
prisma: 6.19.2([email protected])([email protected])
optional: true
[email protected]:
dependencies: