VYPR
High severityNVD Advisory· Published Jun 2, 2026

CVE-2026-48597

CVE-2026-48597

Description

Allocation of Resources Without Limits or Throttling vulnerability in elixir-tesla tesla allows denial of service via atom table exhaustion in Tesla.Adapter.Mint.

Tesla.Adapter.Mint.open_conn/2 converts the URL scheme of every outgoing request to a BEAM atom via String.to_atom(uri.scheme) with no allow-list validation. BEAM atoms are never garbage-collected and the atom table is bounded (approximately 1,048,576 entries by default). An attacker who can influence the URL of a Tesla request — either via an application-level URL-forwarding feature (webhook, proxy, importer) or via a Location header returned by a server when Tesla.Middleware.FollowRedirects is in the pipeline — can mint one fresh permanent atom per request by varying the scheme string. After enough requests the atom table fills and the VM crashes, taking down the entire application.

This issue affects tesla: from 1.3.0 before 1.18.3.

Affected products

1

Patches

1
4699c3cb3e2f

Merge commit from fork

https://github.com/elixir-tesla/teslaYordis PrietoJun 2, 2026via body-scan
2 files changed · +34 15
  • lib/tesla/adapter/mint.ex+21 15 modified
    @@ -150,26 +150,32 @@ if Code.ensure_loaded?(Mint.HTTP) do
         end
     
         defp open_conn(uri, opts) do
    -      opts =
    -        with "https" <- uri.scheme,
    -             global_cacertfile when not is_nil(global_cacertfile) <-
    -               Application.get_env(:tesla, Tesla.Adapter.Mint)[:cacert] do
    -          Map.update(opts, :transport_opts, [cacertfile: global_cacertfile], fn tr_opts ->
    -            Keyword.put_new(tr_opts, :cacertfile, global_cacertfile)
    -          end)
    -        else
    -          _ -> opts
    -        end
    +      with {:ok, scheme} <- parse_scheme(uri.scheme) do
    +        opts =
    +          with :https <- scheme,
    +               global_cacertfile when not is_nil(global_cacertfile) <-
    +                 Application.get_env(:tesla, Tesla.Adapter.Mint)[:cacert] do
    +            Map.update(opts, :transport_opts, [cacertfile: global_cacertfile], fn tr_opts ->
    +              Keyword.put_new(tr_opts, :cacertfile, global_cacertfile)
    +            end)
    +          else
    +            _ -> opts
    +          end
     
    -      opts = Map.put_new(opts, :mode, :passive)
    +        opts = Map.put_new(opts, :mode, :passive)
     
    -      with {:ok, conn} <-
    -             HTTP.connect(String.to_atom(uri.scheme), uri.host, uri.port, Enum.into(opts, [])) do
    -        # If there were redirects, and passed `closed_conn: false`, we need to close opened connections to these intermediate hosts.
    -        {:ok, conn, Map.put(opts, :close_conn, true)}
    +        with {:ok, conn} <-
    +               HTTP.connect(scheme, uri.host, uri.port, Enum.into(opts, [])) do
    +          # If there were redirects, and passed `closed_conn: false`, we need to close opened connections to these intermediate hosts.
    +          {:ok, conn, Map.put(opts, :close_conn, true)}
    +        end
           end
         end
     
    +    defp parse_scheme("http"), do: {:ok, :http}
    +    defp parse_scheme("https"), do: {:ok, :https}
    +    defp parse_scheme(_), do: {:error, :unsupported_scheme}
    +
         defp make_request(conn, method, path, headers, body) when is_function(body) do
           with {:ok, conn, ref} <-
                  HTTP.request(
    
  • test/tesla/adapter/mint_test.exs+13 0 modified
    @@ -63,6 +63,19 @@ defmodule Tesla.Adapter.MintTest do
         assert conn.state == :closed
       end
     
    +  test "unsupported scheme does not mint atoms" do
    +    request = %Env{
    +      method: :get,
    +      url: "atk-#{:erlang.unique_integer([:positive])}://127.0.0.1/"
    +    }
    +
    +    before_count = :erlang.system_info(:atom_count)
    +    assert {:error, :unsupported_scheme} = call(request)
    +    after_count = :erlang.system_info(:atom_count)
    +
    +    assert after_count == before_count
    +  end
    +
       test "certificates_verification" do
         request = %Env{
           method: :get,
    

Vulnerability mechanics

Root cause

"The Tesla adapter for Mint improperly converts untrusted URL schemes into BEAM atoms without validation, leading to atom table exhaustion."

Attack vector

An attacker can trigger this vulnerability by influencing the URL scheme of a request processed by Tesla.Adapter.Mint.open_conn/2. This can be achieved through application-level features like URL forwarding or webhooks, or by exploiting the Tesla.Middleware.FollowRedirects middleware with a server that returns a Location header containing a novel scheme. Each such request creates a new, permanent atom in the BEAM VM's atom table. [ref_id=1]

Affected code

The vulnerability resides in the `open_conn/2` function within `lib/tesla/adapter/mint.ex`. Specifically, the line `HTTP.connect(String.to_atom(uri.scheme), ...)` is responsible for converting the URI scheme directly into an atom without prior validation. The patch modifies this section by introducing `parse_scheme/1` and using its output for the `HTTP.connect` call. [patch_id=4524231]

What the fix does

The patch introduces a new private function `parse_scheme/1` which validates the URL scheme against a hardcoded allow-list of supported schemes (http and https). Only recognized schemes are passed to `HTTP.connect/4` as atoms; any other scheme results in an `{:error, :unsupported_scheme}` tuple, preventing the creation of new atoms in the atom table. This directly addresses the vulnerability by ensuring that only valid schemes can be converted to atoms, thus preventing exhaustion. [patch_id=4524231]

Preconditions

  • configThe application must use Tesla.Adapter.Mint. [ref_id=1]
  • inputThe application must expose a feature that allows untrusted input to influence request URLs, or use Tesla.Middleware.FollowRedirects. [ref_id=1]

Reproduction

Stand up any application that accepts a user-supplied URL and forwards it through Tesla.Adapter.Mint. Send requests to the application, each with a distinct, previously unseen URL scheme (e.g. atk1://, atk2://, ...). Each request interns one new permanent atom; Mint rejects the connection but the atom persists. After approximately 1,000,000 requests the BEAM atom table is exhausted and the VM crashes. [ref_id=1]

Generated on Jun 2, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.