Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Html Sanitizer Laravel Package

typo3/html-sanitizer

A standalone PHP HTML sanitization component from TYPO3, usable in any PHP project. Declarative Behavior settings define allowed tags, attributes, and values; visitors modify or remove nodes; builders combine presets into ready-to-use Sanitizer instances for safe HTML output.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. Standalone, framework-agnostic PHP component distributed via Composer under MIT. Despite the TYPO3 namespace, the README explicitly declares CMS-agnosticism and the package has no dependency on TYPO3 core — it is a leaf library with only a PSR-3 logging dependency and ext-dom. The layering maps cleanly onto application boundaries: Behavior is policy, Visitor implementations are transformations, Builder is a preset factory, Sanitizer is the stateless engine. In a Laravel codebase that maps directly to config file → container-bound builder → singleton service. Critically, it is a parse-transform-serialize pipeline over a DOM, not a regex scrubber, which is the correct architecture for XSS defense.

Integration feasibility. High. composer require typo3/html-sanitizer plus roughly 30–50 lines of glue (service provider binding, optional Blade directive, optional Eloquent cast) is a working integration. No database, queue, or external service involvement. CommonBuilder ships a reasonable default allow-list, so a team can get to a safe baseline without hand-authoring policy. The cost is that no Laravel wrapper exists — we own and must test the glue ourselves.

