lisowiecw/filament-media-library
Filament Media Library provides a ready-to-use media manager for Filament panels: upload, browse, search, and organize files, then attach media to Eloquent models. It simplifies handling images and documents in admin resources with an intuitive interface.
enshrined/svg-sanitize bump to ^1.0 closes four unpatched advisories (stored XSS via DTD entity/HMTL5 named-character collision, libxml DoS via DTD attribute declaration, mixed-case xlink:HrEf bypassing the <use> nesting check, and CSS injection). For any product that lets end users upload SVG and serves it back to other users, this is the difference between "we sanitize" as a claim and "we sanitize" as a fact. The key PM-relevant nuance: composer audit reported clean throughout because Packagist had not ingested the advisories, so this fix is invisible to dependency dashboards. That is an argument for treating upload-surface dependencies as a reviewed list rather than trusting automated audit alone.<!DOCTYPE> is stripped before parsing, so SVGs that reference a custom entity are now refused with a named file, where before they were silently stored with the entity expanded away. Declaring-but-not-using an entity still passes; a doctype with no declarations still passes. Remote references are now caught in more places (bare remote href/src, unquoted url(), url() among other declarations in a style attribute — costing the whole attribute — and remote @import/url() inside <style> text), while local /x and fragment #x references survive. This is a changed default about what is refused, and it needs a product answer: how do we tell a user whose icon set no longer uploads, and what do we tell them to do (re-export without the custom entity; make the remote reference local).0.22 produced. If you have a media library with historical uploads and you actually rely on the sanitation guarantee, "re-upload to get the stricter pass" is a product/ops task (bulk re-upload, or accept residual risk). ADR 5 notes the privacy residual the Strict pass was written for is now largely closed upstream, but keeps Strict in force — so no relaxation decision is needed now.MediaPicker::upload() removal is internal-only and not on the promised surface.thumbnailUsing() and asked once per asset, rather than the library grid and a picker's attached items each assembling a card from five modules. Fewer redundant hash requests per tile. One behaviour converges on the grid's: a non-image asset beside the field is now a bare item, where a field with its own thumbnailUsing() previously asked it to paint one, and neighbouring items no longer wait on a rendering that can never arrive. That is the reason this is a minor and not a patch — if you have custom thumbnail rules that assume they'll be consulted for non-images, check them.TenantReach), shared by picker validation and AttachmentReconciler. Product consequence: what the picker offers is what a reconcile accepts, and a condition added to the rule lands on both paths or neither — no drift. Two operational changes follow. First, an application with no tenant resolver configured now gets the rule where it had none: an attach from application code, a queued job, or a seeder previously fell through to a foreign key error and now raises AttachRefused naming what the package will not do. If you were catching QueryException around attaches, expect the new exception instead. Second, programmatic reconciles asking for an id that names no live asset get AttachRefused::unknownAsset() rather than a spurious tenant mismatch; it's a second named constructor on the same class, so existing catch (AttachRefused $e) still catches both. The picker deliberately keeps one wording for every refusal, because distinguishing them would reveal whether an asset the viewer cannot reach exists (ADR 7) — don't "improve" that copy.Adopt when:
1.0 upstream allowlist is the strongest argument for the package. If you are rolling your own SVG handling, this release is the case study for why you shouldn't.Look elsewhere or defer when:
MediaPicker::upload(), LibraryGrid::thumbnailUsing(), pollable(), isPollable(), MediaPicker::getThumbnailUrl() and paintsThroughPipeline() have all been removed as internals in this release. Fine if you only configure fields; a problem if you subclass or call in.QueryException (rather than AttachRefused) surfacing from attaches in a non-tenanted app, or on a tenant mismatch being reported for an id that simply doesn't exist.To executives: This release closes four known security holes in how we clean user-uploaded SVG images — including a stored cross-site-scripting vector — by moving to a patched upstream sanitiser. It is the kind of fix our dependency scanner could not flag, so it also justifies treating the upload path as a reviewed surface. Alongside that it fixes a genuinely annoying UX behaviour (dropping a new cover image onto a filled field used to be refused; it now replaces), removes orphaned uploads from an over-full gallery confirm, and fixes a bug where a soft-deleted asset blocked every subsequent save of the record it sat on.
To engineering: The enshrined/svg-sanitize constraint moves ^0.22 → ^1.0 and is dropped, not widened to ^0.22||^1.0, because leaving 0.22 resolvable leaves the advisories resolvable. Treat this as a changed default, not housekeeping: <!DOCTYPE> is stripped pre-parse, so entity-referencing SVGs are refused by name; remote-reference matching is generalised and reaches bare remote href/src, unquoted url(), a remote url() among other declarations in a style attribute (whole attribute dropped), and remote @import/url() in <style> text; href cleaning is no longer skipped when href and xlink:href coexist and is case-insensitive; element-dense SVGs are no longer quadratic. Sanitizing still runs once at upload on the bytes about to be written, and the Strict pass on public placement still drops embedded images, <style> blocks and links. Nothing is re-sanitized at rest — re-upload is the migration. Separately, three internal refactors land: Drop intake (one module behind the three Drop surfaces; replacing-on-drop for single selection; per-file refusal absorption; Upload tab now room-checked), Card painting (one assembly per field, asked once per asset; non-image assets beside the field are now bare items, matching the grid — hence minor, not patch), and TenantReach as the single attach rule shared by picker validation and AttachmentReconciler. Two things to watch in integration: non-tenanted apps now get AttachRefused where they previously got a foreign key QueryException, and programmatic reconciles get AttachRefused::unknownAsset() for ids naming no live asset. The removed methods listed above are all off the promised surface; if we call or subclass them, that's our debt to clear in this upgrade.
How can I help you explore Laravel packages today?