phlib/xss-sanitizer
PHP library for sanitizing untrusted HTML and preventing XSS. It parses user-supplied markup, strips dangerous tags, attributes and URLs, and returns safe HTML for rendering in web applications. Configurable rules suit comments, rich text and other user-generated content.
Architecture fit. phlib/xss-sanitizer is a standalone PHP library, not a framework package. It ships no Laravel service provider, facade, config file, or Blade directive, so it occupies no opinionated slot in a Laravel architecture. Its natural home is a thin anti-corruption layer at the trust boundary: a HtmlSanitizerInterface bound in a service provider and injected wherever untrusted HTML is ingested or rendered. That is a reasonable architectural position, but the package does not earn it — the same seam can be filled by any sanitizer, which means the package is a replaceable implementation detail rather than a structural dependency. Functionally it appears to be a convenience wrapper plus configuration-caching layer over HTML Purifier; the security-critical logic lives in the upstream library, and the package's distinct value is ergonomics and performance, not detection capability.
Integration feasibility. Mechanically trivial: composer require, one wrapper class, one binding, done. The friction is entirely non-technical — licensing and provenance. Two gates must clear before any code is written:
vendor/, so the "linking exception" argument is weaker than it is for compiled languages. Most organizations tolerate LGPL in server-side dependencies, but this requires an explicit legal ruling, not an engineering judgment call. Treat this as a hard gate, not a checklist item.Technical risk. Ranked by severity:
Key questions for the maintainer/vendor evaluation.
ezyang/htmlpurifier — caching only, or behavioral differences in filtering?mews/purifier (Laravel-native, widely adopted) or symfony/html-sanitizer (institutional backing, no wrapper layer)?The honest answer to the last question is likely "no strong reason," which should frame the whole evaluation.
Stack fit. Poor-to-adequate. Laravel's default posture — escape on output via {{ }} and e() — already covers the majority of XSS exposure and costs nothing. A sanitizer is only warranted where rich HTML must be preserved: WYSIWYG content, imported email bodies, CMS fragments, markdown-rendered user prose. Scope the integration to those surfaces only; do not adopt a sanitizer as a blanket policy replacement for output escaping, because sanitizing everything destroys fidelity and creates a false sense of coverage.
Comparison set before committing.
| Option | Laravel fit | Adoption | License | Verdict |
|---|---|---|---|---|
phlib/xss-sanitizer |
None (DIY) | Very low | LGPL-3.0 | Only if caching is the deciding factor |
mews/purifier |
Native (provider, config, facade) | High | MIT | Default candidate |
symfony/html-sanitizer |
None, but stable API | High | MIT | Strong if Wrapping is acceptable |
| HTML Purifier direct | None | Very high | LGPL-2.1+ | Baseline; same license concern |
Note that three of four options carry permissive licenses — the LGPL question is largely avoidable without conceding capability.
Migration path. Because the package is a wrapper, migration risk is asymmetric and low. Integrate behind an interface from day one:
HtmlSanitizerInterface::sanitize(string $html, string $profile): string.PhlibSanitizerAdapter in a service provider; resolve via constructor injection only, never app() calls in views or models.This makes the adoption decision reversible, which is the correct risk posture for a low-signal package.
Compatibility. Verify explicitly during the spike: the package's composer.json PHP constraint against the Laravel version in use (Laravel 10 → PHP 8.1+, Laravel 11 → PHP 8.2+), required extensions (ext-dom, ext-libxml, likely ext-mbstring), and behavior on the newest PHP minor, since low-adoption packages often lag on deprecation fixes. Also confirm the HTML Purifier version it pins — an outdated pin can mean unpatched advisories inherited transitively.
Sequencing.
mews/purifier on representative payloads — large documents, pathological nesting, malformed markup. Measure cold-start cost versus cached cost; that ratio determines whether the wrapper justifies itself.Step 2 is the decision point. If the caching benefit is not measurable against mews/purifier, the package offers nothing that justifies its licensing and maintenance overhead, and the evaluation should terminate there.
Maintenance. This is the dominant cost and it is structural, not incidental. You inherit a two-layer dependency: the wrapper's release cadence and HTML Purifier's. The wrapper adds no independent security research, so you are effectively betting on a single low-velocity maintainer to relay upstream patches promptly. Budget for the possibility that your team becomes the de facto maintainer — either by forking or by pinning and patching locally. That is a real ongoing headcount fraction, not a theoretical risk.
Support. With 16 stars, community support is effectively absent. There will be no Stack Overflow answers, no blog posts, no third-party tutorials. Every question escalates to the internal team, and every internal answer must be derived by reading source. Factor this into onboarding estimates for anyone who touches the sanitization path.
Scaling. The library is stateless and horizontally scalable; there is no shared state or session coupling. The constraint is CPU and memory. Two operating rules:
Enforce hard input-size limits at the boundary. Sanitizers are a classic vector for memory exhaustion and catastrophic backtracking on adversarially large documents.
Failure modes.
style, class, data-*, or permissive URI schemes) yields a bypass despite the library being "correct." Configuration is the attack surface, not the code.Ramp-up. Developer ramp-up is low: the API surface is small and the concepts (allowlist, profile, sanitize) are standard. Operational ramp-up is moderate: cache warming, size limits, write-path placement, and the shadow-mode rollout all require deliberate setup. Legal and security review is the long pole — plan for it to consume more calendar time than the engineering work itself, and do not let a successful spike create pressure to skip it.
Recommendation posture. Treat this as a conditional, reversible pilot rather than an adoption. The default should be mews/purifier or symfony/html-sanitizer; adopt phlib/xss-sanitizer only if the performance spike shows a material advantage that cannot be replicated by caching around a permissively licensed alternative, and only after LGPL clearance and repository provenance are resolved. The interface-first integration pattern keeps that decision cheap to reverse either way.
How can I help you explore Laravel packages today?