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

tgalopin/html-sanitizer

tgalopin/html-sanitizer is a PHP library for cleaning untrusted HTML safely. It removes dangerous markup to prevent XSS while letting you configure allowed tags, attributes, and extensions, making it easy to display user-generated content securely.

Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • The library's core design — an HTML5-compliant parser plus a whitelist (allow-list) of tags, attributes, and URL protocols — is the correct security posture for rendering user-generated or third-party HTML. Deny-by-default beats regex blacklisting, and this package does not attempt regex sanitization, which is the single largest source of historical XSS bypasses.
  • Sanitization is a pure, stateless transformation (sanitize(string): string-shaped contract) with no framework coupling in the core. That makes it a natural fit as a boundary component: one place in the request/response pipeline where untrusted markup is normalized before storage or render.
  • The extension model (reusable extensions, custom allowed elements) is the right abstraction for a platform: a base policy owned by the security/architecture group, with per-product extensions for permitted markup. This is what a TPM wants to see, because policy drift across teams is the usual failure mode for sanitization.
  • Symfony integration exists, but the package is framework-agnostic at its core, so it does not force a Symfony dependency into a Laravel codebase. In Laravel it would be wired through a service provider and a singleton binding, not consumed directly from controllers.

Integration feasibility

  • Composer-installable, MIT-licensed, no exotic runtime requirements. Integration cost is measured in hours, not sprints.
  • The real work is not the wiring — it is agreeing the policy. Expect the majority of effort in defining the tag/attribute allow-list per content surface (comments vs. CMS body vs. support-ticket HTML) and building a regression corpus of hostile payloads.
  • The masterminds/html5 parser dependency is the largest transitive risk: the sanitizer's robustness is inherited from that parser, not from the sanitizer itself.

Technical risk

  • Archived and unmaintained since 2021-12-15. This is the dominant risk. There will be no upstream fixes for parser-confusion bypasses, no PHP-version compatibility patches, and no coordinated disclosure channel. In a security-sensitive component, "no advisories" does not mean "no vulnerabilities" — it means "no one is looking."
  • Succession risk is manageable but must be planned: the library's lineage was folded into Symfony's own HTML sanitizer (the W3C HTML Sanitizer API-aligned implementation). The migration target exists and is actively maintained, which materially lowers the risk of adopting this package as a bridge but not as a destination.
  • PHP version drift: a 2021-era release predates current PHP minor versions. Deprecation noise and, eventually, hard failures in CI are likely. Verify against the oldest and newest PHP versions actually in the estate before committing.
  • Behavioral risk: sanitizers fail quietly and partially. Stripping a needed attribute can silently break product features (embedded video, tables, anchor targets) long after rollout, with no error surfaced.

Key questions

  1. Do we actually need to render untrusted HTML, or can we accept a restricted Markdown subset and eliminate most of the attack surface?
  2. Are we adopting this as a permanent dependency or as an interim shim ahead of the maintained successor? If permanent, who owns the fork?
  3. What is the sanitizer's role in the trust boundary — does it also run on read (defense in depth) or only on write?
  4. Do we require a W3C Sanitizer API-compatible policy model for future portability?
  5. What is the blast radius of a bypass — stored XSS in an admin console, or in a low-privilege public comment thread?
  6. Is there an existing CSP that limits the consequence of a sanitizer failure? (CSP reduces, but does not remove, the criticality of this decision.)

Integration Approach

Stack fit

  • Laravel: bind the sanitizer as a singleton in a service provider, inject via constructor, and expose one narrow interface (sanitize(string, Policy): string) that the rest of the codebase depends on. Do not let application code instantiate the sanitizer directly — the interface is what makes the eventual swap to the maintained successor a one-file change.
  • Queue/API consumers writing HTML to the database should use the same binding so that the policy is enforced once, consistently, at the write boundary.
  • Blade rendering of already-stored HTML remains the highest-risk sink; enforce that any {!! !!} usage is paired with an explicit, reviewed justification.

