Untrusted-Content-as-Markup Escaping
Encode untrusted text for the exact output context that receives it.
These examples and illustrative results are independently authored teaching materials, not measured model results.
Use case
An HTML report displays an external PR title containing script markup and a </script> terminator. Text nodes and embedded JSON scripts are different receiving contexts.
Mechanism
Identify text/attribute/URL/script sinks. Prefer textContent or template escaping for plain text; apply context-specific attribute encoding and URL policy. Serialize JSON with a library plus supported safe embedding for < and script termination, not HTML escaping alone. Render markup only in constrained containers. Test the final DOM.
Bad example
Concatenate title into h1 and JavaScript strings and claim one HTML escape secures every context.
Good example
Display the title with textContent, not innerHTML. Embed state with a supported safe-JSON helper handling script termination. Test </script>/quotes round-tripping as data without added execution and validate attribute/URL contexts separately.
Why the change matters
Receiving parsers give characters different meanings. Context encoding preserves external values as data rather than executable HTML/script syntax.
Observable expectation
Teaching titles display literal markup; no title-created script or executed sentinel appears. Embedded JSON retains the value and script boundaries. Normal appearance alone does not establish every sink’s safety.
Limits
Encoding does not replace authorization, target validation or all XSS defenses. Rich text needs its own sanitization contract. JSON.stringify alone is neither HTML-script safety nor shell escaping. Frozen report CSP is context-specific.
Sources and evidence
- anthropics/skills · Context-specific escaping, inert markup and confined local refs
File at this version8a1541c4a3ff