Skip to content

Conversation

@tsv2013
Copy link
Member

@tsv2013 tsv2013 commented Aug 8, 2025

No description provided.

Comment on lines +53 to +56
header.innerHTML = `
<div class="sa-panel-layout__item-title">${title}</div>
<div class="sa-panel-layout__item-coords">${panel.x},${panel.y} | ${panel.width}×${panel.height}</div>
`;

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium

DOM text
is reinterpreted as HTML without escaping meta-characters.

Copilot Autofix

AI about 1 month ago

How to fix:
The core issue is the unescaped insertion of possibly-untrusted text into an HTML context using .innerHTML. The safest, most robust fix is to escape title for HTML meta-characters (<, >, &, ", etc.) before embedding it into the string. The best way to implement this is to create a utility function to escape HTML, and use it on title in the template string.

Detailed steps:

  • Implement an escapeHtml function in the file (preferably at module-scope if not available elsewhere) that converts "&", "<", ">", '"', and ' to their corresponding HTML entities.
  • Use escapeHtml(title) (instead of title) in the template literal on line 54, ensuring that any unexpected input is displayed as text, not HTML.
  • No external dependencies are required for this, and the change should be limited to the scope of the existing method in the file shown.

Suggested changeset 1
src/panel-layout-engine.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/panel-layout-engine.ts b/src/panel-layout-engine.ts
--- a/src/panel-layout-engine.ts
+++ b/src/panel-layout-engine.ts
@@ -17,6 +17,19 @@
   resizeHandler?: (e: MouseEvent) => void; // Mouse down handler for resizing
 }
 
+/**
+ * Escape a string for insertion into HTML context.
+ * Converts &, <, >, ", and ' to HTML entities.
+ */
+function escapeHtml(str: string): string {
+  return String(str)
+    .replace(/&/g, "&amp;")
+    .replace(/</g, "&lt;")
+    .replace(/>/g, "&gt;")
+    .replace(/"/g, "&quot;")
+    .replace(/'/g, "&#39;");
+}
+
 export class PanelLayoutEngine extends LayoutEngine {
   public static GRID_SIZE = 25;
   public static DEFAULT_COL_COUNT = 2;
@@ -51,7 +64,7 @@
       header.className = "sa-panel-layout__item-header";
       const title = item.dataset.title || (item.querySelector(".sa-question__title") as HTMLElement)?.innerText || "Panel";
       header.innerHTML = `
-              <div class="sa-panel-layout__item-title">${title}</div>
+              <div class="sa-panel-layout__item-title">${escapeHtml(title)}</div>
               <div class="sa-panel-layout__item-coords">${panel.x},${panel.y} | ${panel.width}×${panel.height}</div>
           `;
       item.prepend(header);
EOF
@@ -17,6 +17,19 @@
resizeHandler?: (e: MouseEvent) => void; // Mouse down handler for resizing
}

/**
* Escape a string for insertion into HTML context.
* Converts &, <, >, ", and ' to HTML entities.
*/
function escapeHtml(str: string): string {
return String(str)
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;");
}

export class PanelLayoutEngine extends LayoutEngine {
public static GRID_SIZE = 25;
public static DEFAULT_COL_COUNT = 2;
@@ -51,7 +64,7 @@
header.className = "sa-panel-layout__item-header";
const title = item.dataset.title || (item.querySelector(".sa-question__title") as HTMLElement)?.innerText || "Panel";
header.innerHTML = `
<div class="sa-panel-layout__item-title">${title}</div>
<div class="sa-panel-layout__item-title">${escapeHtml(title)}</div>
<div class="sa-panel-layout__item-coords">${panel.x},${panel.y} | ${panel.width}×${panel.height}</div>
`;
item.prepend(header);
Copilot is powered by AI and may make mistakes. Always verify output.
@tsv2013 tsv2013 changed the title Started panel layout manager Panel layout manager Aug 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants