mrkeyoor.com_
Sat 08 Aug 21:00 UTC
npmSecurityupdated 08 Aug 2026

xss

xss, also known as js-xss, sanitizes an untrusted HTML string with a tag-and-attribute allowlist. Unknown tags are escaped by default, disallowed attributes are removed, allowed href and src values pass through a protocol check, and allowed style attributes can be filtered by the bundled cssfilter dependency. It runs in Node, ships a prebuilt browser file and CLI, and supports custom hooks when the default policy does not match an application's HTML subset.

Verdict

xss is compact and configurable enough for a deliberately small HTML policy, but its defaults are not a substitute for defining that policy. New browser-heavy projects should compare DOMPurify first, and no project should copy permissive custom hooks without security tests.

API stability4/5The core filterXSS function, FilterXSS class, allowlist options, and hooks have remained in the 1.x line for years. Recent 1.0.15 changes only added kbd to the defaults and single-quoted attribute output. The deduction is for release drift: the repository README and main branch now advertise filterXSSWithResult, but that export is absent from the published 1.0.15 package and its TypeScript declarations.
Docs4/5The README documents the default model, Node and browser usage, CLI, allowlists, every major hook, CSS behavior, tag-body stripping, comments, data attributes, custom tags, image parsing, and plain-text extraction. Security-sensitive warnings exist for disabling CSS filtering and the hosted browser file. The main weakness is versioning: documentation follows the repository branch, so at least one prominently shown API is newer than the npm release.
Maintenance3/5GitHub shows a push on 2026-05-06 and 69 open issues and pull requests, so development has continued. The latest published version is still 1.0.15 from 2024-03-03, and the changelog shows earlier security-relevant parser and denial-of-service fixes arriving at irregular intervals. For an HTML sanitizer, the gap between repository work and a consumable release matters more than it would for an ordinary formatting utility.
Ecosystem4/5The package recorded 5,417,372 downloads in the last complete week and the repository has 5,316 stars. It includes Node, browser, Web Worker, CLI, and TypeScript entry points, and the README names production users such as nodeclub, cnpmjs.org, and CoCalc. Its surrounding ecosystem is smaller than DOMPurify's, and its cssfilter dependency is a project-specific policy layer rather than a broadly shared sanitizer standard.

Use it if

  • You deliberately accept a limited HTML subset from users and need the same string-based sanitizer in Node and a browser bundle
  • Your policy is naturally expressed as allowed tags and attributes, with optional hooks for custom elements or data attributes
  • You want unsupported markup escaped for display rather than silently discarded
  • You need a reusable FilterXSS instance or a small CLI for processing stored HTML files
Skip it if

Setup reality

npm install xss gives CommonJS code, bundled TypeScript declarations, a command-line binary, commander, and cssfilter. There are no peer dependencies or native builds, but installation is not the important security decision. Start by writing the exact HTML policy your product needs. Passing whiteList or its allowList alias replaces the default policy rather than extending it; clone xss.getDefaultWhiteList() first if you mean to add a tag. Unknown tags are escaped, not removed, unless stripIgnoreTag is true. Even then their text remains, so stripIgnoreTagBody must name script or other elements whose contents should also disappear. Allowed href and src values use the library's own protocol policy, which accepts more than http and https, including data:image/ and FTP. If those are outside your threat model, provide a tested safeAttrValue wrapper or remove the attributes. The default allowlist does not permit style, but adding style activates cssfilter unless css is false. Hook return values are raw output fragments: onIgnoreTag and onIgnoreTagAttr examples use escapeAttrValue because returning unescaped input can recreate the exact injection path the sanitizer was meant to close. Sanitize at the final HTML rendering boundary, keep the original separately if edits are needed, and avoid repeatedly sanitizing already transformed markup. The README's browser example uses a RawGit URL and explicitly says not to use it in production; bundle the package yourself. Finally, pin and test the shipped npm version against your own hostile corpus because the repository README currently describes an unreleased export not present in 1.0.15.

Patterns

Sanitize with the default allowlistsanitize-default-html

const xss = require('xss');

const clean = xss('<p>Hello <strong>friend</strong></p><script>alert(1)</script>');

Unknown tags are escaped by default, so the script text remains visible inside escaped markup. Use stripIgnoreTagBody when the contents must disappear too.

Allow only a small formatting subsetdefine-minimal-allowlist

