Api Key Exposure in Phoenix with Mutual Tls
Api Key Exposure in Phoenix with Mutual Tls — how this specific combination creates or exposes the vulnerability
In Phoenix applications that use mutual TLS (mTLS), developers often assume that because the transport is authenticated with client certificates, sensitive data such as API keys cannot leak. This assumption can create a false sense of security and lead to insecure handling of API keys within the application. Even when mTLS is enforced at the endpoint layer, API keys may still be logged, echoed in error messages, or exposed through configuration and runtime introspection if not managed carefully.
Consider a Phoenix controller that receives an mTLS-authenticated request and forwards it to a downstream service using an API key stored in application environment variables. If the controller inadvertently includes the API key in logs, telemetry, or structured responses (for example, when rendering JSON for debugging), the key can be exposed despite the presence of mTLS. Similarly, if the API key is embedded in client-side JavaScript or included in error payloads returned to the client, the confidentiality of the key is compromised regardless of transport-layer authentication.
Another scenario specific to Phoenix and mTLS involves improper certificate validation or misconfigured cipher suites that weaken the effective assurance of client identity. If the server does not strictly verify client certificates, an unauthorized client may present a valid certificate but still operate under an unverified identity, increasing the risk that an API key associated with that client is abused. Additionally, if the application mixes mTLS with bearer tokens or API keys in a way that prioritizes one mechanism over the other without clear boundaries, routing rules may inadvertently route sensitive requests through less secure paths, exposing keys in logs or traces.
middleBrick’s scan checks for these exposure risks by testing the unauthenticated attack surface of your Phoenix endpoint, including header handling, error responses, and observable metadata. The tool’s Data Exposure check can flag scenarios where API keys appear in responses, logs, or insecurely handled configurations, even when mTLS is in place. By combining OpenAPI/Swagger spec analysis with runtime probes, the scanner cross-references defined security schemes with actual behavior, helping you identify whether your mTLS-enabled Phoenix endpoints inadvertently leak sensitive keys.
For LLM-related exposures, the scanner’s LLM/AI Security checks are especially relevant if your Phoenix service exposes endpoints that interact with language models. These checks detect system prompt leakage, probe for prompt injection and jailbreak attempts, scan LLM responses for PII or API keys, and identify excessive agency patterns such as unchecked tool calls. If your API routes pass user input directly into LLM prompts or configuration without strict validation, an attacker may coerce the model into revealing API keys or other secrets embedded in prompts or responses.
To mitigate these risks, apply strict input validation and output encoding in your Phoenix controllers, ensure API keys are never included in logs or error messages, and use structured logging that redacts sensitive values. Combine mTLS with well-defined security schemes in your OpenAPI specification, and validate that client certificates map correctly to authorized identities. The middleBrick Pro plan supports continuous monitoring and CI/CD integration, allowing you to fail builds if a scan detects API key exposure or insecure handling in your Phoenix endpoints before changes reach production.
Mutual Tls-Specific Remediation in Phoenix — concrete code fixes
Securing a Phoenix application with mutual TLS requires precise configuration at both the transport layer and the application layer. Below are concrete steps and code examples to implement mTLS correctly and avoid exposing API keys or other sensitive data.
1. Configure the endpoint to require client certificates
In your endpoint definition, enforce client certificate verification so that only clients with valid certificates can establish a connection. This ensures that each request is tied to a known identity before any application logic runs.
defmodule MyAppWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :my_app
# Require client certificates and validate them against a trusted CA
socket "/socket", MyAppWeb.UserSocket,
websocket: true,
verify_client: true,
cert_auth: MyApp.Tls.ClientCertAuth
end
2. Implement a client certificate authenticator
Define a module that validates client certificates and maps them to user identities. This module should check the certificate chain, verify revocation (e.g., via CRL), and extract a subject or serial number to associate the request with an authorized entity.
defmodule MyApp.Tls.ClientCertAuth do
@trusted_ca File.read!("path/to/ca.pem")
|> :public_key.pem_decode()
|> List.first()
|> elem(1)
def verify(cert, _opts) do
case :public_key.pkix_path_validation(@trusted_ca, [cert]) do
{:ok, _} -> {:ok, subject(cert)}
{:error, _} -> :error
end
end
defp subject(cert) do
{:OTPRtPkix, _, tbs} = :public_key.pem_entry_decode(cert)
{:rdnSequence, rdn} = tbs.TBSCertificate.subject
# Extract common name or another attribute to identify the client
Enum.flat_map(rdn, & &1)
|> Enum.find_value(fn {type, value} = _attr ->
if type == ?CN, do: value
end)
end
end
3. Avoid leaking API keys in controllers and views
Ensure that API keys are never included in assigns, logs, or rendered JSON. Use environment variables for configuration and redact sensitive values in structured logging.
defmodule MyAppWeb.ResourceController do
use MyAppWeb, :controller
plug :require_mtls_client when action in [:show, :update]
def show(conn, %{"id" => id}) do
# Retrieve API key from environment, never from user input or logs
api_key = System.get_env("DOWNSTREAM_API_KEY")
# Use the key securely without exposing it in assigns
result = ExternalService.fetch(id, api_key)
json(conn, %{data: result.data})
end
defp require_mtls_client(conn, _opts) do
# The endpoint already enforces client cert verification
# This plug can be used for additional authorization checks
conn
end
end
4. Define secure routing and scope rules
Separate sensitive routes into a scope that requires mTLS and apply stricter authorization checks within that scope. This reduces the risk of accidental exposure through less guarded endpoints.
scope "/api", MyAppWeb do
pipe_through [:api, :require_mtls]
get "/resource/:id", ResourceController, :show
post "/resource", ResourceController, :create
end
5. Integrate with OpenAPI/Swagger for consistent security schemes
Document your mTLS requirements in the OpenAPI spec so that clients and scanners understand the expected security model. This also helps tools like middleBrick cross-reference runtime behavior with the spec definitions.
openapi: "3.0.0"
info:
title: My API
version: "1.0"
servers:
- url: https://api.example.com
securitySchemes:
mTLS:
type: mutual_tls
description: Mutual TLS client certificate authentication
x-client-cert:
subjectAltNameRegex: "^client\\.example\\.com$"
paths:
/resource/{id}:
get:
summary: Get resource
security:
- mTLS: []
responses:
'200':
description: OK
6. Monitor and rotate credentials
Even with mTLS, rotate API keys and certificates regularly. Use the middleBrick CLI to scan your Phoenix endpoints periodically and verify that no keys are exposed in responses or logs.
# Example CLI usage
middlebrick scan https://api.example.com/openapi.json
By combining strict mTLS configuration, careful handling of API keys, and continuous scanning, you reduce the risk of exposing sensitive credentials while maintaining strong client authentication in your Phoenix application.