| name | html-xss-filtering |
| description | Custom-allowlist XSS filtering with fine-grained tag and attribute control. leizongmin/js-xss whitelist configuration, attribute value sanitization, CSS sanitization, and protocol filtering. Sources: leizongmin/js-xss. |
/html-xss-filtering
When to Use
- Sanitize user-generated HTML with custom allowed tag/attribute rules
- Strip XSS from web-scraped content before indexing in agent memory
- Preserve safe formatting (bold, lists) while stripping dangerous attributes
- Server-side filtering when DOMPurify (browser-oriented) is not preferred
Do NOT use for
- Scenarios requiring DOM parsing (use [[dompurify-xss-prevention]] with JSDOM)
- Plain text — stripping is 1 line with
replace(/<[^>]*>/g, '')
Custom allowlist config
import xss from 'xss'
const agentXss = new xss.FilterXSS({
whiteList: {
a: ['href', 'title', 'target'],
b: [],
i: [],
em: [],
strong: [],
p: ['class'],
br: [],
ul: [],
ol: [],
li: [],
code: ['class'],
pre: ['class'],
h1: [], h2: [], h3: [],
},
onTagAttr(tag, name, value) {
if (name === 'href') {
if (/^javascript:/i.test(value) || /^data:/i.test(value)) {
return ''
}
}
return undefined
},
escapeHtml: xss.escapeHtml,
})
const clean = agentXss.process('<script>alert(1)</script><b>Safe</b>')
Strip all HTML (plain text extraction)
const textOnly = new xss.FilterXSS({
whiteList: {},
stripIgnoreTag: true,
stripIgnoreTagBody: ['script', 'style'],
})
const text = textOnly.process('<div>Hello <b>World</b><script>bad()</script></div>')
CSS attribute sanitization
import xss from 'xss'
const withCss = new xss.FilterXSS({
whiteList: { span: ['style'] },
css: {
whiteList: {
color: true,
'font-size': /^\d+(px|em|rem|%)$/,
},
},
})
Anti-Fake-Pass Checklist
❌ Empty whiteList {} with no stripIgnoreTag → unknown tags preserved, XSS possible
❌ href not validated for protocol → javascript: and data: URIs pass through
❌ css option not set when style attribute allowed → CSS expression() injection
❌ onTagAttr returning null vs undefined → null strips attribute, undefined uses default
❌ Nested quotes in attribute values → some parsers misinterpret, allowing escape
❌ No escaping of tag bodies after strip → raw content may contain partial HTML