[object Object]

← back to Dw Settlement Audit

report.js: escape all Shopify-sourced fields in HTML output + add rel=noopener

9ff2b923eb25bdd8025ecf2c091ad9236bcc6948 · 2026-05-18 20:26:55 -0700 · SteveStudio2

Files touched

Diff

commit 9ff2b923eb25bdd8025ecf2c091ad9236bcc6948
Author: SteveStudio2 <steve@designerwallcoverings.com>
Date:   Mon May 18 20:26:55 2026 -0700

    report.js: escape all Shopify-sourced fields in HTML output + add rel=noopener
---
 report.js | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/report.js b/report.js
index 77ef579..9b98070 100644
--- a/report.js
+++ b/report.js
@@ -30,6 +30,9 @@ const errors = by('ERROR');
 
 const adminUrl = id => `${SHOP_ADMIN}/products/${id}`;
 const els = r => (r.partBElements && r.partBElements.length) ? r.partBElements.join(', ') : '—';
+const esc = s => String(s == null ? '' : s)
+  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
+  .replace(/"/g, '&quot;');
 
 // ---- markdown ----
 let md = `# DW Settlement Audit — Verdict Report\n\n`;
@@ -67,14 +70,14 @@ fs.writeFileSync('report.md', md);
 function card(r) {
   const c = r.verdict === 'PROHIBITED' ? '#b3261e' : r.verdict === 'BORDERLINE' ? '#b58a00' : '#888';
   return `<div class="card" style="border-left:5px solid ${c}">
-    ${r.imageUrl ? `<img src="${r.imageUrl}" loading="lazy">` : '<div class="noimg">no image</div>'}
+    ${r.imageUrl ? `<img src="${esc(r.imageUrl)}" loading="lazy">` : '<div class="noimg">no image</div>'}
     <div class="meta">
-      <span class="badge" style="background:${c}">${r.verdict}</span>
-      <h3>${(r.title || r.handle).replace(/</g, '&lt;')}</h3>
-      <p class="sub">ID ${r.id} · ${r.status}${r.published ? ' · published' : ''} · keyword: ${r.match}</p>
-      <p class="gate">Part A: <b>${r.partA}</b> (a1 ${r.a1} / a2 ${r.a2} / a3 ${r.a3}) · Part B: <b>${r.partB}</b> · ${els(r)}</p>
-      <p class="reason">${(r.reason || '').replace(/</g, '&lt;')}</p>
-      <a href="${adminUrl(r.id)}" target="_blank">Open in Shopify admin →</a>
+      <span class="badge" style="background:${c}">${esc(r.verdict)}</span>
+      <h3>${esc(r.title || r.handle)}</h3>
+      <p class="sub">ID ${esc(r.id)} · ${esc(r.status)}${r.published ? ' · published' : ''} · keyword: ${esc(r.match)}</p>
+      <p class="gate">Part A: <b>${r.partA}</b> (a1 ${r.a1} / a2 ${r.a2} / a3 ${r.a3}) · Part B: <b>${r.partB}</b> · ${esc(els(r))}</p>
+      <p class="reason">${esc(r.reason)}</p>
+      <a href="${esc(adminUrl(r.id))}" target="_blank" rel="noopener noreferrer">Open in Shopify admin →</a>
     </div></div>`;
 }
 const flagged = [...prohibited, ...borderline];

← b6b04bf gitignore: add dist/ build/ .next/  ·  back to Dw Settlement Audit  ·  settlement audit: gate faithfulness fix — verbatim binding v c88735e →