This commit is contained in:
Lain Soykaf 2025-03-10 16:48:54 +04:00
parent edcd816730
commit b469b9d9d3
6 changed files with 83 additions and 3 deletions

View file

@ -0,0 +1 @@
Fix content-type spoofing vulnerability that could allow users to upload ActivityPub objects as attachments

View file

@ -65,7 +65,8 @@ config :pleroma, Pleroma.Upload,
proxy_remote: false, proxy_remote: false,
filename_display_max_length: 30, filename_display_max_length: 30,
default_description: nil, default_description: nil,
base_url: nil base_url: nil,
allowed_mime_types: ["image", "audio", "video"]
config :pleroma, Pleroma.Uploaders.Local, uploads: "uploads" config :pleroma, Pleroma.Uploaders.Local, uploads: "uploads"

View file

@ -117,6 +117,19 @@ config :pleroma, :config_description, [
key: :filename_display_max_length, key: :filename_display_max_length,
type: :integer, type: :integer,
description: "Set max length of a filename to display. 0 = no limit. Default: 30" description: "Set max length of a filename to display. 0 = no limit. Default: 30"
},
%{
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"
]
} }
] ]
}, },

View file

@ -11,6 +11,7 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do
require Logger require Logger
alias Pleroma.Web.MediaProxy alias Pleroma.Web.MediaProxy
alias Pleroma.Web.Plugs.Utils
@behaviour Plug @behaviour Plug
# no slashes # no slashes
@ -28,7 +29,9 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do
|> Keyword.put(:at, "/__unconfigured_media_plug") |> Keyword.put(:at, "/__unconfigured_media_plug")
|> Plug.Static.init() |> 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 end
def call(%{request_path: <<"/", @path, "/", file::binary>>} = conn, opts) do def call(%{request_path: <<"/", @path, "/", file::binary>>} = conn, opts) do
@ -69,13 +72,23 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do
defp media_is_banned(_, _), do: false defp media_is_banned(_, _), do: false
defp set_content_type(conn, opts, filepath) do
real_mime = MIME.from_path(filepath)
clean_mime = Utils.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 defp get_media(conn, {:static_dir, directory}, _, opts) do
static_opts = static_opts =
Map.get(opts, :static_plug_opts) Map.get(opts, :static_plug_opts)
|> Map.put(:at, [@path]) |> Map.put(:at, [@path])
|> Map.put(:from, directory) |> Map.put(:from, directory)
|> Map.put(:content_type, false)
conn = Plug.Static.call(conn, static_opts) conn =
conn
|> set_content_type(opts, conn.request_path)
|> Plug.Static.call(static_opts)
if conn.halted do if conn.halted do
conn conn

View file

@ -0,0 +1,14 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Plugs.Utils do
@moduledoc """
Some helper functions shared across several plugs
"""
def 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
end

View file

@ -0,0 +1,38 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Plugs.UploadedMediaTest do
use Pleroma.Web.ConnCase, async: false
alias Pleroma.StaticStubbedConfigMock
alias Pleroma.Web.Plugs.Utils
setup do
Mox.stub_with(StaticStubbedConfigMock, Pleroma.Test.StaticConfig)
{:ok, %{}}
end
describe "content-type sanitization with Utils.get_safe_mime_type/2" do
test "it allows safe MIME types" do
opts = %{allowed_mime_types: ["image", "audio", "video"]}
assert Utils.get_safe_mime_type(opts, "image/jpeg") == "image/jpeg"
assert Utils.get_safe_mime_type(opts, "audio/mpeg") == "audio/mpeg"
assert Utils.get_safe_mime_type(opts, "video/mp4") == "video/mp4"
end
test "it sanitizes potentially dangerous content-types" do
opts = %{allowed_mime_types: ["image", "audio", "video"]}
assert Utils.get_safe_mime_type(opts, "application/activity+json") ==
"application/octet-stream"
assert Utils.get_safe_mime_type(opts, "text/html") == "application/octet-stream"
assert Utils.get_safe_mime_type(opts, "application/javascript") ==
"application/octet-stream"
end
end
end