Migration path

  • Recommended sequencing: adopt the maintained successor from the outset if there is no hard constraint. The API surface is conceptually identical (parser + allow-list policy + extensions), so the design work transfers wholesale.
  • If this package is chosen for schedule or compatibility reasons, treat it as a contained, single-interface dependency with a documented exit criterion and a dated deprecation ticket. Do not let its policy configuration leak into many call sites.
  • Wrap the policy definitions in framework-native config (Laravel config files or a dedicated policy class) rather than in library-specific extension classes, so policy survives the swap.

Compatibility

  • Pin to an exact version and commit the lock file. Add a CI job that runs the sanitizer test corpus on every PHP upgrade so drift is caught at upgrade time, not in production.
  • Verify the transitive graph of masterminds/html5 and any other dependencies — the transitive tree is where archived-package surprises live.
  • Confirm behavior under the app's string encoding assumptions (UTF-8 throughout, no double-encoding at the storage layer).

Sequencing

  1. Inventory every sink that renders untrusted HTML; enumerate the markup each surface legitimately needs.
  2. Define policies per surface; review with security.
  3. Build the hostile-payload regression corpus (mXSS, protocol obfuscation, malformed nesting, encoding tricks) as an automated test suite.
  4. Integrate behind the interface, with a feature flag.
  5. Canary on the lowest-risk surface; compare stripped-markup diffs against production samples before enabling broadly.
  6. Enable read-path sanitization as defense in depth.
  7. Schedule the successor migration or fork ownership decision as a hard, dated deliverable — not a backlog item.

Operational Impact

Maintenance

  • Assume ownership transfer to the internal team on day one. There is no upstream to escalate to. Budget a recurring, small but permanent allocation for dependency bumps, PHP-version compatibility, and payload-corpus expansion.
  • The maintenance burden is low in volume and high in consequence: the work is mostly "keep the lights on" until the day a new bypass class is published against the underlying parser, at which point it is urgent.
  • Mitigate by maintaining the fork as a thin, patchable shim — the smaller the delta from upstream, the cheaper a security patch is to apply.

Support

  • No vendor support, no SLA, no CVE feed subscriptions tied to the package. Internal security review is the substitute.
  • Document the policy decisions in-repo. The most common support question will be "why did my HTML get stripped?" — a per-policy changelog and a debug mode that reports removed nodes will save substantial triage time.

Scaling

  • Sanitization is CPU-bound parsing on every invocation. For high-volume write paths (comments, chat, imports) this is measurable; benchmark with representative payload sizes rather than assuming.
  • For read-path sanitization on hot pages, the cost multiplies with page views. Options: sanitize once at write time and store the result (preferred), cache sanitized output keyed by content hash, or restrict read-path sanitization to high-risk sinks.
  • Watch for large-payload DoS: pathological input can be expensive to parse. Enforce a maximum input size before the parser sees it.

Failure modes

  • Fail-open (sanitizer errors → raw HTML rendered) is the catastrophic mode. Ensure exceptions fail closed and are alarmed, not swallowed.
  • Over-stripping: feature degradation without errors. Requires content-diff monitoring during rollout.
  • Under-stripping / bypass: requires monitoring and a CSP as a second layer.
  • Config drift: divergent policies across services. Centralize policy config and treat changes as reviewed code.
  • Dependency rot: a PHP upgrade silently changes parser behavior. Caught only by the regression corpus in CI.

Ramp-up

  • Integration: low — hours for a competent Laravel engineer.
  • Policy design: moderate — requires someone who understands the product's markup needs and someone who understands XSS; rarely the same person.
  • Security assurance: high — expect a dedicated review cycle and a payload corpus before trusting it on an admin-facing surface.
  • Successor migration: low if the interface boundary was respected early; high if the library leaked into call sites. This is the single most important architectural decision in the whole engagement, and it costs almost nothing to get right at the start.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core