From 1af8997462c52e52c72be436aee990621b692dd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nicole=20miko=C5=82ajczyk?= Date: Fri, 16 Jan 2026 21:32:35 +0100 Subject: [PATCH 01/11] do not ever allow setting database_config_whitelist to database MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: nicole mikołajczyk --- lib/pleroma/web/admin_api/controllers/config_controller.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pleroma/web/admin_api/controllers/config_controller.ex b/lib/pleroma/web/admin_api/controllers/config_controller.ex index 2c9c27294..f3adeb35a 100644 --- a/lib/pleroma/web/admin_api/controllers/config_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/config_controller.ex @@ -174,6 +174,8 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do end end + defp whitelisted_config?(:pleroma, :database_config_whitelist), do: false + defp whitelisted_config?(group, key) do if whitelisted_configs = Config.get(:database_config_whitelist) do Enum.any?(whitelisted_configs, fn From 57a3b1f6d0069934cc564c192dd46e834be8497e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nicole=20miko=C5=82ajczyk?= Date: Fri, 16 Jan 2026 21:33:14 +0100 Subject: [PATCH 02/11] Add sane defaults for :database_config_whitelist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: nicole mikołajczyk --- config/config.exs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/config/config.exs b/config/config.exs index 683805fe3..5bf2c5c2e 100644 --- a/config/config.exs +++ b/config/config.exs @@ -960,6 +960,15 @@ config :pleroma, Pleroma.Search.QdrantSearch, vectors: %{size: 384, distance: "Cosine"} } +config :pleroma, :database_config_whitelist, [ + {:pleroma}, + {:cors_plug}, + {:ex_aws, :s3}, + {:mime}, + {:prometheus, Pleroma.Web.Endpoint.MetricsExporter}, + {:web_push_encryption, :vapid_details} +] + # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. import_config "#{Mix.env()}.exs" From f0669997d30d79fc2d93e7bbadbb8f6fd418cc03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nicole=20miko=C5=82ajczyk?= Date: Fri, 16 Jan 2026 21:34:06 +0100 Subject: [PATCH 03/11] Add test for default whitelist config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: nicole mikołajczyk --- .../web/admin_api/controllers/config_controller_test.exs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/pleroma/web/admin_api/controllers/config_controller_test.exs b/test/pleroma/web/admin_api/controllers/config_controller_test.exs index e12115ea1..ab216e49f 100644 --- a/test/pleroma/web/admin_api/controllers/config_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/config_controller_test.exs @@ -1472,5 +1472,13 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do web_endpoint = Enum.find(children, fn c -> c["key"] == "Pleroma.Upload" end) assert web_endpoint["children"] end + + test "all keys from description are whitelisted", %{conn: conn} do + conn = get(conn, "/api/pleroma/admin/config/descriptions") + + assert response = json_response_and_validate_schema(conn, 200) + + assert length(response) == length(Pleroma.Docs.JSON.compiled_descriptions()) + end end end From b66b93a94ada205c710f1e93efe7a984485ae43d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nicole=20miko=C5=82ajczyk?= Date: Fri, 16 Jan 2026 21:34:45 +0100 Subject: [PATCH 04/11] Add task for filtering non-whitelisted configs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: nicole mikołajczyk --- changelog.d/database-config-whitelist.add | 1 + docs/administration/CLI_tasks/config.md | 16 ++++++- lib/mix/tasks/pleroma/config.ex | 56 +++++++++++++++++++++++ test/mix/tasks/pleroma/config_test.exs | 18 ++++++++ 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 changelog.d/database-config-whitelist.add diff --git a/changelog.d/database-config-whitelist.add b/changelog.d/database-config-whitelist.add new file mode 100644 index 000000000..a78960c98 --- /dev/null +++ b/changelog.d/database-config-whitelist.add @@ -0,0 +1 @@ +Add reasonable defaults for :database_config_whitelist \ No newline at end of file diff --git a/docs/administration/CLI_tasks/config.md b/docs/administration/CLI_tasks/config.md index 13d671a7e..35e02145e 100644 --- a/docs/administration/CLI_tasks/config.md +++ b/docs/administration/CLI_tasks/config.md @@ -169,4 +169,18 @@ This forcibly removes any enabled MRF that does not exist and will fix the abili === "From Source" ```sh mix pleroma.config fix_mrf_policies - ``` \ No newline at end of file + ``` + +## Remove non-whitelisted configs from the database + +This removes any configuration value that is not explicitly whitelisted by `:pleroma, :database_config_whitelist`. Might be useful after updating the whitelist. + +=== "OTP" + ```sh + ./bin/pleroma_ctl config filter_whitelisted + ``` + +=== "From Source" + ```sh + mix pleroma.config filter_whitelisted + ``` diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 834b4fe14..fc6982ea8 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -234,6 +234,57 @@ defmodule Mix.Tasks.Pleroma.Config do end) end + # Removes non-whitelisted configuration sections + def run(["filter_whitelisted" | rest]) do + {options, [], []} = + OptionParser.parse( + rest, + strict: [force: :boolean], + aliases: [f: :force] + ) + + force = Keyword.get(options, :force, false) + + start_pleroma() + + whitelisted_configs = Pleroma.Config.get(:database_config_whitelist) + + whitelisted_groups = + whitelisted_configs + |> Enum.filter(fn + {_group} -> true + _ -> false + end) + |> Enum.map(fn {group} -> group end) + + whitelisted_keys = + whitelisted_configs + |> Enum.filter(fn + {_group, _key} -> true + _ -> false + end) + + filtered = + from(c in ConfigDB) + |> Repo.all() + |> Enum.filter(¬_whitelisted?(&1, whitelisted_groups, whitelisted_keys)) + + if not Enum.empty?(filtered) do + shell_info("The following settings will be removed from ConfigDB:\n") + Enum.each(filtered, &dump(&1)) + + if force or shell_prompt("Are you sure you want to continue?", "n") in ~w(Yn Y y) do + filtered_ids = Enum.map(filtered, fn %{id: id} -> id end) + + Repo.delete_all(from(c in ConfigDB, where: c.id in ^filtered_ids)) + else + shell_error("No changes made.") + end + else + shell_error("No unwanted settings in ConfigDB. No changes made.") + end + end + @spec migrate_to_db(Path.t() | nil) :: any() def migrate_to_db(file_path \\ nil) do with :ok <- Pleroma.Config.DeprecationWarnings.warn() do @@ -434,4 +485,9 @@ defmodule Mix.Tasks.Pleroma.Config do Ecto.Adapters.SQL.query!(Repo, "TRUNCATE config;") Ecto.Adapters.SQL.query!(Repo, "ALTER SEQUENCE config_id_seq RESTART;") end + + defp not_whitelisted?(%{group: group, key: key}, whitelisted_groups, whitelisted_keys) do + not Enum.member?(whitelisted_groups, group) and + not Enum.member?(whitelisted_keys, {group, key}) + end end diff --git a/test/mix/tasks/pleroma/config_test.exs b/test/mix/tasks/pleroma/config_test.exs index 942cfa83d..3b1037f0a 100644 --- a/test/mix/tasks/pleroma/config_test.exs +++ b/test/mix/tasks/pleroma/config_test.exs @@ -329,5 +329,23 @@ defmodule Mix.Tasks.Pleroma.ConfigTest do assert config_records() == [] end + + test "filters non-whitelisted settings" do + clear_config(:database_config_whitelist, [ + {:pleroma}, + {:web_push_encryption, :vapid_details} + ]) + + insert_config_record(:web_push_encryption, :non_whitelisted_key, a: 1) + insert_config_record(:web_push_encryption, :vapid_details, b: 1) + + MixTask.run(["filter_whitelisted", "--force"]) + + assert [ + %ConfigDB{group: :pleroma, key: :instance}, + %ConfigDB{group: :pleroma, key: Pleroma.Captcha}, + %ConfigDB{group: :web_push_encryption, key: :vapid_details} + ] = config_records() + end end end From 92fd157cd82f487899e451635d1b4a94560062b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nicole=20miko=C5=82ajczyk?= Date: Fri, 16 Jan 2026 21:35:53 +0100 Subject: [PATCH 05/11] Update cheatsheet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: nicole mikołajczyk --- docs/configuration/cheatsheet.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 54dd4a5f0..b156c74cf 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -1132,8 +1132,9 @@ Boolean, enables/disables in-database configuration. Read [Transferring the conf List of valid configuration sections which are allowed to be configured from the database. Settings stored in the database before the whitelist is configured are -still applied, so it is suggested to only use the whitelist on instances that -have not migrated the config to the database. +still applied. Consider running the `mix pleroma.config filter_whitelisted` task +after updating the whitelist. Read [Remove non-whitelisted configs from the database](../administration//CLI_tasks/config.md#remove-non-whitelisted-configs-from-the-database) +for more information. Example: ```elixir From 49985b1614467120f1585f9590f5fc7c5c363eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nicole=20miko=C5=82ajczyk?= Date: Fri, 16 Jan 2026 21:37:02 +0100 Subject: [PATCH 06/11] Update tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: nicole mikołajczyk --- .../controllers/config_controller_test.exs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/pleroma/web/admin_api/controllers/config_controller_test.exs b/test/pleroma/web/admin_api/controllers/config_controller_test.exs index ab216e49f..7cb4ec938 100644 --- a/test/pleroma/web/admin_api/controllers/config_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/config_controller_test.exs @@ -194,6 +194,16 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do setup do: clear_config(:configurable_from_database, true) + setup do: + clear_config(:database_config_whitelist, [ + {:pleroma}, + {:http}, + {:idna}, + {:oban}, + {:tesla}, + {:ueberauth} + ]) + test "create new config setting in db", %{conn: conn} do ueberauth = Application.get_env(:ueberauth, Ueberauth) on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end) @@ -807,7 +817,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do %{ "tuple" => [ "/websocket", - "Phoenix.Endpoint.CowboyWebSocket", + ":sth", %{ "tuple" => [ "Phoenix.Transports.WebSocket", @@ -871,7 +881,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do %{ "tuple" => [ "/websocket", - "Phoenix.Endpoint.CowboyWebSocket", + ":sth", %{ "tuple" => [ "Phoenix.Transports.WebSocket", From 77a1d79f92398476a081c3adcca8d227035e6f21 Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Sat, 17 Jan 2026 12:31:35 +0400 Subject: [PATCH 07/11] ConfigTest: Don't crash when whitelist is unset / disabled --- test/mix/tasks/pleroma/config_test.exs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/mix/tasks/pleroma/config_test.exs b/test/mix/tasks/pleroma/config_test.exs index 3b1037f0a..ef1adc235 100644 --- a/test/mix/tasks/pleroma/config_test.exs +++ b/test/mix/tasks/pleroma/config_test.exs @@ -347,5 +347,21 @@ defmodule Mix.Tasks.Pleroma.ConfigTest do %ConfigDB{group: :web_push_encryption, key: :vapid_details} ] = config_records() end + + test "filter_whitelisted doesn't crash when whitelist is unset" do + clear_config(:database_config_whitelist, nil) + + existing = config_records() + MixTask.run(["filter_whitelisted", "--force"]) + assert config_records() == existing + end + + test "filter_whitelisted doesn't crash when whitelist is disabled" do + clear_config(:database_config_whitelist, false) + + existing = config_records() + MixTask.run(["filter_whitelisted", "--force"]) + assert config_records() == existing + end end end From 0b871ff1f298d84c7b3c12444ee923bcfb1ac02a Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Sat, 17 Jan 2026 12:32:10 +0400 Subject: [PATCH 08/11] ConfigController: Don't allow updating the whitelist --- .../controllers/config_controller_test.exs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/pleroma/web/admin_api/controllers/config_controller_test.exs b/test/pleroma/web/admin_api/controllers/config_controller_test.exs index 7cb4ec938..e62d95fad 100644 --- a/test/pleroma/web/admin_api/controllers/config_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/config_controller_test.exs @@ -1220,6 +1220,31 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do assert Application.get_env(:not_real, :anything) == "value6" end + test "doesn't allow updating the database_config_whitelist itself", %{conn: conn} do + original_whitelist = Pleroma.Config.get(:database_config_whitelist) + + refute ConfigDB.get_by_group_and_key(:pleroma, :database_config_whitelist) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/config", %{ + configs: [ + %{ + group: ":pleroma", + key: ":database_config_whitelist", + value: [%{"tuple" => [":pleroma", ":key1"]}] + } + ] + }) + + %{"configs" => configs} = json_response_and_validate_schema(conn, 200) + + assert configs == [] + assert Pleroma.Config.get(:database_config_whitelist) == original_whitelist + refute ConfigDB.get_by_group_and_key(:pleroma, :database_config_whitelist) + end + test "args for Pleroma.Upload.Filter.Mogrify with custom tuples", %{conn: conn} do assert conn |> put_req_header("content-type", "application/json") From 49f9ab3034b9809c53369cf0ade33dac8409faa4 Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Sat, 17 Jan 2026 13:02:18 +0400 Subject: [PATCH 09/11] Cheatsheet: Fix double slash --- docs/configuration/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index b156c74cf..9efa1c8b3 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -1133,7 +1133,7 @@ Boolean, enables/disables in-database configuration. Read [Transferring the conf List of valid configuration sections which are allowed to be configured from the database. Settings stored in the database before the whitelist is configured are still applied. Consider running the `mix pleroma.config filter_whitelisted` task -after updating the whitelist. Read [Remove non-whitelisted configs from the database](../administration//CLI_tasks/config.md#remove-non-whitelisted-configs-from-the-database) +after updating the whitelist. Read [Remove non-whitelisted configs from the database](../administration/CLI_tasks/config.md#remove-non-whitelisted-configs-from-the-database) for more information. Example: From 117b0bd79ed21338a46a558061cc54e86313f5b5 Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Sat, 17 Jan 2026 13:03:02 +0400 Subject: [PATCH 10/11] Config: Don't crash on falsy whitelist config --- lib/mix/tasks/pleroma/config.ex | 68 +++++++++++++++++---------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index fc6982ea8..c5f2e9b0a 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -249,39 +249,43 @@ defmodule Mix.Tasks.Pleroma.Config do whitelisted_configs = Pleroma.Config.get(:database_config_whitelist) - whitelisted_groups = - whitelisted_configs - |> Enum.filter(fn - {_group} -> true - _ -> false - end) - |> Enum.map(fn {group} -> group end) - - whitelisted_keys = - whitelisted_configs - |> Enum.filter(fn - {_group, _key} -> true - _ -> false - end) - - filtered = - from(c in ConfigDB) - |> Repo.all() - |> Enum.filter(¬_whitelisted?(&1, whitelisted_groups, whitelisted_keys)) - - if not Enum.empty?(filtered) do - shell_info("The following settings will be removed from ConfigDB:\n") - Enum.each(filtered, &dump(&1)) - - if force or shell_prompt("Are you sure you want to continue?", "n") in ~w(Yn Y y) do - filtered_ids = Enum.map(filtered, fn %{id: id} -> id end) - - Repo.delete_all(from(c in ConfigDB, where: c.id in ^filtered_ids)) - else - shell_error("No changes made.") - end - else + if whitelisted_configs in [nil, false] do shell_error("No unwanted settings in ConfigDB. No changes made.") + else + whitelisted_groups = + whitelisted_configs + |> Enum.filter(fn + {_group} -> true + _ -> false + end) + |> Enum.map(fn {group} -> group end) + + whitelisted_keys = + whitelisted_configs + |> Enum.filter(fn + {_group, _key} -> true + _ -> false + end) + + filtered = + from(c in ConfigDB) + |> Repo.all() + |> Enum.filter(¬_whitelisted?(&1, whitelisted_groups, whitelisted_keys)) + + if not Enum.empty?(filtered) do + shell_info("The following settings will be removed from ConfigDB:\n") + Enum.each(filtered, &dump(&1)) + + if force or shell_prompt("Are you sure you want to continue?", "n") in ~w(Yn Y y) do + filtered_ids = Enum.map(filtered, fn %{id: id} -> id end) + + Repo.delete_all(from(c in ConfigDB, where: c.id in ^filtered_ids)) + else + shell_error("No changes made.") + end + else + shell_error("No unwanted settings in ConfigDB. No changes made.") + end end end From a4fb651fac4416db7d5102672f10c9a9c3ce14fc Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Sat, 17 Jan 2026 13:30:07 +0400 Subject: [PATCH 11/11] ConfigController: Don't allow whitelist modification. --- lib/pleroma/web/admin_api/controllers/config_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/admin_api/controllers/config_controller.ex b/lib/pleroma/web/admin_api/controllers/config_controller.ex index f3adeb35a..3eba03525 100644 --- a/lib/pleroma/web/admin_api/controllers/config_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/config_controller.ex @@ -174,7 +174,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do end end - defp whitelisted_config?(:pleroma, :database_config_whitelist), do: false + defp whitelisted_config?(":pleroma", ":database_config_whitelist"), do: false defp whitelisted_config?(group, key) do if whitelisted_configs = Config.get(:database_config_whitelist) do