🔒 harden vibe import trust boundary — strip markup from name/emoji (ship-check)
The vibe name + emoji arrive from user-pasted GSV1 codes and #vibe= URL fragments and are rendered via innerHTML in the vibes panel + the shared-vibe offer card. name was <-escaped but emoji was raw. sanitizeVibe now strips [<>&"'`] from both at the trust boundary, so nothing dangerous reaches any render path. Verified live: a crafted code with name='<img onerror=…>' + emoji='<svg onload=…>' imported via #vibe= → no <img>/<svg> in the DOM, no script fired, both rendered as inert text. (ship-check item 3: user strings → HTML must be escaped.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
93c5e20ccf
commit
fc1bb307bc
@ -3153,8 +3153,11 @@
|
||||
const vibeKnownDest = (k) => dests.has(k);
|
||||
function sanitizeVibe(raw) { // trust boundary: user-pasted / URL data
|
||||
if (!raw || typeof raw !== "object") return null;
|
||||
const name = (typeof raw.name === "string" && raw.name.trim()) ? raw.name.trim().slice(0, 48) : "shared vibe";
|
||||
const emoji = (typeof raw.emoji === "string" && raw.emoji) ? [...raw.emoji].slice(0, 2).join("") : "🎁";
|
||||
const noMarkup = (s) => String(s).replace(/[<>&"'`]/g, ""); // strip markup chars — these strings hit innerHTML
|
||||
const nm = (typeof raw.name === "string") ? noMarkup(raw.name).trim() : "";
|
||||
const name = nm ? nm.slice(0, 48) : "shared vibe";
|
||||
const em = (typeof raw.emoji === "string") ? noMarkup(raw.emoji) : "";
|
||||
const emoji = em ? [...em].slice(0, 2).join("") : "🎁";
|
||||
if (!Array.isArray(raw.routes)) return null;
|
||||
const routes = [];
|
||||
for (const r of raw.routes.slice(0, 32)) { // hard cap
|
||||
|
||||
Loading…
Reference in New Issue
Block a user