GuardAPI Logo
GuardAPI
Automated Security Protocol

How to fix Insufficient Logging & Monitoring
in Phoenix

Executive Summary

Insufficient logging is a silent killer in Phoenix apps. If you're only relying on default Plug request logs, you're blind to credential stuffing, IDOR probing, and privilege escalation. To achieve 'hacker-proof' observability, you must implement structured logging that captures security-critical events with enough metadata to reconstruct an attacker's timeline.

The Vulnerable Pattern

VULNERABLE CODE
def login(conn, %{"username" => user, "password" => pass}) do
  case Auth.authenticate(user, pass) do
    {:ok, user} ->
      conn |> put_flash(:info, "Welcome!") |> redirect(to: "/home")
    {:error, _reason} ->
      # VULNERABILITY: No logging of the failed attempt.
      # Attacker can brute-force without leaving a trace in the application logs.
      conn |> put_flash(:error, "Invalid credentials") |> render("new.html")
  end
end

The Secure Implementation

The secure implementation moves beyond basic text logs. First, it uses Elixir's Logger metadata to attach IPs and User-Agents, enabling SOC teams to correlate attacks. Second, it distinguishes between log levels (info vs. warning), allowing SIEMs to trigger alerts on high-frequency warnings. Third, it integrates with :telemetry, which allows you to hook into tools like Grafana or Prometheus to visualize spikes in 401/403 errors, which is a primary indicator of automated brute-force or scanning tools.

SECURE CODE
require Logger

def login(conn, %{“username” => username} = params) do

1. Capture metadata for the session

metadata = [ event: “auth.login”, remote_ip: conn.remote_ip |> :inet.ntoa() |> to_string(), user_agent: get_req_header(conn, “user-agent”) |> List.first() ]

case Auth.authenticate(username, params[“password”]) do {:ok, user} -> Logger.info(“Successful login for user: #{username}”, metadata ++ [user_id: user.id, status: “success”]) conn |> redirect(to: “/dashboard”)

{:error, reason} ->
  # 2. Log failures with 'warning' level and include the reason
  Logger.warning("Failed login attempt for user: #{username}", metadata ++ [reason: reason, status: "failure"])
  
  # 3. Emit Telemetry for real-time monitoring/alerting
  :telemetry.execute([:myapp, :auth, :failure], %{count: 1}, %{user: username})

  conn |> put_flash(:error, "Invalid credentials") |> render("new.html")

end end

System Alert • ID: 7679
Target: Phoenix API
Potential Vulnerability

Your Phoenix API might be exposed to Insufficient Logging & Monitoring

74% of Phoenix apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.

RUN FREE SECURITY DIAGNOSTIC
GuardLabs Engine: ONLINE

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.