[object Object]

← back to Sample Followup Sweep

Require visible owned compliance content

297d26af095fcdfc7da7cc14a0cb0552d5a79185 · 2026-08-28 14:44:09 -0700 · Steve Abrams

Files touched

Diff

commit 297d26af095fcdfc7da7cc14a0cb0552d5a79185
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Aug 28 14:44:09 2026 -0700

    Require visible owned compliance content
---
 README.md                   |  4 ++++
 lib/pre-send-gate.js        | 44 ++++++++++++++++++++++++++++++++++----------
 test/pre-send-gate.test.js  | 21 +++++++++++++++++++++
 verification/e2e-proof.json |  8 ++++++--
 4 files changed, 65 insertions(+), 12 deletions(-)

diff --git a/README.md b/README.md
index 94b7de1..a8bc347 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,10 @@ blocks unless the sender resolves to `info@designerwallcoverings.com`, the body
 contains DW's physical postal address and a working opt-out link, and the subject
 is present without a misleading `Re:`/`Fwd:` prefix. A block performs no network
 request and returns `PRE_SEND_COMPLIANCE_BLOCKED` (HTTP 422 in the console API).
+Address text and opt-out anchors must be visibly rendered; comments and non-rendered
+elements (`script`, `style`, `template`, `noscript`, hidden blocks) never count.
+The current approved opt-out is the `info@designerwallcoverings.com` mailto link.
+HTTPS opt-outs fail closed until a canonical DW-owned endpoint is explicitly registered.
 
 ## The one FileMaker dependency (for hands-free phases 1 & 6)
 
