How to fix Lack of Resources & Rate Limiting
in Phoenix
Executive Summary
Phoenix applications on the BEAM are resilient, but they aren't invincible. Without explicit rate limiting, an attacker can saturate your database pool, exhaust memory with large payloads, or spike CPU cycles by spamming expensive password-hashing algorithms like Argon2 or Bcrypt. To stop DoS and brute-force attacks, you must intercept the request at the Plug level before it hits your business logic.
The Vulnerable Pattern
defmodule MyAppWeb.AuthController do use MyAppWeb, :controller
def login(conn, %{“user” => user_params}) do # VULNERABLE: No rate limiting present. # An attacker can automate 10,000 requests per second. # This will exhaust the DB connection pool and spike CPU via password hashing. case Accounts.authenticate_user(user_params) do {:ok, user} -> render(conn, “success.json”, user: user) {:error, _} -> conn |> put_status(:unauthorized) |> json(%{error: “Invalid credentials”}) end end end
The Secure Implementation
The vulnerable code allows unbounded access to the 'authenticate_user' function, which is a prime target for resource exhaustion. The secure implementation introduces a custom Plug that leverages the 'Hammer' library. By checking the rate limit against the user's IP address (or session token) before the controller logic is reached, we can return a 429 'Too Many Requests' status. Calling 'halt/1' is essential; it prevents the connection from proceeding to the expensive hashing and database operations, effectively shielding the system resources from the attack.
defmodule MyAppWeb.Plugs.RateLimit do import Plug.Conn import Phoenix.Controller@doc """ Intercepts requests to check rate limits using Hammer (ETS/Redis backend). Usage: plug MyAppWeb.Plugs.RateLimit when action in [:login] """ def init(opts), do: opts
def call(conn, _opts) do # Define a unique key (IP or User ID) key = “login:#{conn.remote_ip}”
# Limit: 5 attempts per 60 seconds case Hammer.check_rate(key, 60_000, 5) do {:allow, _count} -> conn {:deny, _limit} -> conn |> put_status(:too_many_requests) |> json(%{error: "Rate limit exceeded. Try again in a minute."}) |> halt() # CRITICAL: Stop the pipeline here end
end end
Your Phoenix API
might be exposed to Lack of Resources & Rate Limiting
74% of Phoenix apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.