diff --git a/companion/extension/entrypoints/content.ts b/companion/extension/entrypoints/content.ts
index ce6a5a5a80..43225e2372 100644
--- a/companion/extension/entrypoints/content.ts
+++ b/companion/extension/entrypoints/content.ts
@@ -1,6 +1,7 @@
///
import { initGoogleCalendarIntegration } from "../lib/google-calendar";
import { initLinkedInIntegration } from "../lib/linkedin";
+import { escapeHtml } from "../lib/utils";
/**
* Development-only logging utility for content scripts.
@@ -964,7 +965,7 @@ export default defineContentScript({
contentWrapper.innerHTML = `
- ${title}
+ ${escapeHtml(title)}
${description}`
+ ? `${escapeHtml(description)}`
: ""
}
@@ -1714,7 +1715,7 @@ export default defineContentScript({
contentWrapper.innerHTML = `
- ${title}
+ ${escapeHtml(title)}
${description}`
+ ? `${escapeHtml(description)}`
: ""
}
diff --git a/companion/extension/lib/linkedin.ts b/companion/extension/lib/linkedin.ts
index 4e10603bd4..6f5b103aea 100644
--- a/companion/extension/lib/linkedin.ts
+++ b/companion/extension/lib/linkedin.ts
@@ -1,4 +1,5 @@
///
+import { escapeHtml } from "./utils";
// LinkedIn integration: inject a Cal.com scheduling button in LinkedIn messaging
@@ -951,15 +952,6 @@ export function initLinkedInIntegration() {
}
// ============================================================================
- // Utility Functions
- // ============================================================================
-
- function escapeHtml(text: string): string {
- const div = document.createElement("div");
- div.textContent = text;
- return div.innerHTML;
- }
-
// ============================================================================
// Initialization
// ============================================================================
diff --git a/companion/extension/lib/utils.ts b/companion/extension/lib/utils.ts
new file mode 100644
index 0000000000..783a2b0eee
--- /dev/null
+++ b/companion/extension/lib/utils.ts
@@ -0,0 +1,10 @@
+/**
+ * Escapes HTML special characters to prevent XSS attacks.
+ * Uses the browser's built-in text encoding via textContent.
+ */
+export function escapeHtml(text: string): string {
+ if (typeof text !== "string") return "";
+ const div = document.createElement("div");
+ div.textContent = text;
+ return div.innerHTML;
+}