Api Key Exposure in Chi with Api Keys
Api Key Exposure in Chi with Api Keys — how this specific combination creates or exposes the vulnerability
Chi is a lightweight HTTP client for Elixir that is commonly used to make outbound requests from Phoenix applications and other services. When developers use Chi with API keys, the risk of Api Key Exposure arises if keys are handled as plain strings, passed in URLs, logged, or transmitted over non-encrypted channels. Because Chi constructs and sends HTTP requests programmatically, an API key that is embedded in source code, configuration files, or environment variables without proper protection can be exposed at runtime through logs, error messages, or insecure dependency configurations.
An attacker might exploit this exposure through several realistic scenarios. For example, if a Chi request is built with an API key included in the URL query string, the key can leak into server logs, browser history, or network monitoring tools. Similarly, if the key is set as an environment variable that is inadvertently printed during application startup or debugging, it becomes accessible to anyone with access to those logs. In distributed systems where telemetry and error reporting capture request metadata, an API key that is not isolated in secure headers and transport layers can be inadvertently surfaced.
Chi does not inherently protect against insecure key management; it relies on the developer to ensure that sensitive values are handled securely. This means using HTTPS for every request, avoiding concatenation of keys into URLs, and ensuring that keys are not included in structured logs or error responses. The risk is compounded when Chi is used in test or staging environments where configurations are less strict, allowing keys to be exposed more easily. Because API keys often provide broad access to third‑party services, their exposure can lead to unauthorized usage, data exfiltration, or lateral movement within an organization’s ecosystem.
Another vector specific to Chi involves the use of macros or compile‑time configuration that injects API keys into requests. If such configurations are shared across environments without segregation, keys intended for production might appear in non‑production contexts, increasing the likelihood of accidental exposure through debugging or monitoring tools. Even when keys are stored in secure vaults, improper integration with Chi can result in keys being written to temporary files or process arguments, which are visible to other processes on the same host.
middleBrick scans for these classes of risk by analyzing the unauthenticated attack surface of an API that uses Chi‑based clients. It checks whether API keys are transmitted in URLs, whether HTTPS is consistently enforced, and whether sensitive data appears in logs or error outputs. The scanner also evaluates whether the application exposes endpoints that can be used to probe or infer the presence of API keys, helping teams understand how an attacker might observe or misuse exposed credentials.
Api Keys-Specific Remediation in Chi — concrete code fixes
To mitigate Api Key Exposure when using Chi, store keys securely and ensure they are never serialized into logs, URLs, or error messages. Use HTTP headers for key transmission, enforce TLS for all requests, and avoid compile‑time injection of secrets into configurations that span environments.
Secure header-based usage
Pass the API key in an Authorization header rather than in the URL. This prevents the key from appearing in logs or browser history.
defmodule MyClient do
import Tesla, only: [get: 2, post: 2]
def get_protected(resource) do
api_key = System.get_env("API_KEY")
Tesla.get("https://api.example.com/#{resource}", [
{"Authorization", "Bearer #{api_key}"}
])
end
end
Environment-based configuration with validation
Load the API key at runtime from environment variables and validate its presence before creating requests. This avoids hard‑coded keys and supports different values per environment.
defmodule MyClient do
def get_resource(path) do
with {:ok, key} <- fetch_api_key() do
url = URI.parse("https://api.example.com/#{path}")
headers = [{"X-API-Key", key}]
:httpc.request(:get, {url, headers}, [], [])
else
:error -> {:error, :missing_api_key}
end
end
defp fetch_api_key do
case System.get_env("API_KEY") do
"" -> :error
nil -> :error
key -> {:ok, key}
end
end
end
Avoid logging sensitive values
Ensure that request and response logging does not include headers or parameters that contain API keys. Configure telemetry and error reporting to filter out sensitive fields.
defmodule MyClient do
require Logger
def safe_get(path) do
url = "https://api.example.com/#{path}"
# Do not log the full request or response headers
Logger.debug(fn -> "Requesting #{url}" end)
:httpc.request(:get, {url, []}, [], [])
end
end
Use Tesla middleware for controlled key handling
When using Tesla with Chi, apply middleware that injects keys securely and avoids exposing them in logs or error tuples.
defmodule KeyMiddleware do
@behaviour Tesla.Middleware
def call(env, next) do
api_key = System.get_env("API_KEY")
env
|> Tesla.put_header("Authorization", "Bearer #{api_key}")
|> Tesla.run(next)
end
end
# In application configuration:
# {Tesla, [adapter: Tesla.Adapter.Hackney, [MyClient, KeyMiddleware]]}
Restrict key scope and rotate regularly
Limit the permissions associated with each API key and rotate them on a schedule. This reduces the impact of any accidental exposure. Combine this with network-level controls such as IP allowlists where supported.