const clean = xss(untrustedHtml, {
  allowList: {
    p: [],
    strong: [],
    em: [],
    a: ['href', 'title'],
  },
});

allowList and whiteList are aliases. Supplying either replaces all defaults, which is useful for a deny-by-default policy.

Extend the shipped default policyextend-default-allowlist

const allowList = xss.getDefaultWhiteList();
allowList.mark = [...(allowList.mark || []), 'class'];

const clean = xss(untrustedHtml, { allowList });

getDefaultWhiteList returns a fresh object. Mutating the exported xss.whiteList directly can change behavior elsewhere in the same process.

Reuse one configured sanitizerreuse-filter-instance

const filter = new xss.FilterXSS({
  allowList: { p: [], code: ['class'], pre: [] },
  stripIgnoreTag: true,
});

const first = filter.process(commentA);
const second = filter.process(commentB);

FilterXSS avoids rebuilding options for repeated calls. stripIgnoreTag removes disallowed tags but keeps their text content.

Remove dangerous elements and their contentsremove-script-bodies

const clean = xss(untrustedHtml, {
  allowList: { p: [], strong: [], em: [] },
  stripIgnoreTag: true,
  stripIgnoreTagBody: ['script', 'style', 'iframe'],
});

stripIgnoreTagBody applies only to tags that are not allowed. List the bodies explicitly; stripIgnoreTag alone leaves their inner text.

Keep text while dropping markupextract-plain-text

const plain = xss(untrustedHtml, {
  allowList: {},
  stripIgnoreTag: true,
  stripIgnoreTagBody: ['script', 'style'],
});

This is HTML-to-text-like filtering, not full text extraction. Entities and whitespace follow xss's parser behavior rather than a rendered DOM's textContent.

Allow data attributes with escaped valuesallow-data-attributes

const clean = xss(untrustedHtml, {
  onIgnoreTagAttr(tag, name, value) {
    if (tag === 'div' && name.startsWith('data-')) {
      return `${name}="${xss.escapeAttrValue(value)}"`;
    }
  },
});

A hook's returned string is inserted into output. Escaping the value is essential, and applications should also constrain acceptable attribute names.

Apply a stricter link URL policyrestrict-link-protocols

const strict = new xss.FilterXSS({
  allowList: { a: ['href', 'title'] },
  safeAttrValue(tag, name, value, cssFilter) {
    if (tag === 'a' && name === 'href') {
      const normalized = xss.friendlyAttrValue(value).trim();
      if (!/^https:\/\//i.test(normalized)) return '';
    }
    return xss.safeAttrValue(tag, name, value, cssFilter);
  },
});

The default URL policy also accepts http, mailto, tel, FTP, data images, relative paths, and fragments. This wrapper narrows links to HTTPS.

Allow a small CSS property setfilter-inline-styles

const filter = new xss.FilterXSS({
  allowList: { span: ['style'] },
  css: {
    whiteList: {
      color: true,
      'font-weight': /^(normal|bold|[1-9]00)$/i,
    },
  },
});

Style is not in the default HTML allowlist. Do not set css: false for untrusted style values unless another trusted CSS sanitizer runs first.

Record rejected tag namesobserve-disallowed-tags

const rejected = new Set();
const clean = xss(untrustedHtml, {
  onIgnoreTag(tag) {
    rejected.add(tag);
    // Return undefined to keep the default escaped output.
  },
});
console.log([...rejected]);

Returning undefined preserves default handling. Returning the original html argument from this hook would reinsert the disallowed tag unsanitized.

Emit single-quoted attribute valuesuse-single-quoted-attributes

const clean = xss('<a href="https://example.com">link</a>', {
  singleQuotedAttributeValue: true,
});

This changes output syntax, not the allowlist or URL policy. It was added in 1.0.15.

Process an HTML file from the command linesanitize-file-cli

npx xss -i untrusted.html -o sanitized.html

The CLI uses the package defaults. For an application-specific allowlist and automated security tests, call the JavaScript API instead.

Alternatives

PackageRegistryPick it when
dompurifynpmUse it for DOM-based sanitization in browsers or on a server with a carefully maintained DOM implementation
sanitize-htmlnpmUse it for a server-oriented HTML parser with detailed tag, attribute, transform, and URL-scheme policies
rehype-sanitizenpmUse it when untrusted content already flows through the unified or rehype HTML syntax-tree pipeline