From 095234460382d030b2b2332a030e005372310598 Mon Sep 17 00:00:00 2001 From: fox Date: Mon, 1 Apr 2024 19:33:45 +0000 Subject: [PATCH] Sanitise Content-Type of uploads --- config/config.exs | 3 ++- config/description.exs | 13 +++++++++++++ lib/pleroma/web/plugs/uploaded_media.ex | 22 ++++++++++++++++++++-- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/config/config.exs b/config/config.exs index e11c774e5..876d25c26 100644 --- a/config/config.exs +++ b/config/config.exs @@ -66,7 +66,8 @@ config :pleroma, Pleroma.Upload, proxy_remote: false, filename_display_max_length: 30, default_description: nil, - base_url: nil + base_url: nil, + allowed_mime_types: ["image", "audio", "video"] config :pleroma, Pleroma.Uploaders.Local, uploads: "uploads" diff --git a/config/description.exs b/config/description.exs index 6cceaeb51..53e26bcb8 100644 --- a/config/description.exs +++ b/config/description.exs @@ -105,6 +105,19 @@ config :pleroma, :config_description, [ "https://cdn-host.com" ] }, + %{ + key: :allowed_mime_types, + label: "Allowed MIME types", + type: {:list, :string}, + description: + "List of MIME (main) types uploads are allowed to identify themselves with. Other types may still be uploaded, but will identify as a generic binary to clients. WARNING: Loosening this over the defaults can lead to security issues. Removing types is safe, but only add to the list if you are sure you know what you are doing.", + suggestions: [ + "image", + "audio", + "video", + "font" + ] + }, %{ key: :proxy_remote, type: :boolean, diff --git a/lib/pleroma/web/plugs/uploaded_media.ex b/lib/pleroma/web/plugs/uploaded_media.ex index cccbfe350..e0a862cf7 100644 --- a/lib/pleroma/web/plugs/uploaded_media.ex +++ b/lib/pleroma/web/plugs/uploaded_media.ex @@ -28,7 +28,9 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do |> Keyword.put(:at, "/__unconfigured_media_plug") |> Plug.Static.init() - %{static_plug_opts: static_plug_opts} + allowed_mime_types = Pleroma.Config.get([Pleroma.Upload, :allowed_mime_types]) + + %{static_plug_opts: static_plug_opts, allowed_mime_types: allowed_mime_types} end def call(%{request_path: <<"/", @path, "/", file::binary>>} = conn, opts) do @@ -68,13 +70,29 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do defp media_is_banned(_, _), do: false + defp get_safe_mime_type(%{allowed_mime_types: allowed_mime_types} = _opts, mime) do + [maintype | _] = String.split(mime, "/", parts: 2) + if maintype in allowed_mime_types, do: mime, else: "application/octet-stream" + end + + defp set_content_type(conn, opts, filepath) do + real_mime = MIME.from_path(filepath) + clean_mime = get_safe_mime_type(opts, real_mime) + put_resp_header(conn, "content-type", clean_mime) + end + + defp get_media(conn, {:static_dir, directory}, opts) do static_opts = Map.get(opts, :static_plug_opts) |> Map.put(:at, [@path]) |> Map.put(:from, directory) + |> Map.put(:set_content_type, false) - conn = Plug.Static.call(conn, static_opts) + conn = + conn + |> set_content_type(opts, conn.request_path) + |> Pleroma.Web.Plugs.StaticNoCT.call(static_opts) if conn.halted do conn