diff options
author | Lain Soykaf <lain@lain.com> | 2025-03-10 17:23:21 +0400 |
---|---|---|
committer | Lain Soykaf <lain@lain.com> | 2025-03-10 17:23:21 +0400 |
commit | 1dd9ba5d6fa45a8965703c96e9823ac7e41c52be (patch) | |
tree | f692932b4c69d5d4aec51d937bf6e854236f540a /test | |
parent | b469b9d9d358a30642d1221a01125af9b6399ff4 (diff) | |
download | pleroma-1dd9ba5d6fa45a8965703c96e9823ac7e41c52be.tar.gz pleroma-1dd9ba5d6fa45a8965703c96e9823ac7e41c52be.zip |
Sanitize media uploads.
Diffstat (limited to 'test')
-rw-r--r-- | test/pleroma/web/mastodon_api/controllers/media_controller_test.exs | 89 | ||||
-rw-r--r-- | test/pleroma/web/plugs/uploaded_media_test.exs | 31 |
2 files changed, 112 insertions, 8 deletions
diff --git a/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs index 3f696d94d..ae86078d7 100644 --- a/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs @@ -227,4 +227,93 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do |> json_response_and_validate_schema(403) end end + + describe "Content-Type sanitization" do + setup do: oauth_access(["write:media", "read:media"]) + + setup do + ConfigMock + |> stub_with(Pleroma.Test.StaticConfig) + + config = + Pleroma.Config.get([Pleroma.Upload]) + |> Keyword.put(:uploader, Pleroma.Uploaders.Local) + + clear_config([Pleroma.Upload], config) + clear_config([Pleroma.Upload, :allowed_mime_types], ["image", "audio", "video"]) + + # Create a file with a malicious content type and dangerous extension + malicious_file = %Plug.Upload{ + content_type: "application/activity+json", + path: Path.absname("test/fixtures/image.jpg"), + # JSON extension to make MIME.from_path detect application/json + filename: "malicious.json" + } + + [malicious_file: malicious_file] + end + + test "sanitizes malicious content types when serving media", %{ + conn: conn, + malicious_file: malicious_file + } do + # First upload the file with the malicious content type + media = + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/v1/media", %{"file" => malicious_file}) + |> json_response_and_validate_schema(:ok) + + # Get the file URL from the response + url = media["url"] + + # Now make a direct request to the media URL and check the content-type header + response = + build_conn() + |> get(URI.parse(url).path) + + # Find the content-type header + content_type_header = + Enum.find(response.resp_headers, fn {name, _} -> name == "content-type" end) + + # The server should detect the application/json MIME type from the .json extension + # and replace it with application/octet-stream since it's not in allowed_mime_types + assert content_type_header == {"content-type", "application/octet-stream"} + + # Verify that the file was still served correctly + assert response.status == 200 + end + + test "allows safe content types", %{conn: conn} do + safe_image = %Plug.Upload{ + content_type: "image/jpeg", + path: Path.absname("test/fixtures/image.jpg"), + filename: "safe_image.jpg" + } + + # Upload a file with a safe content type + media = + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/v1/media", %{"file" => safe_image}) + |> json_response_and_validate_schema(:ok) + + # Get the file URL from the response + url = media["url"] + + # Make a direct request to the media URL and check the content-type header + response = + build_conn() + |> get(URI.parse(url).path) + + # The server should preserve the image/jpeg MIME type since it's allowed + content_type_header = + Enum.find(response.resp_headers, fn {name, _} -> name == "content-type" end) + + assert content_type_header == {"content-type", "image/jpeg"} + + # Verify that the file was served correctly + assert response.status == 200 + end + end end diff --git a/test/pleroma/web/plugs/uploaded_media_test.exs b/test/pleroma/web/plugs/uploaded_media_test.exs index b260fd03b..69affa019 100644 --- a/test/pleroma/web/plugs/uploaded_media_test.exs +++ b/test/pleroma/web/plugs/uploaded_media_test.exs @@ -3,17 +3,10 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Plugs.UploadedMediaTest do - use Pleroma.Web.ConnCase, async: false + use ExUnit.Case, async: true - 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"]} @@ -34,5 +27,27 @@ defmodule Pleroma.Web.Plugs.UploadedMediaTest do assert Utils.get_safe_mime_type(opts, "application/javascript") == "application/octet-stream" end + + test "it sanitizes ActivityPub 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, "application/ld+json") == "application/octet-stream" + assert Utils.get_safe_mime_type(opts, "application/jrd+json") == "application/octet-stream" + end + + test "it sanitizes other potentially dangerous types" do + opts = %{allowed_mime_types: ["image", "audio", "video"]} + + assert Utils.get_safe_mime_type(opts, "text/html") == "application/octet-stream" + + assert Utils.get_safe_mime_type(opts, "application/javascript") == + "application/octet-stream" + + assert Utils.get_safe_mime_type(opts, "text/javascript") == "application/octet-stream" + assert Utils.get_safe_mime_type(opts, "application/xhtml+xml") == "application/octet-stream" + end end end |