[object Object]

← back to Commercialrealestate

harden esc(): escape > as well as & < " (condos + crcp)

df8a26f904021202f6dffa97400e4b2f4f890e40 · 2026-07-31 11:21:19 -0700 · Steve

Cody-gate follow-up: close the full HTML-escape class in both esc() helpers
(vendor/scrape-controlled broker/firm names flow through innerHTML via line()).
Low practical risk (hrefs use encodeURIComponent) but free + fleet-hardening.
Cody's 404-rate concern was REFUTED empirically (40/40 sampled condo broker
names resolve; dropped as phantom).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit df8a26f904021202f6dffa97400e4b2f4f890e40
Author: Steve <steve@designerwallcoverings.com>
Date:   Fri Jul 31 11:21:19 2026 -0700

    harden esc(): escape > as well as & < " (condos + crcp)
    
    Cody-gate follow-up: close the full HTML-escape class in both esc() helpers
    (vendor/scrape-controlled broker/firm names flow through innerHTML via line()).
    Low practical risk (hrefs use encodeURIComponent) but free + fleet-hardening.
    Cody's 404-rate concern was REFUTED empirically (40/40 sampled condo broker
    names resolve; dropped as phantom).
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 public/condos.html | 2 +-
 public/crcp.html   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/public/condos.html b/public/condos.html
index 51eca50..7eab544 100644
--- a/public/condos.html
+++ b/public/condos.html
@@ -151,7 +151,7 @@
 <script>
 const $=s=>document.querySelector(s);
 const $$=s=>Array.from(document.querySelectorAll(s));
-const esc=s=>String(s==null?'':s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/"/g,'&quot;');
+const esc=s=>String(s==null?'':s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
 const PROXY='FHA/VA-approval-based proxy, NOT lender-verified Fannie/Freddie warrantability.';
 const NOW_YEAR=new Date().getFullYear();
 let DATA=[], MODE='db', VIEW=localStorage.getItem('condoView')||'grid', bannerDefault='';
diff --git a/public/crcp.html b/public/crcp.html
index 8f12088..d87cc97 100644
--- a/public/crcp.html
+++ b/public/crcp.html
@@ -313,7 +313,7 @@ function srt(arr,col,dir){ return arr.slice().sort((a,b)=>{ let x=a[col],y=b[col
 function markHdr(tbl,sort){ document.querySelectorAll('#'+tbl+' th.srt').forEach(th=>{ th.classList.remove('asc','desc'); if(th.dataset.col===sort.col) th.classList.add(sort.dir>0?'asc':'desc'); }); }
 // Web column shows the SITE NAME (domain), not a bare "site↗" — Steve 2026-07-13.
 const siteName=u=>{ try{ return new URL(/^https?:/.test(u)?u:'https://'+u).hostname.replace(/^www\./,''); }catch(e){ return u; } };
-const esc=s=>(s==null?'':String(s)).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/"/g,'&quot;');
+const esc=s=>(s==null?'':String(s)).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
 const webLink=u=>{ if(!u) return '<span class="miss">—</span>'; const h=/^https?:/.test(u)?u:'https://'+u; return `<a href="${esc(h)}" target="_blank" rel="noopener noreferrer" style="color:var(--gold)" title="${esc(h)}">${esc(siteName(u))}↗</a>`; };
 // On-demand email hunt (the "✉ find email" button). hunt[] survives the 3s poll re-renders;
 // a found email also lands in broker.email server-side, so the next poll carries it natively.

← 653c5c9 condos detail modal: broker/firm fields drill to crcp (TK-10  ·  back to Commercialrealestate  ·  crcp: make all stat tiles + enrichment bars drill to their f b8c63bc →