{"_id":"@bernierllc/html-sanitizer","_rev":"6-df33e5e477724a7338670866c62fcde0","name":"@bernierllc/html-sanitizer","dist-tags":{"latest":"1.5.0"},"versions":{"1.0.0":{"name":"@bernierllc/html-sanitizer","version":"1.0.0","keywords":["html","sanitizer","xss","security","content"],"author":{"name":"Bernier LLC"},"license":"SEE LICENSE IN LICENSE.txt","_id":"@bernierllc/html-sanitizer@1.0.0","maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"dist":{"shasum":"ef2d07459345ea9f93e87186f1171dde724a80c6","tarball":"https://registry.npmjs.org/@bernierllc/html-sanitizer/-/html-sanitizer-1.0.0.tgz","fileCount":24,"integrity":"sha512-cX4TBfJHhUg818nJtwFhVjOt0FGyIKpfzfhmjL21Med+UDMOr3Jn0fJ8Dtr0kVxM1g3TBlYC1yZYczHCDCEpDQ==","signatures":[{"sig":"MEUCIQCV0zJnk0GwxEUZZm12WcoVKn2RXgZV2z64UMYK8UmuiwIgFchSC0K67wvis/lVwpOHrTXGH77vpmj6rcG0Z14Z6nU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":76378},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"a2a0a7115181a9a7f7e1649f8003d2bf17c6b8a7","scripts":{"lint":"eslint src/**/*.ts","test":"jest --watch","build":"tsc","clean":"rm -rf dist","test:run":"jest","test:coverage":"jest --coverage"},"_npmUser":{"name":"mkbernier","email":"mkbernier@gmail.com"},"bernierllc":{"category":"core","priority":"critical","integration":{"logger":"optional","docsuite":"ready","neverhub":"optional"},"securityCritical":true},"_npmVersion":"11.6.0","description":"XSS prevention and HTML sanitization for user-generated content","directories":{},"_nodeVersion":"24.10.0","dependencies":{"jsdom":"^25.0.1","dompurify":"^3.1.7"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","eslint":"^8.50.0","ts-jest":"^29.1.0","typescript":"^5.0.0","@types/jest":"^29.5.0","@types/node":"^20.0.0","@types/jsdom":"^21.1.7","@types/dompurify":"^3.0.5","@typescript-eslint/parser":"^6.0.0","@typescript-eslint/eslint-plugin":"^6.0.0"},"peerDependencies":{"@bernierllc/logger":"^1.0.0"},"peerDependenciesMeta":{"@bernierllc/logger":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/html-sanitizer_1.0.0_1762314613912_0.4273261042230192","host":"s3://npm-registry-packages-npm-production"}},"1.0.7":{"name":"@bernierllc/html-sanitizer","version":"1.0.7","keywords":["html","sanitizer","xss","security","content"],"author":{"name":"Bernier LLC"},"license":"SEE LICENSE IN LICENSE.txt","_id":"@bernierllc/html-sanitizer@1.0.7","maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"dist":{"shasum":"ce9170929f627f43b368504765ce7d12c85c3bb8","tarball":"https://registry.npmjs.org/@bernierllc/html-sanitizer/-/html-sanitizer-1.0.7.tgz","fileCount":39,"integrity":"sha512-dVOsDAR+gVoJzMsywkcX3jaltq9fxbiLC/9/0GoofA9eWqwxQ4B3wXGyRgUpFJHvbmUK6RceNag1P1XnW9CyZQ==","signatures":[{"sig":"MEQCIHpMok8kU4uQ+/eBhm9JgEdhuHvWnBRe4bJKdGxvCVcQAiBaWWshlJ1jNM705H95pVBQ+3drFBKPC06a/hu1uH2yRg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":202791},"main":"dist/index.js","_from":"file:bernierllc-html-sanitizer-1.0.7.tgz","types":"dist/index.d.ts","scripts":{"lint":"eslint src/**/*.ts","test":"jest --watch","build":"tsc","clean":"rm -rf dist","test:run":"jest","test:coverage":"jest --coverage"},"_npmUser":{"name":"mkbernier","email":"mkbernier@gmail.com"},"_resolved":"/private/var/folders/r0/wspnzd1s18sfjy10ffyv2qxw0000gn/T/fe9ca52dc5bfbfb2e6644539dd74cd31/bernierllc-html-sanitizer-1.0.7.tgz","_integrity":"sha512-dVOsDAR+gVoJzMsywkcX3jaltq9fxbiLC/9/0GoofA9eWqwxQ4B3wXGyRgUpFJHvbmUK6RceNag1P1XnW9CyZQ==","bernierllc":{"category":"core","priority":"critical","integration":{"logger":"optional","docsuite":"ready","neverhub":"optional"},"securityCritical":true},"_npmVersion":"11.6.2","description":"XSS prevention and HTML sanitization for user-generated content","directories":{},"_nodeVersion":"25.2.1","dependencies":{"jsdom":"^25.0.1","dompurify":"^3.1.7"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","eslint":"^8.50.0","ts-jest":"^29.1.0","typescript":"^5.0.0","@types/jest":"^29.5.0","@types/node":"^20.0.0","@types/jsdom":"^21.1.7","@types/dompurify":"^3.0.5","@typescript-eslint/parser":"^6.0.0","@typescript-eslint/eslint-plugin":"^6.0.0"},"peerDependencies":{"@bernierllc/logger":"^1.0.0"},"peerDependenciesMeta":{"@bernierllc/logger":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/html-sanitizer_1.0.7_1764636152243_0.4994993746839549","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@bernierllc/html-sanitizer","version":"1.2.0","keywords":["html","sanitizer","xss","security","content"],"author":{"name":"Bernier LLC"},"license":"SEE LICENSE IN LICENSE.txt","_id":"@bernierllc/html-sanitizer@1.2.0","maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"dist":{"shasum":"e8204c64bc41ee93c101ffee4014dc7242c7ec42","tarball":"https://registry.npmjs.org/@bernierllc/html-sanitizer/-/html-sanitizer-1.2.0.tgz","fileCount":25,"integrity":"sha512-9fiGp7Ngg1bImR674QurUWsvq5jSkfIP0OUsuZEaoOFOhQdnDiHjp0Oh3XD1V5dR5HzcjbA7eKc2CyeEIWq4ow==","signatures":[{"sig":"MEYCIQC1CTLbfRxBjxhj5MBL2evJ5E7bSCgsPLnOpulF1jAKoAIhAI0/TykwfVvM6B8LLeiPweFd8qky4d2EXJh6nyBmgFmZ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":79922},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"af7e74b3715d56d3a193e1bb6743b337c2b0df6d","scripts":{"lint":"eslint src/**/*.ts","test":"jest --watch","build":"tsc","clean":"rm -rf dist","test:run":"jest","test:coverage":"jest --coverage"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1adf0fba-0843-44cd-a45e-9759b8e68575"}},"bernierllc":{"category":"core","priority":"critical","integration":{"logger":"optional","docsuite":"ready","neverhub":"optional"},"securityCritical":true},"_npmVersion":"lerna/9.0.3/node@v20.19.6+x64 (linux)","description":"XSS prevention and HTML sanitization for user-generated content","directories":{},"_nodeVersion":"20.19.6","dependencies":{"jsdom":"^25.0.1","dompurify":"^3.1.7"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","eslint":"^8.50.0","ts-jest":"^29.1.0","typescript":"^5.0.0","@types/jest":"^29.5.0","@types/node":"^20.0.0","@types/jsdom":"^21.1.7","@types/dompurify":"^3.0.5","@typescript-eslint/parser":"^6.0.0","@typescript-eslint/eslint-plugin":"^6.0.0"},"peerDependencies":{"@bernierllc/logger":"^1.0.0"},"peerDependenciesMeta":{"@bernierllc/logger":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/html-sanitizer_1.2.0_1767642309220_0.09355985429435276","host":"s3://npm-registry-packages-npm-production"}},"1.2.2":{"name":"@bernierllc/html-sanitizer","version":"1.2.2","keywords":["html","sanitizer","xss","security","content"],"author":{"name":"Bernier LLC"},"license":"SEE LICENSE IN LICENSE.txt","_id":"@bernierllc/html-sanitizer@1.2.2","maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"dist":{"shasum":"92b8e84ea2ea0a009b04e86ca01310c6d4425861","tarball":"https://registry.npmjs.org/@bernierllc/html-sanitizer/-/html-sanitizer-1.2.2.tgz","fileCount":25,"integrity":"sha512-z9QmSmsGW9SUVF4kCyBgtz7r3I4CBXqpob7yuqfzx/9ObDBY4qUCtAQzhxQbbd524IrDaqRzK0GoG44tKD0JcA==","signatures":[{"sig":"MEUCIC00ZcF9qjlo0HN9DshN0aT1gzAmCNC6kLAasHLCnhtuAiEAnU75VyElkyiqC4LIg1KRqClyJ6foy4u6lMEDbYLyd+s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":80284},"main":"dist/index.js","_from":"file:bernierllc-html-sanitizer-1.2.2.tgz","types":"dist/index.d.ts","scripts":{"lint":"eslint src/**/*.ts","test":"jest --watch","build":"tsc","clean":"rm -rf dist","test:run":"jest","test:coverage":"jest --coverage"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1adf0fba-0843-44cd-a45e-9759b8e68575"}},"_resolved":"/home/runner/work/tools/tools/packages/core/html-sanitizer/bernierllc-html-sanitizer-1.2.2.tgz","_integrity":"sha512-z9QmSmsGW9SUVF4kCyBgtz7r3I4CBXqpob7yuqfzx/9ObDBY4qUCtAQzhxQbbd524IrDaqRzK0GoG44tKD0JcA==","bernierllc":{"category":"core","priority":"critical","integration":{"logger":"optional","docsuite":"ready","neverhub":"optional"},"securityCritical":true},"_npmVersion":"11.11.0","description":"XSS prevention and HTML sanitization for user-generated content","directories":{},"_nodeVersion":"20.20.0","dependencies":{"jsdom":"^25.0.1","dompurify":"^3.1.7"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","eslint":"^8.50.0","ts-jest":"^29.1.0","typescript":"^5.0.0","@types/jest":"^29.5.0","@types/node":"^20.0.0","@types/jsdom":"^21.1.7","@types/dompurify":"^3.0.5","@typescript-eslint/parser":"^6.0.0","@typescript-eslint/eslint-plugin":"^6.0.0"},"peerDependencies":{"@bernierllc/logger":"^1.0.0"},"peerDependenciesMeta":{"@bernierllc/logger":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/html-sanitizer_1.2.2_1773163195299_0.7708586575933081","host":"s3://npm-registry-packages-npm-production"}},"1.4.0":{"name":"@bernierllc/html-sanitizer","version":"1.4.0","keywords":["html","sanitizer","xss","security","content"],"author":{"name":"Bernier LLC"},"license":"SEE LICENSE IN LICENSE.txt","_id":"@bernierllc/html-sanitizer@1.4.0","maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"dist":{"shasum":"b7796e478f29aa56de2a988a04968adc8f40e85b","tarball":"https://registry.npmjs.org/@bernierllc/html-sanitizer/-/html-sanitizer-1.4.0.tgz","fileCount":14,"integrity":"sha512-haeU0Zx9sumcniJ0TAbKXVkepFqg42t4HkkSjDhs4mxvuDc9t1GCzoKl50NG0D1Y3K9CprwejWQNV1KK4Ovsbw==","signatures":[{"sig":"MEQCIFX6DcAA6wD/Ilc3YneIYUiWqb+HDkshzTEGrHkyBHHtAiBYJWVmBzZCSbbS1dyc9J7QHFKv4Des8Wx+eoAer6AYxw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":32956},"main":"dist/index.js","_from":"file:bernierllc-html-sanitizer-1.4.0.tgz","types":"dist/index.d.ts","scripts":{"lint":"eslint src/**/*.ts","test":"jest --watch","build":"tsc","clean":"rm -rf dist","test:run":"jest","test:coverage":"jest --coverage"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1adf0fba-0843-44cd-a45e-9759b8e68575"}},"_resolved":"/home/runner/work/tools/tools/packages/core/html-sanitizer/bernierllc-html-sanitizer-1.4.0.tgz","_integrity":"sha512-haeU0Zx9sumcniJ0TAbKXVkepFqg42t4HkkSjDhs4mxvuDc9t1GCzoKl50NG0D1Y3K9CprwejWQNV1KK4Ovsbw==","bernierllc":{"category":"core","priority":"critical","integration":{"logger":"optional","docsuite":"ready","neverhub":"optional"},"securityCritical":true},"_npmVersion":"11.14.1","description":"XSS prevention and HTML sanitization for user-generated content","directories":{},"_nodeVersion":"20.20.2","dependencies":{"jsdom":"^25.0.1","dompurify":"^3.1.7"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","eslint":"^8.50.0","ts-jest":"^29.1.0","typescript":"^5.0.0","@types/jest":"^29.5.0","@types/node":"^20.0.0","@types/jsdom":"^21.1.7","@types/dompurify":"^3.0.5","@typescript-eslint/parser":"^6.0.0","@typescript-eslint/eslint-plugin":"^6.0.0"},"peerDependencies":{"@bernierllc/logger":"^1.0.0"},"peerDependenciesMeta":{"@bernierllc/logger":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/html-sanitizer_1.4.0_1779241192963_0.8041956731453777","host":"s3://npm-registry-packages-npm-production"}},"1.5.0":{"name":"@bernierllc/html-sanitizer","version":"1.5.0","description":"XSS prevention and HTML sanitization for user-generated content","main":"dist/index.js","types":"dist/index.d.ts","author":{"name":"Bernier LLC"},"license":"SEE LICENSE IN LICENSE.txt","keywords":["html","sanitizer","xss","security","content"],"dependencies":{"dompurify":"^3.1.7","jsdom":"^25.0.1"},"peerDependencies":{"@bernierllc/logger":"^1.0.0"},"peerDependenciesMeta":{"@bernierllc/logger":{"optional":true}},"devDependencies":{"@types/dompurify":"^3.0.5","@types/jest":"^29.5.0","@types/jsdom":"^21.1.7","@types/node":"^20.0.0","@typescript-eslint/eslint-plugin":"^6.0.0","@typescript-eslint/parser":"^6.0.0","eslint":"^8.50.0","jest":"^29.5.0","ts-jest":"^29.1.0","typescript":"^5.0.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"bernierllc":{"integration":{"logger":"optional","neverhub":"optional","docsuite":"ready"},"category":"core","priority":"critical","securityCritical":true},"scripts":{"build":"tsc","test":"jest --watch","test:run":"jest","test:coverage":"jest --coverage","lint":"eslint src/**/*.ts","clean":"rm -rf dist"},"_id":"@bernierllc/html-sanitizer@1.5.0","_integrity":"sha512-Hlan67E/TbK1EGA3bpHMEIPwARD/D/7KtvgGrZ+BBh9030yA991WryEiSmo8pO9tN1368JL/rcWglJ2kXAfguA==","_resolved":"/home/runner/work/tools/tools/packages/core/html-sanitizer/bernierllc-html-sanitizer-1.5.0.tgz","_from":"file:bernierllc-html-sanitizer-1.5.0.tgz","_nodeVersion":"20.20.2","_npmVersion":"11.14.1","dist":{"integrity":"sha512-Hlan67E/TbK1EGA3bpHMEIPwARD/D/7KtvgGrZ+BBh9030yA991WryEiSmo8pO9tN1368JL/rcWglJ2kXAfguA==","shasum":"623673f864e5c3701b3f277db78e6f146236f394","tarball":"https://registry.npmjs.org/@bernierllc/html-sanitizer/-/html-sanitizer-1.5.0.tgz","fileCount":14,"unpackedSize":32956,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBNLWMKfP40ZsASlLTE5VsZ0g4tOcfNoeihJu+I9kEd8AiARbT2f3LzXSmJSM4QJvFIMFtUW/vnnEUf9SgD/QfksPg=="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1adf0fba-0843-44cd-a45e-9759b8e68575"}},"directories":{},"maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/html-sanitizer_1.5.0_1779249937754_0.3690212221579492"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-05T03:50:13.796Z","modified":"2026-05-20T04:05:38.006Z","1.0.0":"2025-11-05T03:50:14.100Z","1.0.7":"2025-12-02T00:42:32.429Z","1.2.0":"2026-01-05T19:45:09.368Z","1.2.2":"2026-03-10T17:19:55.453Z","1.4.0":"2026-05-20T01:39:53.104Z","1.5.0":"2026-05-20T04:05:37.895Z"},"author":{"name":"Bernier LLC"},"license":"SEE LICENSE IN LICENSE.txt","keywords":["html","sanitizer","xss","security","content"],"description":"XSS prevention and HTML sanitization for user-generated content","maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"readme":"# @bernierllc/html-sanitizer\n\n**XSS Prevention and HTML Sanitization for User-Generated Content**\n\nA 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.\n\n## Installation\n\n```bash\nnpm install @bernierllc/html-sanitizer\n```\n\n## Quick Start\n\n```typescript\nimport { HtmlSanitizer, sanitizeHtml, SanitizationProfile } from '@bernierllc/html-sanitizer';\n\n// Simple sanitization with defaults (MODERATE profile)\nconst clean = sanitizeHtml('<p>Safe content</p><script>alert(\"XSS\")</script>');\n// Result: '<p>Safe content</p>' (script removed)\n\n// Get detailed sanitization report\nconst sanitizer = new HtmlSanitizer();\nconst result = sanitizer.sanitize(userHtml);\n\nconsole.log(result.html);           // Clean HTML\nconsole.log(result.modified);       // true if content was changed\nconsole.log(result.removedTags);    // ['script', 'object']\nconsole.log(result.xssPatterns);    // ['script tag', 'event handler']\nconsole.log(result.warnings);       // Security warnings\n```\n\n## Features\n\n- **XSS Attack Prevention**: Removes script tags, event handlers, dangerous protocols\n- **Configurable Profiles**: STRICT, MODERATE, RELAXED security levels\n- **Custom Rules**: Define your own allowed tags, attributes, and protocols\n- **Security Reporting**: Detailed reports of removed content and detected patterns\n- **Performance Optimized**: Built on DOMPurify, the industry standard\n- **Zero-Config**: Works out of the box with sensible defaults\n\n## Security Profiles\n\n### STRICT Profile\n\nOnly basic text formatting - ideal for comments or simple user input:\n\n```typescript\nimport { sanitizeWithProfile, SanitizationProfile } from '@bernierllc/html-sanitizer';\n\nconst clean = sanitizeWithProfile(userHtml, SanitizationProfile.STRICT);\n```\n\n**Allowed:**\n- Basic formatting: `<p>`, `<br>`, `<strong>`, `<em>`, `<b>`, `<i>`, `<u>`\n- Lists: `<ul>`, `<ol>`, `<li>`\n\n**Blocked:**\n- Links, images, tables, media, everything else\n\n### MODERATE Profile (Default)\n\nStandard blog content formatting - default for most use cases:\n\n```typescript\nconst sanitizer = new HtmlSanitizer(); // Uses MODERATE by default\n```\n\n**Allowed:**\n- All STRICT tags\n- Headings: `<h1>` through `<h6>`\n- Links: `<a href=\"...\" title=\"...\">`\n- Images: `<img src=\"...\" alt=\"...\">`\n- Code: `<code>`, `<pre>`, `<blockquote>`\n\n**Protocols:** `http`, `https`, `mailto`\n\n### RELAXED Profile\n\nRich content for trusted users - includes tables and embedded media:\n\n```typescript\nconst clean = sanitizeWithProfile(userHtml, SanitizationProfile.RELAXED);\n```\n\n**Allowed:**\n- All MODERATE tags\n- Tables: `<table>`, `<thead>`, `<tbody>`, `<tr>`, `<th>`, `<td>`\n- Media: `<iframe>`, `<video>`, `<audio>`\n\n## Custom Configuration\n\nDefine your own security rules:\n\n```typescript\nimport { HtmlSanitizer } from '@bernierllc/html-sanitizer';\n\nconst sanitizer = new HtmlSanitizer({\n  allowedTags: ['p', 'a', 'strong', 'em'],\n  allowedAttributes: {\n    'a': ['href', 'title']\n  },\n  allowedProtocols: ['https'], // Only HTTPS links\n  allowStyles: false,\n  allowDataUris: false\n});\n\nconst result = sanitizer.sanitize(userHtml);\n```\n\n## API Reference\n\n### `HtmlSanitizer`\n\nMain class for HTML sanitization.\n\n#### Constructor\n\n```typescript\nnew HtmlSanitizer(config?: SanitizerConfig)\n```\n\n**Config Options:**\n- `allowedTags?: string[]` - Whitelist of allowed HTML tags\n- `allowedAttributes?: Record<string, string[]>` - Allowed attributes per tag\n- `allowedProtocols?: string[]` - Allowed URL protocols\n- `allowStyles?: boolean` - Allow inline styles (default: false)\n- `allowDataUris?: boolean` - Allow data: URIs (default: false)\n- `mode?: 'strict' | 'moderate' | 'relaxed'` - Use predefined profile\n\n#### Methods\n\n**`sanitize(html: string): SanitizationResult`**\n\nSanitize HTML and get detailed report:\n\n```typescript\nconst result = sanitizer.sanitize(html);\n\n// SanitizationResult:\n{\n  html: string;                              // Sanitized HTML\n  modified: boolean;                         // Whether content was changed\n  removedTags: string[];                     // Tags that were removed\n  removedAttributes: Array<{                 // Attributes that were removed\n    tag: string;\n    attribute: string;\n  }>;\n  xssPatterns: string[];                     // XSS patterns detected\n  warnings: string[];                        // Security warnings\n}\n```\n\n**`sanitizeWithProfile(html: string, profile: SanitizationProfile): SanitizationResult`**\n\nSanitize using a specific profile:\n\n```typescript\nconst result = sanitizer.sanitizeWithProfile(html, SanitizationProfile.STRICT);\n```\n\n**`validate(html: string): ValidationResult`**\n\nCheck if HTML is safe without modifying:\n\n```typescript\nconst result = sanitizer.validate(html);\n\n// ValidationResult:\n{\n  safe: boolean;      // Whether HTML is safe\n  issues: string[];   // List of security issues\n}\n```\n\n### Convenience Functions\n\n**`sanitizeHtml(html: string, config?: SanitizerConfig): string`**\n\nQuick sanitization, returns clean HTML string:\n\n```typescript\nimport { sanitizeHtml } from '@bernierllc/html-sanitizer';\n\nconst clean = sanitizeHtml(userInput);\n```\n\n**`sanitizeWithProfile(html: string, profile: SanitizationProfile): string`**\n\nSanitize with a profile, returns clean HTML string:\n\n```typescript\nimport { sanitizeWithProfile, SanitizationProfile } from '@bernierllc/html-sanitizer';\n\nconst clean = sanitizeWithProfile(userInput, SanitizationProfile.STRICT);\n```\n\n**`validateHtml(html: string): { safe: boolean; issues: string[] }`**\n\nValidate HTML safety:\n\n```typescript\nimport { validateHtml } from '@bernierllc/html-sanitizer';\n\nconst result = validateHtml(userInput);\nif (!result.safe) {\n  console.error('Unsafe HTML:', result.issues);\n}\n```\n\n## XSS Attack Prevention\n\nThis package protects against all common XSS attack vectors:\n\n### Script Tags\n\n```typescript\nconst html = '<p>Hello</p><script>alert(\"XSS\")</script>';\nconst result = sanitizer.sanitize(html);\n\n// result.html: '<p>Hello</p>'\n// result.removedTags: ['script']\n// result.xssPatterns: ['script tag']\n// result.warnings: ['CRITICAL: Dangerous executable content removed']\n```\n\n### Event Handlers\n\n```typescript\nconst html = '<img src=\"x\" onerror=\"alert(1)\">';\nconst result = sanitizer.sanitize(html);\n\n// onerror attribute removed\n// result.xssPatterns: ['event handler']\n```\n\n### JavaScript Protocol\n\n```typescript\nconst html = '<a href=\"javascript:alert(1)\">Click</a>';\nconst result = sanitizer.sanitize(html);\n\n// javascript: protocol removed\n// result.xssPatterns: ['javascript: protocol']\n```\n\n### Data URIs\n\n```typescript\nconst html = '<img src=\"data:text/html,<script>alert(1)</script>\">';\nconst result = sanitizer.sanitize(html);\n\n// Detected and blocked\n// result.xssPatterns: ['data: URI']\n```\n\n### Embedded Objects\n\n```typescript\nconst html = '<object data=\"malicious.swf\"></object>';\nconst result = sanitizer.sanitize(html);\n\n// <object> and <embed> tags always removed\n// result.removedTags: ['object']\n```\n\n## Security Best Practices\n\n### Always Sanitize User Input\n\n```typescript\n// ✅ CORRECT\napp.post('/comment', (req, res) => {\n  const sanitized = sanitizeHtml(req.body.comment);\n  await saveComment(sanitized);\n});\n\n// ❌ WRONG - Never trust user input\napp.post('/comment', (req, res) => {\n  await saveComment(req.body.comment); // Dangerous!\n});\n```\n\n### Choose the Right Profile\n\n```typescript\n// Comments: Use STRICT\nconst comment = sanitizeWithProfile(userComment, SanitizationProfile.STRICT);\n\n// Blog posts: Use MODERATE (default)\nconst blogPost = sanitizeHtml(userBlogPost);\n\n// Admin content: Use RELAXED (only for trusted users)\nif (user.isAdmin) {\n  const adminContent = sanitizeWithProfile(userContent, SanitizationProfile.RELAXED);\n}\n```\n\n### Monitor Security Events\n\n```typescript\nconst result = sanitizer.sanitize(userHtml);\n\nif (result.xssPatterns.length > 0) {\n  // Log security event\n  logger.warn('XSS attempt detected', {\n    userId: user.id,\n    patterns: result.xssPatterns,\n    removedTags: result.removedTags\n  });\n}\n```\n\n### Use Validation Before Saving\n\n```typescript\nconst validation = validateHtml(userInput);\n\nif (!validation.safe) {\n  return res.status(400).json({\n    error: 'Content contains unsafe HTML',\n    issues: validation.issues\n  });\n}\n```\n\n## Performance\n\n- **Typical blog post (5KB)**: <10ms\n- **Large content (500KB)**: <100ms\n- **Memory usage**: <50MB for large content\n\nBuilt on DOMPurify, which is highly optimized and used by millions of websites.\n\n## Integration Status\n\n### Logger Integration\n**Status**: Optional (recommended for security monitoring)\n\n**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.\n\n**Pattern**: Optional integration - package works without logger, but logger enhances security monitoring capabilities.\n\n**Example Integration**:\n```typescript\nimport { Logger } from '@bernierllc/logger';\nimport { HtmlSanitizer } from '@bernierllc/html-sanitizer';\n\nconst logger = new Logger({ service: 'html-sanitizer' });\nconst sanitizer = new HtmlSanitizer();\n\nconst result = sanitizer.sanitize(userHtml);\nif (result.xssPatterns.length > 0) {\n  logger.warn('XSS attempt detected', {\n    patterns: result.xssPatterns,\n    removedTags: result.removedTags\n  });\n}\n```\n\n### NeverHub Integration\n**Status**: Not applicable\n\n**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.\n\n**Pattern**: Core utility - no service mesh integration needed. Security events should be handled by the application layer that uses this sanitizer.\n\n### Docs-Suite Integration\n**Status**: Ready\n\n**Format**: TypeDoc-compatible JSDoc comments are included throughout the source code. All public APIs are documented with examples and type information.\n\n## Dependencies\n\n- **dompurify** (^3.1.7) - HTML sanitization engine\n- **jsdom** (^25.0.1) - DOM implementation for Node.js\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Run tests\nnpm test\n\n# Run tests with coverage\nnpm run test:coverage\n\n# Build package\nnpm run build\n\n# Lint code\nnpm run lint\n```\n\n## Testing\n\nThis package has comprehensive test coverage (90%+) including:\n\n- XSS attack prevention (script tags, event handlers, protocols)\n- All security profiles (strict, moderate, relaxed)\n- Custom configuration options\n- Edge cases (malformed HTML, Unicode, large input)\n- Sanitization result metadata\n\n## Related Packages\n\n### Dependencies\n- `dompurify` (npm) - HTML sanitization engine\n- `jsdom` (npm) - DOM implementation\n\n### Used By\n- `@bernierllc/content-transformer` - Content format conversions\n- `@bernierllc/content-editor-service` - Editor backend\n- `@bernierllc/markdown-renderer` - HTML output sanitization\n\n### Part Of\n- **Content Management Suite** - Blog content and commit message workflows\n\n## License\n\nCopyright (c) 2025 Bernier LLC\n\nThis file is licensed to the client under a limited-use license.\nThe client may use and modify this code *only within the scope of the project it was delivered for*.\nRedistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.\n\n## Security\n\nFor security concerns or to report vulnerabilities, please contact: security@bernierllc.com\n\n**This is a security-critical package. All XSS vulnerabilities are treated as high priority.**\n","readmeFilename":"README.md"}