Technical risk.

  1. Live CVE history. Releases v1.0.7, v1.5.0, v1.5.1, v1.5.3, v2.1.4 and v2.3.2 each ship [SECURITY] fixes: comment-end-bang bypass, CDATA and raw-text element XSS, processing-instruction handling, namespace attribute encoding, and a raw-text bypass under ALLOW_INSECURE_RAW_TEXT. This is double-edged — it demonstrates active maintenance, but a pinned-and-forgotten version inherits known vulnerabilities. Patch discipline is non-negotiable.
  2. Misleading adoption signal. 29 stars and 0 tracked dependents understate reality: the package is a TYPO3 CMS core dependency, so production deployment is far larger than GitHub metrics suggest. The honest read is "widely deployed but mostly through one CMS," meaning paths you hit in a generic Laravel app are less travelled than with Symfony's sanitizer.
  3. Bus factor. Effectively one primary maintainer plus the TYPO3 Security Team. Partly offset by five maintained release branches (1.5.x through 2.3.x), which evidences genuine LTS intent rather than a hobby project.
  4. API churn in the 2.x line. v2.3.0 made Behavior and visitors mandatory in the constructor and removed CommonBuilder->srcsetAttr; v2.3.1 reverted that removal. Treat minor bumps as needing test runs, not silent updates.
  5. Inconsistent immutability. Behavior is immutable (withFlags/withTags return new instances) but Behavior\Tag and Behavior\Attr are mutable. Sharing and then mutating a tag or attr object after building a preset is a real defect class, especially under Octane.
  6. Misconfiguration is the dominant risk, not the library. ALLOW_CUSTOM_ELEMENTS, ALLOW_INSECURE_RAW_TEXT, and naive value regexes (the README's #^https?://# is unanchored) can silently weaken policy. The library cannot save a team from a permissive allow-list.
  7. No published performance benchmarks. DOM parsing is O(document) and CPU-bound; sizing must come from our own load tests.

Key questions.

  • What tags and attributes actually exist in our content corpus, and do we need custom elements or closure handlers? If not, symfony/html-sanitizer is a lower-risk, larger-community alternative.
  • Write-time or read-time sanitization — do we store cleaned HTML or clean at render?
  • Do we need an audit trail of stripped content, or is silent removal acceptable? (PSR-3 logging with initiator forwarding covers basic observability.)
  • What is our SLA for applying upstream security releases, and is it automated?
  • Which branch do we pin, and does it support our PHP version?
  • Who owns the Behavior policy artifact — security, platform, or product?

Integration Approach

Stack fit. Compatible with Laravel 9–12 on PHP 8.1–8.4; the 2.x line has CI coverage through PHP 8.5. MIT licensing is clean for closed-source commercial use. No dependency conflicts beyond PSR-3. We supply the missing framework glue: a config/html-sanitizer.php holding the allow-list, an HtmlSanitizerServiceProvider binding the Sanitizer singleton via a custom Builder, and a Blade directive or HtmlString cast for unescaped rendering.

Alternatives weighed: mews/purifier (HTMLPurifier) is mature but config-driven, slow, and has no custom-element handlers or encode-rather-than-delete semantics. Symfony's sanitizer follows the W3C spec with a larger community but is less expressive for the "disarm and keep" behavior this package offers.

Migration path.

  1. Inventory — sample stored user HTML, extract tag/attribute frequency, author Behavior from evidence rather than assumption.
  2. Author policy — implement a Builder, and build a golden-file regression suite seeded from the oliverhader/html-sanitizer-demo XSS payload corpus.
  3. Shadow mode — sanitize on read, log input-vs-output diffs, enforce nothing. Two weeks of diff review surfaces every over-strip before users see it.
  4. Enforce at render for new content, then backfill stored content via chunked, idempotent queued jobs.
  5. Retire the legacy path (raw {!! !!} on user input, strip_tags, or an older purifier) and delete its config.

Compatibility. Construct the Sanitizer once and bind it as a singleton — it is stateless after construction. Keep closures out of cached config so Behavior is reproducible under config:cache. Under Octane, never mutate Tag/Attr objects at request time.

Sequencing. Week 1: corpus inventory, policy draft, test corpus. Week 2: shadow mode and diff instrumentation. Week 3: enforce on new writes. Week 4: backfill and retire legacy. Roughly one engineer for 2–3 weeks including security review.

Operational Impact

Maintenance. Small code footprint, but a real lifecycle obligation. Watch GitHub releases and the TYPO3 security advisory channel; configure Dependabot/Renovate with the package ungrouped so security patches land as individual, reviewable PRs. Expect 2–5 releases a year, at least one security-relevant. Pin with ~2.3.0 and treat patch bumps as high-priority, test-covered changes. The Behavior policy becomes a living config artifact co-owned by security and product — every newly allowed tag is a security decision, not a formatting one.

Support. Community-only; no vendor SLA. Escalation is the TYPO3 Security Team or GitHub private advisories. Acceptable for internal and standard commercial use; a genuine gap if the product sits under a customer security SLA requiring vendor-backed support. In that case, budget for internal ownership via fork, or select a vendor-backed alternative.

Scaling. Stateless and horizontally scalable; cost is per-document CPU in the PHP worker with no I/O. Cache the singleton and never rebuild Behavior per request. The scaling hazard is unbounded input: a multi-megabyte document expands into a large DOM. Enforce an input size cap (e.g. 256 KB) in the validation layer before calling the sanitizer, and run backfills in chunked jobs with explicit memory limits. At high write volume, sanitize on write rather than on every read.

Failure modes.

  • Silent over-stripping — legitimate markup (embeds, data attributes, figure/table structures) disappears with no error. Primary risk; mitigated by shadow mode and diff logging.
  • Silent under-stripping — a permissive Behavior or unanchored regex lets payloads through. Mitigated by the XSS payload regression corpus in CI.
  • Encoding corruption — libxml/DOMDocument can mangle non-ASCII or malformed UTF-8. Requires explicit encoding tests.
  • Denial of service — oversized documents. Mitigated by input caps and request timeouts.
  • Config drift — differing policy across environments producing different render output. Mitigated by versioned config plus a snapshot test.
  • Upgrade breakage — the 2.x line has carried breaking changes. Mitigated by pinning and running goldens on every bump.

Ramp-up. The API itself is under a day for a mid-level PHP developer; the README example is close to a working integration. The real effort is the policy: 2–4 days to author, security-review, and validate an allow-list against a real corpus, plus ongoing review whenever content types change. No specialist knowledge is required beyond standard XSS literacy — and that literacy, not the library, is the gating skill for safe operation.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log