diff --git a/lib/pre-send-gate.js b/lib/pre-send-gate.js
index 9dda896..8027178 100644
--- a/lib/pre-send-gate.js
+++ b/lib/pre-send-gate.js
@@ -3,24 +3,48 @@
 const REQUIRED_FROM = 'info@designerwallcoverings.com';
 const ADDRESS_PATTERN = /15442\s+Ventura\s+Blvd(?:\.|\s)*(?:#|Suite)?\s*102[\s\S]*Sherman\s+Oaks,?\s*CA\s+91403/i;
 const MISLEADING_SUBJECT_PATTERN = /\b(?:re|fw|fwd)\s*:/i;
+const NON_RENDERED_ELEMENTS = 'script|style|template|noscript|head|svg|canvas';
 
-function stripHtmlComments(value) {
-  return String(value || '').replace(/<!--[\s\S]*?-->/g, '');
+function decodeHtmlEntities(value) {
+  return String(value || '')
+    .replace(/&nbsp;|&#160;|&#xa0;/gi, ' ')
+    .replace(/&amp;/gi, '&')
+    .replace(/&lt;/gi, '<')
+    .replace(/&gt;/gi, '>')
+    .replace(/&quot;/gi, '"')
+    .replace(/&#39;|&apos;/gi, "'")
+    .replace(/&#(\d+);/g, (_, code) => String.fromCodePoint(Number(code)))
+    .replace(/&#x([0-9a-f]+);/gi, (_, code) => String.fromCodePoint(parseInt(code, 16)));
+}
+
+function sanitizeRenderedHtml(value) {
+  let html = String(value || '').replace(/<!--[\s\S]*?-->/g, '');
+  html = html.replace(new RegExp(`<(${NON_RENDERED_ELEMENTS})\\b[^>]*>[\\s\\S]*?<\\/\\1\\s*>`, 'gi'), '');
+  const hiddenBlock = /<([a-z][\w:-]*)\b(?=[^>]*(?:\bhidden(?:\s*=\s*(?:["'][^"']*["']|[^\s>]+))?|\baria-hidden\s*=\s*(["'])?true\2|\bstyle\s*=\s*(["'])[^"']*(?:display\s*:\s*none|visibility\s*:\s*hidden)[^"']*\3))[^>]*>[\s\S]*?<\/\1\s*>/gi;
+  let previous;
+  do { previous = html; html = html.replace(hiddenBlock, ''); } while (html !== previous);
+  return html;
+}
+
+function visibleTextFromHtml(body) {
+  const rendered = sanitizeRenderedHtml(body)
+    .replace(/<(?:br|\/p|\/div|\/li|\/tr|\/h[1-6])\b[^>]*>/gi, ' ')
+    .replace(/<[^>]*>/g, ' ');
+  return decodeHtmlEntities(rendered).replace(/\s+/g, ' ').trim();
 }
 
 function hasWorkingOptOutLink(body) {
-  const visible = stripHtmlComments(body);
-  const hrefs = [...visible.matchAll(/<a\b[^>]*\bhref\s*=\s*(["'])(.*?)\1[^>]*>/gi)].map((match) => match[2].trim());
+  const rendered = sanitizeRenderedHtml(body);
+  const hrefs = [...rendered.matchAll(/<a\b[^>]*\bhref\s*=\s*(["'])(.*?)\1[^>]*>/gi)].map((match) => decodeHtmlEntities(match[2].trim()));
   return hrefs.some((href) => {
     try {
       const url = new URL(href);
       const optOutSignal = `${url.pathname} ${url.search} ${url.hash}`;
       if (!/(?:unsubscribe|opt[-_ ]?out)/i.test(optOutSignal)) return false;
       if (url.protocol === 'mailto:') return url.pathname.toLowerCase() === REQUIRED_FROM;
-      if (url.protocol !== 'https:') return false;
-      const host = url.hostname.toLowerCase();
-      if (!host.includes('.') || host === 'invalid.example' || host.endsWith('.invalid') || host.endsWith('.example') || host.endsWith('.test') || host === 'localhost') return false;
-      return true;
+      // No canonical DW-hosted unsubscribe endpoint is registered yet. Fail closed
+      // instead of treating an attacker-controlled HTTPS URL as a working opt-out.
+      return false;
     } catch {
       return false;
     }
@@ -32,7 +56,7 @@ function assertPreSendCompliance({ from, subject, body }) {
   if (String(from || '').trim().toLowerCase() !== REQUIRED_FROM) errors.push(`From must be ${REQUIRED_FROM}`);
   if (!String(subject || '').trim()) errors.push('Subject is required');
   if (MISLEADING_SUBJECT_PATTERN.test(String(subject || ''))) errors.push('Subject must not imply a reply or forward');
-  if (!ADDRESS_PATTERN.test(String(body || ''))) errors.push('Body must include the DW physical postal address');
+  if (!ADDRESS_PATTERN.test(visibleTextFromHtml(body))) errors.push('Body must include the DW physical postal address in visible content');
   if (!hasWorkingOptOutLink(body)) errors.push('Body must include a working unsubscribe or opt-out link');
   if (errors.length) {
     const error = new Error(`PRE-SEND COMPLIANCE GATE BLOCKED: ${errors.join('; ')}`);
@@ -43,4 +67,4 @@ function assertPreSendCompliance({ from, subject, body }) {
   return true;
 }
 
-module.exports = { assertPreSendCompliance, hasWorkingOptOutLink, REQUIRED_FROM };
+module.exports = { assertPreSendCompliance, hasWorkingOptOutLink, sanitizeRenderedHtml, visibleTextFromHtml, REQUIRED_FROM };
diff --git a/test/pre-send-gate.test.js b/test/pre-send-gate.test.js
index 4921f82..16922bb 100644
--- a/test/pre-send-gate.test.js
+++ b/test/pre-send-gate.test.js
@@ -36,4 +36,25 @@ for (const fakeLink of [
   assert.throws(() => assertPreSendCompliance({ from: REQUIRED_FROM, subject: compliant.subject, body: bodyWithoutLink + fakeLink }), { code: 'PRE_SEND_COMPLIANCE_BLOCKED' });
 }
 
+const bodyWithoutAddress = compliant.html
+  .replace(/Designer Wallcoverings · 15442 Ventura Blvd\. #102 · Sherman Oaks, CA 91403<br>/, '')
+  .replace(/Designer Wallcoverings<br>\s*15442 Ventura Blvd\. #102<br>\s*Sherman Oaks, CA 91403<br>/, '');
+for (const hiddenAddress of [
+  '<div hidden>15442 Ventura Blvd. #102, Sherman Oaks, CA 91403</div>',
+  '<div style="display:none">15442 Ventura Blvd. #102, Sherman Oaks, CA 91403</div>',
+  '<script>const address = "15442 Ventura Blvd. #102, Sherman Oaks, CA 91403"</script>',
+  '<template>15442 Ventura Blvd. #102, Sherman Oaks, CA 91403</template>',
+]) {
+  assert.throws(() => assertPreSendCompliance({ from: REQUIRED_FROM, subject: compliant.subject, body: bodyWithoutAddress + hiddenAddress }), { code: 'PRE_SEND_COMPLIANCE_BLOCKED' });
+}
+
+const scriptOnly = bodyWithoutLink + '<script>document.write(`<a href="mailto:info@designerwallcoverings.com?subject=Unsubscribe">unsubscribe</a>`)</script>';
+assert.throws(() => assertPreSendCompliance({ from: REQUIRED_FROM, subject: compliant.subject, body: scriptOnly }), { code: 'PRE_SEND_COMPLIANCE_BLOCKED' });
+
+const attackerOwned = bodyWithoutLink + '<a href="https://attacker.example.org/unsubscribe">unsubscribe</a>';
+assert.throws(() => assertPreSendCompliance({ from: REQUIRED_FROM, subject: compliant.subject, body: attackerOwned }), { code: 'PRE_SEND_COMPLIANCE_BLOCKED' });
+
+const reconciledFooter = `<div><p>Ship to:<br>Designer Wallcoverings<br>15442 Ventura Blvd. #102<br>Sherman Oaks, CA 91403<br>1-888-373-4564</p><p>Thank you!<br>Showroom Manager</p><p>Designer Wallcoverings · 15442 Ventura Blvd. #102 · Sherman Oaks, CA 91403<br>To stop receiving sample follow-up emails, <a href="mailto:info@designerwallcoverings.com?subject=Unsubscribe%20from%20sample%20follow-ups">unsubscribe here</a>.</p></div>`;
+assert.equal(assertPreSendCompliance({ from: REQUIRED_FROM, subject: 'Sample Follow-Up — Outstanding Memos — Designer Wallcoverings', body: reconciledFooter }), true);
+
 console.log('pre-send compliance gate: PASS');
diff --git a/verification/e2e-proof.json b/verification/e2e-proof.json
index b01e050..242050a 100644
--- a/verification/e2e-proof.json
+++ b/verification/e2e-proof.json
@@ -1,5 +1,5 @@
 {
-  "intent": "Centralize fail-closed compliance enforcement for all sendable George transports and Gmail draft artifacts",
+  "intent": "Centralize fail-closed compliance enforcement and require visibly rendered, DW-owned compliance content",
   "risk_tier": "R3",
   "environment": "local repository only; injected HTTP spy; no George/Gmail/FileMaker/production network calls",
   "ticket": "TK-10940-centralize-sample-follow-up-pre-send-com",
@@ -13,7 +13,7 @@
     {
       "boundary": "compliance parser",
       "verdict": "PASS",
-      "evidence": "test/pre-send-gate.test.js rejects HTML comments, plain-text mailto tokens, and https://invalid.example/unsubscribe while accepting lib/compose.js output"
+      "evidence": "test/pre-send-gate.test.js rejects comments, script/template/hidden address text, script-only links, plain-text mailto tokens, invalid.example, and attacker.example.org while accepting lib/compose.js and reconciled-footer output"
     },
     {
       "boundary": "George /api/send and /api/drafts",
@@ -44,6 +44,10 @@
     "opt-out anchor hidden in HTML comment",
     "plain-text mailto token",
     "reserved invalid.example unsubscribe URL",
+    "attacker-owned HTTPS unsubscribe URL",
+    "postal address hidden with hidden/display:none",
+    "postal address present only in script/template",
+    "opt-out link present only in script",
     "blocked transport makes zero requests"
   ],
   "cleanup": "No external or persistent test state created; repository verification artifact intentionally retained",

← 984ab8e Centralize sample follow-up compliance enforcement  ·  back to Sample Followup Sweep  ·  Record cycle 3 compliance proof identity a3c2bbb →