Introducing Purifai: A Zero-Dependency Strip-to-Text Sanitizer

Introducing Purifai: A Zero-Dependency Strip-to-Text Sanitizer

Published March 8, 2025 · Updated July 26, 2026 · 6 min read

Purifai is a zero-dependency, TypeScript-native strip-to-text sanitizer designed for Node.js, browsers, edge runtimes, and workers.

Introducing Purifai: A Zero-Dependency Strip-to-Text Sanitizer

Cross-site scripting (XSS) is still one of the top risks on the OWASP Top 10. Every time you render user-generated content—comments, rich text, profile bios—you're opening a door. The standard fix is sanitization: strip or escape dangerous HTML before it hits the DOM. There are two different jobs hiding behind that one word. One is preserving safe HTML while removing the dangerous parts — what DOMPurify and sanitize-html do, and the harder problem. The other is emitting untrusted content as plain text, where nothing needs to survive. I built Purifai for the second job, in a footprint small enough for edge runtimes with no DOM available.

Purifai is a zero-dependency strip-to-text sanitizer: it removes markup rather than allow-listing safe tags. That leaves no markup for a parser to mutate on re-parse, and it places Purifai in a different category from DOMPurify, which exists to keep safe formatting. It's TypeScript-native, 4.1 KB gzipped, needs no DOM, and runs in Node, browsers, edge runtimes, and workers.

Abstract tangled input passing through a filter into clean output

Quick Start

Install it:

npm install purifai # or pnpm add purifai

Use it:

import { Purifai } from 'purifai'; // Simple sanitization const clean = Purifai.sanitize('<script>alert("xss")</script>Hello World'); console.log(clean); // "Hello World" // With options for stricter control const safe = Purifai.sanitize(userInput, { maxLength: 10000, allowBasicHtml: false, aggressiveMode: true });

That's it. No DOM, no external dependencies. Just a function that takes dirty HTML and returns safe output.

Security and Content Fidelity

The benchmark inserts each sanitizer's output into a real DOM (jsdom), serializes and re-parses it, and counts a vector blocked only if neither parse yields a script node, an on* handler, or a dangerous-protocol URL. It reports content fidelity alongside security:

LibraryCategorySecurityText keptMarkup kept
Purifaistrip-to-text100%100%0% (by design)
DOMPurifypreserve-html100%100%100%
sanitize-htmlpreserve-html100%100%100%
xsspreserve-html100%100%100%

84 attack vectors, including the mutation-XSS and namespace-confusion corpora from cure53 and PortSwigger.

Every maintained sanitizer in the comparison blocks the full suite. Purifai's 0% markup retention is its design: it exists for content that should be displayed as text, with no surviving markup for a browser to reinterpret.

Where Purifai Fits

DOMPurify and sanitize-html preserve safe markup, which is the right choice for rich text. Purifai is designed for places where the output should be text: labels, previews, notifications, search indexes, logs, and API pipelines. Removing markup also means it can run without a browser DOM or a server-side DOM shim.

The choice is about output requirements. Keep a preserve-HTML sanitizer when formatting must survive; use Purifai when plain text is the intended result.

How Purifai Approaches the Problem

Purifai uses a multi-stage pipeline without relying on a runtime DOM. It:

  1. Normalizes encodings first — Decodes HTML entities, URL encoding, and Unicode escapes before applying rules.
  2. Handles context switches — Tracks when the parser moves between HTML, SVG, script, and style contexts.
  3. Blocks protocol injectionjavascript:, vbscript:, data: URIs are stripped from attributes.
  4. Offers aggressive modeaggressiveMode: true (default) applies stricter rules and fallback checks.

aggressiveMode is the right choice for user-generated content, chat systems, CMS content, or anywhere you can't fully trust the input. Turn it off only if you have a controlled input source and need to preserve more HTML structure.

Key Features

Zero dependencies. No DOM, no jsdom, no cheerio. Minimal bundle size (~12KB) and a tiny attack surface. Works in Node and the browser.

Threat analysis. Use analyze() when you need more than sanitization—logging, blocking, or incident response:

