How to fix Insufficient Logging & Monitoring
in Plug
Executive Summary
Insufficient logging in Elixir/Plug stacks creates a massive blind spot for incident response. If your pipeline doesn't explicitly track authentication failures, authorization bypass attempts, and high-impact state changes, you are effectively flying blind while an attacker maps your attack surface. Default Plug logging is for debugging, not security auditing.
The Vulnerable Pattern
defmodule MyApp.Router do use Plug.Router plug :match plug :dispatch
post “/api/v1/login” do # VULNERABLE: Fails silently. No audit trail for failed attempts. case MyApp.Auth.verify(conn.params[“user”], conn.params[“pass”]) do {:ok, user} -> send_resp(conn, 200, “OK”) {:error, _reason} -> send_resp(conn, 401, “Unauthorized”) end end end
The Secure Implementation
The secure implementation introduces structured security logging. By using Logger.metadata/1, we ensure all subsequent logs in the process lifecycle are tagged with the user's identity. The custom log_event/3 helper captures critical forensic data: the remote IP (converted from tuple to string), the request path, and the specific failure reason. This allows security teams to set up automated alerts for credential stuffing (high volume of LOGIN_FAILURE) and provides a clear audit trail for post-compromise analysis.
defmodule MyApp.SecurityLogger do require Loggerdef log_event(conn, event_type, metadata \ []) do # Structured logging for SIEM ingestion Logger.warning(“Security Event: #{event_type}”, Keyword.merge([ path: conn.request_path, remote_ip: :inet.ntoa(conn.remote_ip), user_agent: get_req_header(conn, “user-agent”), security: true ], metadata) ) end end
defmodule MyApp.Router do use Plug.Router import MyApp.SecurityLogger
post “/api/v1/login” do case MyApp.Auth.verify(conn.params[“user”], conn.params[“pass”]) do {:ok, user} -> Logger.metadata(user_id: user.id) send_resp(conn, 200, “OK”) {:error, reason} -> # SECURE: Explicitly log the failure with context for brute-force detection log_event(conn, “LOGIN_FAILURE”, [user: conn.params[“user”], reason: reason]) send_resp(conn, 401, “Unauthorized”) end end end
Your Plug API
might be exposed to Insufficient Logging & Monitoring
74% of Plug 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.