← 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
M public/condos.htmlM public/crcp.html
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,'&').replace(/</g,'<').replace(/"/g,'"');
+const esc=s=>String(s==null?'':s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
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,'&').replace(/</g,'<').replace(/"/g,'"');
+const esc=s=>(s==null?'':String(s)).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
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 →