import { analyze } from 'purifai'; const result = analyze('<script>alert("hack")</script>User content'); console.log(result.content); // "User content" console.log(result.hadThreats); // true console.log(result.threatLevel); // "critical" if (result.hadThreats) { console.warn('Potential XSS detected', { level: result.threatLevel }); } broadcast(result.content); // Safe to use

Batch processing. Sanitize multiple strings at once for APIs or content pipelines:

import { sanitizeBatch } from 'purifai'; const cleanData = sanitizeBatch([ '<script>alert(1)</script>Hello', '<img src=x onerror=alert(1)>World', 'Safe content' ]); // ["Hello", "World", "Safe content"]

Danger check. Quick pre-scan with isDangerous() for logging or blocking before full sanitization.

Choosing Purifai over a Preserve-HTML Sanitizer

Purifai is not a drop-in replacement when your product needs to retain rich-text formatting. Its API is straightforward to adopt when the desired output is plain text or a small, explicitly enabled set of basic tags.

When Migration Makes Sense

  • Plain-text output — Markup does not need to survive
  • Edge and worker runtimes — No browser DOM or jsdom available
  • Small dependency budget — A compact, zero-dependency package
  • TypeScript projects — Typed APIs without separate declarations

From DOMPurify

Before:

import DOMPurify from 'dompurify'; const clean = DOMPurify.sanitize(dirty);

After:

import { sanitize } from 'purifai'; const clean = sanitize(dirty);

If you were using DOMPurify in Node with jsdom, you no longer need jsdom—Purifai doesn't use the DOM.

From sanitize-html

Before:

import sanitizeHtml from 'sanitize-html'; const clean = sanitizeHtml(dirty, { allowedTags: ['b', 'i', 'em', 'strong', 'p'], allowedAttributes: { a: ['href'] }, });

After:

import { sanitize } from 'purifai'; const clean = sanitize(dirty, { allowBasicHtml: true, maxLength: 50000, allowedProtocols: ['http', 'https', 'mailto'], aggressiveMode: true });

allowBasicHtml: true enables a curated set of safe inline tags. For "strip everything," use allowBasicHtml: false (default).

Edge Cases

Custom protocols. Purifai defaults to http, https, and mailto. For others (e.g. tel:):

sanitize(dirty, { allowedProtocols: ['http', 'https', 'mailto', 'tel'] });

Max length. Cap input size to avoid DoS:

sanitize(dirty, { maxLength: 10000 });

Batch processing. For many strings (e.g. API request bodies):

import { sanitizeBatch } from 'purifai'; const cleanData = sanitizeBatch(Object.values(request.body));

Testing Strategy

Don't switch cold. Run both sanitizers in parallel during rollout:

  1. Install Purifai alongside your current library.
  2. Add a comparison layer in development or staging:
import { sanitize as purifaiSanitize } from 'purifai'; import DOMPurify from 'dompurify'; function sanitizeWithComparison(input: string) { const purifaiResult = purifaiSanitize(input); const dompurifyResult = DOMPurify.sanitize(input); if (purifaiResult !== dompurifyResult) { console.warn('Sanitizer output differs', { input, purifaiResult, dompurifyResult }); } return purifaiResult; }
  1. Log differences—Purifai may strip more because its default output is plain text.
  2. Run your test suite. Fix any legitimate content that gets over-stripped.
  3. Deploy, then remove the old library and comparison code.

Quick Checklist

  • Install: pnpm add purifai
  • Replace imports: sanitize from purifai
  • Map options: allowBasicHtml, maxLength, allowedProtocols as needed
  • Remove jsdom (if you only had it for DOMPurify)
  • Run both sanitizers in parallel in staging
  • Run tests, fix any over-stripping
  • Deploy and remove old dependency

Wrap-up

Purifai offers a compact option for turning untrusted markup into text without a DOM dependency. If your product needs rich text, keep a sanitizer built to preserve safe HTML; if it needs text, Purifai keeps that path small and portable.

Purifai is on npm and open source on GitHub. Run the benchmark yourself with pnpm benchmark; the suite compares security and content fidelity across Purifai, DOMPurify, sanitize-html, and xss. The README and GitHub issues cover usage and edge cases.