Skip to content
forked from bevacqua/insane

😾 Lean and configurable whitelist-oriented HTML sanitizer

License

Notifications You must be signed in to change notification settings

RTVision/insane

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

html-sane

Lean and configurable whitelist-oriented HTML sanitizer with native Sanitizer API support.

Note: This is a TypeScript rewrite of the original insane package by @bevacqua. The original package is no longer maintained and has known security vulnerabilities (CVE-2020-26303). This fork has been renamed to html-sane and published as a new package.

Features

  • Whitelist-based - Only allows tags, attributes, and classes you explicitly permit
  • URL sanitization - Validates URL schemes in href, src, and other URI attributes
  • Lightweight - ~4KB gzipped with zero runtime dependencies (except html-entities)
  • TypeScript - Written in TypeScript with full type definitions
  • Native API support - Automatically uses the browser's native Sanitizer API when available and compatible
  • Universal - Works in Node.js and browsers
  • Security hardened - Fixes CVE-2020-26303 (ReDoS vulnerability) and includes 280+ security tests

Installation

npm install html-sane
# or
pnpm add html-sane
# or
yarn add html-sane

Migrating from insane

If you're migrating from the original insane package:

npm uninstall insane
npm install html-sane

Then update your imports:

- import insane from 'insane'
+ import insane from 'html-sane'

The API is fully compatible - no other code changes required.

Security

This rewrite addresses the following security issues from the original package:

  • CVE-2020-26303: Regular Expression Denial of Service (ReDoS) - Fixed by rewriting the HTML parser to use a state machine approach instead of vulnerable regex patterns
  • Comprehensive security test suite covering:
    • XSS attack vectors (script injection, event handlers, javascript: URLs)
    • URL scheme validation (blocks javascript:, data:, vbscript:, etc.)
    • HTML entity encoding bypasses
    • Malformed HTML handling
    • Nested/recursive attack patterns
    • ReDoS prevention
    • mXSS (mutation XSS) vectors
    • DOM clobbering prevention
    • Prototype pollution prevention

Usage

import insane from 'html-sane'

// Basic usage with defaults
insane('<script>alert(1)</script><p>Hello</p>')
// => '<p>Hello</p>'

// Custom options
insane('<div class="foo bar">text</div>', {
  allowedTags: ['div'],
  allowedClasses: { div: ['foo'] }
})
// => '<div class="foo">text</div>'

API

insane(html, options?, strict?)

Sanitizes an HTML string.

  • html - The HTML string to sanitize
  • options - Optional sanitization options (merged with defaults)
  • strict - If true, options are used as-is without merging with defaults

Returns the sanitized HTML string.

Options

allowedTags

Array of allowed HTML tag names (lowercase).

insane('<div><script>bad</script></div>', {
  allowedTags: ['div']
})
// => '<div></div>'

allowedAttributes

Map of tag names to allowed attribute names. Use '*' for attributes allowed on all tags.

insane('<a href="/foo" onclick="bad()">link</a>', {
  allowedTags: ['a'],
  allowedAttributes: { a: ['href'] }
})
// => '<a href="/foo">link</a>'

allowedClasses

Map of tag names to allowed class names. Only applies when 'class' is NOT in allowedAttributes for that tag.

insane('<div class="safe danger">text</div>', {
  allowedTags: ['div'],
  allowedClasses: { div: ['safe'] }
})
// => '<div class="safe">text</div>'

allowedSchemes

Array of allowed URL schemes for URI attributes.

insane('<a href="javascript:alert(1)">link</a>', {
  allowedSchemes: ['http', 'https']
})
// => '<a>link</a>'

Default: ['http', 'https', 'mailto']

filter

Custom filter function to accept/reject tags. Return true to keep the tag, false to remove it.

insane('<span data-user="admin">secret</span><span>public</span>', {
  allowedTags: ['span'],
  filter: (token) => !token.attrs['data-user']
})
// => '<span>public</span>'

transformText

Transform text content before output.

insane('<p>hello world</p>', {
  transformText: (text) => text.toUpperCase()
})
// => '<p>HELLO WORLD</p>'

Default Options

{
  allowedTags: [
    'a', 'abbr', 'article', 'b', 'blockquote', 'br', 'caption', 'code',
    'del', 'details', 'div', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
    'hr', 'i', 'img', 'ins', 'kbd', 'li', 'main', 'mark', 'ol', 'p',
    'pre', 'section', 'span', 'strike', 'strong', 'sub', 'summary',
    'sup', 'table', 'tbody', 'td', 'th', 'thead', 'tr', 'u', 'ul'
  ],
  allowedAttributes: {
    '*': ['title', 'accesskey'],
    a: ['href', 'name', 'target', 'aria-label'],
    iframe: ['allowfullscreen', 'frameborder', 'src'],
    img: ['src', 'alt', 'title', 'aria-label']
  },
  allowedClasses: {},
  allowedSchemes: ['http', 'https', 'mailto'],
  filter: null,
  transformText: null
}

Native Sanitizer API

In supported browsers, html-sane will automatically use the native Sanitizer API when:

  1. The API is available in the browser
  2. The options don't use features unsupported by the native API (allowedClasses, filter, transformText, or custom allowedSchemes)

This provides better performance and security in modern browsers while maintaining full compatibility everywhere else.

TypeScript

Full TypeScript support with exported types:

import insane, { type InsaneOptions, type TokenInfo, defaults } from 'html-sane'

const options: InsaneOptions = {
  allowedTags: ['p', 'strong'],
  filter: (token: TokenInfo) => token.tag !== 'script'
}

console.log(defaults.allowedTags)

Credits

This package is a TypeScript rewrite of insane by Nicolas Bevacqua.

License

MIT

About

😾 Lean and configurable whitelist-oriented HTML sanitizer

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • TypeScript 100.0%