github awcodes/filament-curator v5.1.5

4 hours ago

Security

Curator's upload components fell back to a default list of accepted file types that included text/html, application/xhtml+xml, text/javascript, application/xml and application/octet-stream. An authenticated user with permission to upload media could upload an HTML file containing a <script> tag. The file was stored unmodified and later served from the application's own origin, executing the script with the session of whoever opened it.

This affected the Media resource form, MultiUploadAction, CuratorPicker and the rich editor's attachment flow, which all share the same default. Applications that already set acceptedFileTypes() themselves — globally or per field — were never affected, because the vulnerable list was only used as a fallback.

The default is now MimeType::defaults(): the full list minus types that are effectively executable content. MimeType::toArray() is unchanged, so code referencing the enum directly still works. As defense in depth, media served through Curator's own route now sends X-Content-Type-Options: nosniff, and restricted types are forced to Content-Disposition: attachment.

If your application genuinely needs to host these types, opt back in explicitly:

use Awcodes\Curator\Enums\MimeType;

Curator::acceptedFileTypes([...MimeType::defaults(), 'text/html']);

Note that Curator only sanitizes SVG uploads. Anything else you allow is stored and served verbatim, and with the default public disk it is also reachable through the storage symlink, where the new response headers do not apply. Serve deliberately-allowed executable types from a private disk.

The 3.x line is not affected — its accepted types come from config('curator.accepted_file_types'), whose default has always been limited to images and PDFs.

Fixed

Glider fallbacks could not be used at all. Several faults compounded:

  • GliderFallback::make() passed the name through the container, but the class has no constructor, so Laravel discarded it. The name stayed null and getName() threw a TypeError, meaning a fallback built exactly as documented failed before it could be registered.
  • The <x-curator-glider> component rejected a null media item, which is the main reason to configure a fallback in the first place. It now accepts null.
  • handleInt() checked the raw id rather than the looked-up record, so the fallback branch never ran and a missing record produced "Attempt to read property path on null" instead. The documented <x-curator-glider :media="1" fallback="thumbnail"/> could not work.

Fallback resolution now happens in one place, so a null media item, an id that does not resolve, and a blank string all reach it. An unregistered fallback name, or one with no source, no longer dereferences null.

Also fixed while in there:

  • GliderFallback's optional getters were typed non-nullable while every property defaults to null, so a partially configured fallback threw. They are nullable now.
  • GliderFallback::isPreviewable() called Curator::isResizable(), reporting svg sources as not previewable.

Thanks to @battulga0719 for reporting the fallback issues in #717.

Don't miss a new filament-curator release

NewReleases is sending notifications on new releases.