diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b6f4d3..3189db0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ Requires Elixir 1.15 or higher. +- Prevent decoding of unsafe data in `IdempotencyPlug.EctoStore` + ## v0.2.1 (2023-04-28) Relaxed dependency requirements for `ecto` and `ecto_sql`. diff --git a/lib/idempotency_plug/store/ecto_store.ex b/lib/idempotency_plug/store/ecto_store.ex index 4ad424a..cd4f914 100644 --- a/lib/idempotency_plug/store/ecto_store.ex +++ b/lib/idempotency_plug/store/ecto_store.ex @@ -34,7 +34,7 @@ if Code.ensure_loaded?(Ecto) do def cast(term), do: {:ok, term} @impl true - def load(bin) when is_binary(bin), do: {:ok, :erlang.binary_to_term(bin)} + def load(bin) when is_binary(bin), do: {:ok, :erlang.binary_to_term(bin, [:safe])} @impl true def dump(term), do: {:ok, :erlang.term_to_binary(term)} diff --git a/test/idempotency_plug/store/ecto_store_test.exs b/test/idempotency_plug/store/ecto_store_test.exs index 1e3c06c..6baae82 100644 --- a/test/idempotency_plug/store/ecto_store_test.exs +++ b/test/idempotency_plug/store/ecto_store_test.exs @@ -53,6 +53,23 @@ defmodule IdempotencyPlug.EctoStoreTest do {@updated_data, @fingerprint, updated_expires_at} end + test "prevents decoding of unsafe data" do + :ok = EctoStore.setup(@options) + + unsafe_data = <<131, 119, 8, "tjenixen">> + + assert EctoStore.insert(@request_id, @data, @fingerprint, DateTime.utc_now(), @options) == :ok + + TestRepo.query!("UPDATE idempotency_plug_requests SET data = $1 WHERE id = $2", [ + unsafe_data, + @request_id + ]) + + assert_raise ArgumentError, ~r/invalid or unsafe external representation of a term/, fn -> + EctoStore.lookup(@request_id, @options) + end + end + test "prunes" do :ok = EctoStore.setup(@options)