Skip to content

Security ​

This page lists what Media Library Pro checks, so you can judge what to add on top. Each statement matches the shipped code and is covered by the package's test suite.

Authorization ​

Every action goes through Laravel policies. MediaItemPolicy and MediaFolderPolicy are registered unless your app defines its own for the models.

  • Shared files are open to every user who can reach the library. Files marked Only me are limited to their uploader and to users who pass the viewPrivate ability.
  • Uploads need create. Replacing a file needs update on that file.
  • The library page and the picker modal need viewAny. The panel plugin's canAccess() also gates the page and the upload routes.
  • Deleting a folder that holds someone else's private content, or moving a folder into one the user cannot see, is refused.
  • Folders given to the picker with folder() are only resolved when the user can see them.

See Authorization for every ability and how to override it.

Uploads ​

Uploads arrive in chunks, and the server checks each stage.

CheckWhat it does
ExtensionBefore any data is stored, the file name must have a plain extension that is not on upload.blocked_extensions. Trailing dots and spaces are trimmed, so shell.php. is still blocked. Files with no extension are refused.
Content sniffingAfter assembly, the file's real MIME type is detected from its bytes with finfo. It must match upload.accepted_mime_types, so a renamed executable does not pass as photo.jpg.
SizeThe declared and assembled size must be within upload.max_file_size.
QuotaThe upload must fit the remaining quota. Previous versions count towards it.
File namesNames are slugged by default. Inner extensions are never kept, so shell.php.png is stored as shell-php.png.
SVGWith upload.sanitize_svg on (the default), scripts, event handlers and remote references are removed. An SVG that cannot be cleaned is refused.

The default blocked_extensions list covers server scripts (php, phtml, phar, py, rb, jsp, asp), executables and shell files (exe, sh, bat, ps1, jar), and browser-renderable files (html, htm, xhtml, js, mjs, xml, xsl, svgz, swf). Edit it in config/filament-media-library.php.

Chunk handling ​

  • The first chunk must come first. A chunk that skips it is refused and nothing is written.
  • Every later chunk must match the file name, total size and chunk count declared by the first.
  • A chunk may not be larger than the configured chunk size, and the parts together may not exceed the declared size.
  • Each person can have at most 20 unfinished uploads. Finished uploads and duplicates do not count.
  • Chunks are kept in a folder per user. Folders untouched for 24 hours are removed by media-library:prune.
  • The upload routes require an authenticated user and are throttled to 600 requests a minute.

URL import ​

Import from URL downloads a file from a link a user types, so it is guarded against server-side request forgery.

  • Only http and https links are accepted.
  • The host is resolved first. Every address it resolves to must be public. Loopback, private ranges, link-local addresses (including cloud metadata addresses), carrier-grade NAT, IPv4-mapped and NAT64 IPv6 addresses, and documentation ranges are refused.
  • The request connects to the address that was checked (DNS pinning), so a second DNS answer cannot redirect it.
  • Redirects are followed manually, up to three times, and every hop is checked again.
  • The download has a 30 second timeout and stops as soon as it passes upload.max_file_size.
  • The downloaded file then goes through the same checks as any upload.
  • Files are stored under a random UUID folder, so URLs cannot be guessed from sequential ids.
  • Private files are never given a permanent link. They get short-lived signed links, and the serve route refuses a signed link without an expiry for a private file.
  • The serve route refuses trashed files and invalid signatures, and sends X-Content-Type-Options: nosniff and a restrictive Content-Security-Policy.
  • The image editor receives a fresh link, and signed links are never altered after signing.
  • Rich text embeds use non-expiring signed links for non-public disks, and never for private files. See Rich Editor.

Signed links depend on your APP_KEY. Keep it secret.

Tenants and private files ​

  • Folders, files and tags are filtered by tenant on every query when tenancy is on. Picker validation, attachments and the rich editor reject items from another tenant. See Tenancy.
  • Duplicate detection ignores files from other tenants.
  • Private files are filtered out of picker validation for users who cannot see them. See Private Files.

Livewire state ​

The library and the picker lock their configuration with Livewire's #[Locked] attribute: the folder, page size, active file, accepted types, selection limits, layout and the rest. A visitor who edits that state in the browser gets an exception. Sort order goes through a validated method, and tag names typed by users are treated as names, never as ids.

Standalone mode ​

Using the library outside Filament panels is off by default. Until you enable standalone.enabled, the components return 403 and the upload and download routes return 404. See Outside Panels. Before you enable it, register a policy that fits your users.

What we do not do ​

  • No virus scanning. Files are checked by type and content sniffing, not scanned for malware. If you need it, scan chunks or stored files with your own pipeline, for example on the MediaItemUploaded event.
  • No EXIF stripping. Photos keep the metadata they were uploaded with, including location data. The inspector shows a short list of camera fields, but the file on disk is unchanged.
  • No protection for public disks. On a public disk the file sits in a web-readable folder. Anyone with the exact URL can open it, even if the file is marked Only me. Use a private disk for confidential files. See Storage.
  • No content moderation. The library does not look at what an image shows.
  • No policy for you. The default policy is permissive for signed-in users. Write your own for any site where users are not all trusted.

Reporting a vulnerability ​

Email security@hoceine.com with a description, the version you tested and steps to reproduce. Please do not open a public issue or post details until a fix is available.

Commercial licence. One licence per production project. Terms · Privacy · Refunds