@bernierllc/html-sanitizer
v1.0.7
Published
XSS prevention and HTML sanitization for user-generated content
Readme
@bernierllc/html-sanitizer
XSS Prevention and HTML Sanitization for User-Generated Content
A security-critical package that provides robust HTML sanitization to prevent XSS (Cross-Site Scripting) attacks in user-generated content. Built on battle-tested DOMPurify with configurable security profiles.
Installation
npm install @bernierllc/html-sanitizerQuick Start
import { HtmlSanitizer, sanitizeHtml, SanitizationProfile } from '@bernierllc/html-sanitizer';
// Simple sanitization with defaults (MODERATE profile)
const clean = sanitizeHtml('<p>Safe content</p><script>alert("XSS")</script>');
// Result: '<p>Safe content</p>' (script removed)
// Get detailed sanitization report
const sanitizer = new HtmlSanitizer();
const result = sanitizer.sanitize(userHtml);
console.log(result.html); // Clean HTML
console.log(result.modified); // true if content was changed
console.log(result.removedTags); // ['script', 'object']
console.log(result.xssPatterns); // ['script tag', 'event handler']
console.log(result.warnings); // Security warningsFeatures
- XSS Attack Prevention: Removes script tags, event handlers, dangerous protocols
- Configurable Profiles: STRICT, MODERATE, RELAXED security levels
- Custom Rules: Define your own allowed tags, attributes, and protocols
- Security Reporting: Detailed reports of removed content and detected patterns
- Performance Optimized: Built on DOMPurify, the industry standard
- Zero-Config: Works out of the box with sensible defaults
Security Profiles
STRICT Profile
Only basic text formatting - ideal for comments or simple user input:
import { sanitizeWithProfile, SanitizationProfile } from '@bernierllc/html-sanitizer';
const clean = sanitizeWithProfile(userHtml, SanitizationProfile.STRICT);Allowed:
- Basic formatting:
<p>,<br>,<strong>,<em>,<b>,<i>,<u> - Lists:
<ul>,<ol>,<li>
Blocked:
- Links, images, tables, media, everything else
MODERATE Profile (Default)
Standard blog content formatting - default for most use cases:
const sanitizer = new HtmlSanitizer(); // Uses MODERATE by defaultAllowed:
- All STRICT tags
- Headings:
<h1>through<h6> - Links:
<a href="..." title="..."> - Images:
<img src="..." alt="..."> - Code:
<code>,<pre>,<blockquote>
Protocols: http, https, mailto
RELAXED Profile
Rich content for trusted users - includes tables and embedded media:
const clean = sanitizeWithProfile(userHtml, SanitizationProfile.RELAXED);Allowed:
- All MODERATE tags
- Tables:
<table>,<thead>,<tbody>,<tr>,<th>,<td> - Media:
<iframe>,<video>,<audio>
Custom Configuration
Define your own security rules:
import { HtmlSanitizer } from '@bernierllc/html-sanitizer';
const sanitizer = new HtmlSanitizer({
allowedTags: ['p', 'a', 'strong', 'em'],
allowedAttributes: {
'a': ['href', 'title']
},
allowedProtocols: ['https'], // Only HTTPS links
allowStyles: false,
allowDataUris: false
});
const result = sanitizer.sanitize(userHtml);API Reference
HtmlSanitizer
Main class for HTML sanitization.
Constructor
new HtmlSanitizer(config?: SanitizerConfig)Config Options:
allowedTags?: string[]- Whitelist of allowed HTML tagsallowedAttributes?: Record<string, string[]>- Allowed attributes per tagallowedProtocols?: string[]- Allowed URL protocolsallowStyles?: boolean- Allow inline styles (default: false)allowDataUris?: boolean- Allow data: URIs (default: false)mode?: 'strict' | 'moderate' | 'relaxed'- Use predefined profile
Methods
sanitize(html: string): SanitizationResult
Sanitize HTML and get detailed report:
const result = sanitizer.sanitize(html);
// SanitizationResult:
{
html: string; // Sanitized HTML
modified: boolean; // Whether content was changed
removedTags: string[]; // Tags that were removed
removedAttributes: Array<{ // Attributes that were removed
tag: string;
attribute: string;
}>;
xssPatterns: string[]; // XSS patterns detected
warnings: string[]; // Security warnings
}sanitizeWithProfile(html: string, profile: SanitizationProfile): SanitizationResult
Sanitize using a specific profile:
const result = sanitizer.sanitizeWithProfile(html, SanitizationProfile.STRICT);validate(html: string): ValidationResult
Check if HTML is safe without modifying:
const result = sanitizer.validate(html);
// ValidationResult:
{
safe: boolean; // Whether HTML is safe
issues: string[]; // List of security issues
}Convenience Functions
sanitizeHtml(html: string, config?: SanitizerConfig): string
Quick sanitization, returns clean HTML string:
import { sanitizeHtml } from '@bernierllc/html-sanitizer';
const clean = sanitizeHtml(userInput);sanitizeWithProfile(html: string, profile: SanitizationProfile): string
Sanitize with a profile, returns clean HTML string:
import { sanitizeWithProfile, SanitizationProfile } from '@bernierllc/html-sanitizer';
const clean = sanitizeWithProfile(userInput, SanitizationProfile.STRICT);validateHtml(html: string): { safe: boolean; issues: string[] }
Validate HTML safety:
import { validateHtml } from '@bernierllc/html-sanitizer';
const result = validateHtml(userInput);
if (!result.safe) {
console.error('Unsafe HTML:', result.issues);
}XSS Attack Prevention
This package protects against all common XSS attack vectors:
Script Tags
const html = '<p>Hello</p><script>alert("XSS")</script>';
const result = sanitizer.sanitize(html);
// result.html: '<p>Hello</p>'
// result.removedTags: ['script']
// result.xssPatterns: ['script tag']
// result.warnings: ['CRITICAL: Dangerous executable content removed']Event Handlers
const html = '<img src="x" onerror="alert(1)">';
const result = sanitizer.sanitize(html);
// onerror attribute removed
// result.xssPatterns: ['event handler']JavaScript Protocol
const html = '<a href="javascript:alert(1)">Click</a>';
const result = sanitizer.sanitize(html);
// javascript: protocol removed
// result.xssPatterns: ['javascript: protocol']Data URIs
const html = '<img src="data:text/html,<script>alert(1)</script>">';
const result = sanitizer.sanitize(html);
// Detected and blocked
// result.xssPatterns: ['data: URI']Embedded Objects
const html = '<object data="malicious.swf"></object>';
const result = sanitizer.sanitize(html);
// <object> and <embed> tags always removed
// result.removedTags: ['object']Security Best Practices
Always Sanitize User Input
// ✅ CORRECT
app.post('/comment', (req, res) => {
const sanitized = sanitizeHtml(req.body.comment);
await saveComment(sanitized);
});
// ❌ WRONG - Never trust user input
app.post('/comment', (req, res) => {
await saveComment(req.body.comment); // Dangerous!
});Choose the Right Profile
// Comments: Use STRICT
const comment = sanitizeWithProfile(userComment, SanitizationProfile.STRICT);
// Blog posts: Use MODERATE (default)
const blogPost = sanitizeHtml(userBlogPost);
// Admin content: Use RELAXED (only for trusted users)
if (user.isAdmin) {
const adminContent = sanitizeWithProfile(userContent, SanitizationProfile.RELAXED);
}Monitor Security Events
const result = sanitizer.sanitize(userHtml);
if (result.xssPatterns.length > 0) {
// Log security event
logger.warn('XSS attempt detected', {
userId: user.id,
patterns: result.xssPatterns,
removedTags: result.removedTags
});
}Use Validation Before Saving
const validation = validateHtml(userInput);
if (!validation.safe) {
return res.status(400).json({
error: 'Content contains unsafe HTML',
issues: validation.issues
});
}Performance
- Typical blog post (5KB): <10ms
- Large content (500KB): <100ms
- Memory usage: <50MB for large content
Built on DOMPurify, which is highly optimized and used by millions of websites.
Integration Status
Logger Integration
Status: Optional (recommended for security monitoring)
Justification: While this package can function without logging, it's highly recommended to integrate @bernierllc/logger for security event monitoring. The sanitizer can detect and remove XSS patterns, and logging these events helps with security auditing and threat detection. However, the package is designed to work without logging for environments where logging isn't available.
Pattern: Optional integration - package works without logger, but logger enhances security monitoring capabilities.
Example Integration:
import { Logger } from '@bernierllc/logger';
import { HtmlSanitizer } from '@bernierllc/html-sanitizer';
const logger = new Logger({ service: 'html-sanitizer' });
const sanitizer = new HtmlSanitizer();
const result = sanitizer.sanitize(userHtml);
if (result.xssPatterns.length > 0) {
logger.warn('XSS attempt detected', {
patterns: result.xssPatterns,
removedTags: result.removedTags
});
}NeverHub Integration
Status: Not applicable
Justification: This is a core utility package that performs HTML sanitization. It does not participate in service discovery, event publishing, or service mesh operations. While security events could theoretically be published to NeverHub, this package focuses solely on sanitization logic and delegates event handling to calling code.
Pattern: Core utility - no service mesh integration needed. Security events should be handled by the application layer that uses this sanitizer.
Docs-Suite Integration
Status: Ready
Format: TypeDoc-compatible JSDoc comments are included throughout the source code. All public APIs are documented with examples and type information.
Dependencies
- dompurify (^3.1.7) - HTML sanitization engine
- jsdom (^25.0.1) - DOM implementation for Node.js
Development
# Install dependencies
npm install
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Build package
npm run build
# Lint code
npm run lintTesting
This package has comprehensive test coverage (90%+) including:
- XSS attack prevention (script tags, event handlers, protocols)
- All security profiles (strict, moderate, relaxed)
- Custom configuration options
- Edge cases (malformed HTML, Unicode, large input)
- Sanitization result metadata
Related Packages
Dependencies
dompurify(npm) - HTML sanitization enginejsdom(npm) - DOM implementation
Used By
@bernierllc/content-transformer- Content format conversions@bernierllc/content-editor-service- Editor backend@bernierllc/markdown-renderer- HTML output sanitization
Part Of
- Content Management Suite - Blog content and commit message workflows
License
Copyright (c) 2025 Bernier LLC
This file is licensed to the client under a limited-use license. The client may use and modify this code only within the scope of the project it was delivered for. Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
Security
For security concerns or to report vulnerabilities, please contact: [email protected]
This is a security-critical package. All XSS vulnerabilities are treated as high priority.
