diff --git a/package-lock.json b/package-lock.json
index b6daf8b..dbc90c1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,6 +13,7 @@
"@tiptap/starter-kit": "^3.13.0",
"classnames": "^2.5.1",
"date-fns": "^3.6.0",
+ "dompurify": "^3.4.12",
"file-saver": "^2.0.5",
"html-to-docx": "^1.8.0",
"lodash-es": "^4.17.21",
@@ -31,6 +32,7 @@
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.0",
+ "@types/dompurify": "^3.0.5",
"@types/file-saver": "^2.0.7",
"@types/html-to-docx": "^1.8.0",
"@types/lodash-es": "^4.17.12",
@@ -2685,6 +2687,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/dompurify": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz",
+ "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/trusted-types": "*"
+ }
+ },
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@@ -2783,6 +2795,13 @@
"@types/react": "^19.2.0"
}
},
+ "node_modules/@types/trusted-types": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/@types/use-sync-external-store": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
@@ -4287,6 +4306,15 @@
"domelementtype": "1"
}
},
+ "node_modules/dompurify": {
+ "version": "3.4.12",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.12.tgz",
+ "integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==",
+ "license": "(MPL-2.0 OR Apache-2.0)",
+ "optionalDependencies": {
+ "@types/trusted-types": "^2.0.7"
+ }
+ },
"node_modules/domutils": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
diff --git a/package.json b/package.json
index ccb01aa..986df7e 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"@tiptap/starter-kit": "^3.13.0",
"classnames": "^2.5.1",
"date-fns": "^3.6.0",
+ "dompurify": "^3.4.12",
"file-saver": "^2.0.5",
"html-to-docx": "^1.8.0",
"lodash-es": "^4.17.21",
@@ -34,6 +35,7 @@
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.0",
+ "@types/dompurify": "^3.0.5",
"@types/file-saver": "^2.0.7",
"@types/html-to-docx": "^1.8.0",
"@types/lodash-es": "^4.17.12",
diff --git a/src/components/CitationBrowser.tsx b/src/components/CitationBrowser.tsx
index e1829ab..a9f4a3e 100644
--- a/src/components/CitationBrowser.tsx
+++ b/src/components/CitationBrowser.tsx
@@ -4,6 +4,7 @@
*/
import { useState, useEffect, useCallback, useMemo } from 'react';
+import DOMPurify from 'dompurify';
import {
Search,
Filter,
@@ -47,6 +48,7 @@ import {
} from '../utils/citationService';
import type { CitationStyle } from '../utils/citationTypes';
import { formatCitation, citationToHtml } from '../utils/citationFormatter';
+import { safeHref } from '../utils/safeHref';
// ============================================
// Type Icons
@@ -207,7 +209,7 @@ function CitationPreview({ citation, style, onInsert, onClose, onCopyToClipboard
-
+