Header Injection in Chi with Api Keys
Header Injection in Chi with Api Keys — how this specific combination creates or exposes the vulnerability
Header injection in the Chi web framework occurs when untrusted input is directly concatenated into HTTP header values, allowing an attacker to inject additional headers or split the header block. When API keys are handled via headers (e.g., authorization or custom headers), careless string assembly can enable header manipulation, request smuggling, or privilege escalation. A typical unsafe pattern in Chi is building headers by interpolating user-controlled values without validation or sanitization.
Consider a Chi route that forwards an API key from an incoming request into another header without validation:
(defn unsafe-api-key-forward [request]
(let [api-key (get-in request [:headers "x-api-key"])]
{:status 200
:headers {"X-Forwarded-API-Key" api-key}
:body "ok"}))
If api-key contains newline characters (e.g., abc\r\nX-Admin: true), the injected header can alter the downstream service’s behavior, potentially bypassing authorization or enabling smuggling. Chi does not sanitize header values, so it is the developer’s responsibility to ensure that API key usage does not open a path for header injection.
Another scenario involves constructing custom headers for outbound requests by concatenating strings:
(defn build-outbound-headers [user-supplied]
(str "Authorization: ApiKey " user-supplied))
If user-supplied includes a newline, an attacker can inject additional headers (e.g., Authorization: ApiKey attacker\r\nX-Internal: leak). In the context of API keys, this can expose sensitive routing logic or cause the request to be authenticated with a different key than intended. Because API keys often govern access scope and rate limits, header injection can unintentionally grant elevated or unintended access.
The risk is compounded when API keys are used in multiple headers or when logging captures raw headers. An attacker might learn internal header names or key formats through response handling or error messages. Since Chi leaves header validation to the developer, integrating input validation and canonical header construction is essential to prevent injection.
Api Keys-Specific Remediation in Chi — concrete code fixes
To secure API key handling in Chi, avoid direct interpolation of user input into headers. Use strict validation, canonical header construction, and dedicated client libraries where possible. Below are concrete, safe patterns for managing API keys in Chi routes.
1. Validate and sanitize header values
Ensure that any user-supplied value used in headers is stripped of control characters and does not contain newline or carriage return characters. Use a validation library to enforce format constraints (e.g., alphanumeric with optional separators).
(defn safe-api-key-header [raw-key]
(when (and (string? raw-key)
(re-matches #"[A-Za-z0-9\\-_]+" raw-key))
raw-key))
(defn secure-forward [request]
(let [api-key (safe-api-key-header (get-in request [:headers "x-api-key"]))]
(if api-key
{:status 200
:headers {"X-Forwarded-API-Key" api-key}
:body "ok"}
{:status 400
:body {:error "invalid-api-key"}})))
This ensures the API key contains only safe characters and prevents newline-based injection.
2. Use structured outbound requests instead of string concatenation
When making outbound calls, construct headers as a map rather than concatenating strings. This avoids accidental injection and keeps control over header formatting.
(defn build-outbound-headers [api-key]
{"Authorization" (str "ApiKey " api-key)
"User-Agent" "middleBrick-client"})
(defn forward-to-service [request]
(let [api-key (safe-api-key-header (get-in request [:headers "x-api-key"]))]
(if api-key
(let [client (http/client)
resp (client/get "https://upstream.example.com/data"
{:headers (build-outbound-headers api-key)})
body (resp/body-string resp)]
{:status 200
:body body})
{:status 401
:body {:error "missing-api-key"}})))
By using a map, Chi (and underlying HTTP clients) handle header formatting safely, eliminating newline injection risks. The validation function prevents malformed keys from being used.
3. Centralize key handling and avoid logging raw keys
Do not log raw API keys or echo them in responses. If logging is required for debugging, mask or hash the key. Also, centralize key extraction to reduce duplication and enforce consistent validation.
(defn extract-api-key [request]
(let [key (get-in request [:headers "x-api-key"])]
(when (safe-api-key-header key)
key)))
(defn log-request [request]
(let [masked-key (when-let [k (extract-api-key request)]
(str (subs k 0 4) "****"))]
(println (str "Request from " (-> request :remote-addr) " key: " masked-key))))
These practices reduce the likelihood of accidental exposure and ensure that API keys are handled in a controlled, predictable manner within Chi routes.