Apply a consistent security posture to every workflow/prompt-controlled value and to any derived content that will be rendered or linked:
1) Validate untrusted paths before cleanup/normalization
.., starts with / or a drive letter, etc.2) Normalize/whitelist paths before template substitution
3) Sanitize/escape anything injected into HTML (especially attributes)
http/https only).4) Redact sensitive identifiers from generated reports/logs
Minimal example (HTML + URL allowlist + escaping):
function sanitizeUrlForHtml(url) {
const u = String(url).trim();
if (!/^https?:\/\//i.test(u)) return null;
return u;
}
function escapeHtmlAttr(s) {
return String(s)
.replaceAll('&','&')
.replaceAll('"','"')
.replaceAll("'",''')
.replaceAll('<','<')
.replaceAll('>','>');
}
const safeUrl = sanitizeUrlForHtml(sourceUrl);
const label = escapeHtmlAttr(sourceLabel);
if (safeUrl) {
html += `<a href="${escapeHtmlAttr(safeUrl)}">[${label}]</a>`;
} else {
html += `${label}`;
}
Rule of thumb: if a value comes from prompts, user/community text, filesystem paths, or external sources, assume it can be adversarial until you (a) validate/whitelist it for the target context, (b) normalize it before templating, and (c) escape it for the final rendering context.