Crlf Injection in Chi with Firestore
Crlf Injection in Chi with Firestore — how this specific combination creates or exposes the vulnerability
Crlf Injection occurs when user-controlled data is reflected in HTTP headers without sanitization, allowing an attacker to inject newline characters (CRLF = Carriage Return + Line Feed). In a Chi application using Firestore as a backend, this typically arises when dynamic values stored in Firestore are later used to construct response headers. Chi is a composable routing library for Clojure, and Firestore is a NoSQL database; the vulnerability is not in either product itself but in how data flows between them and into header construction.
For example, if a Firestore document contains a user-controlled field such as display_name or location, and the application uses that value directly in a header like X-User-Name, an attacker who can write to that Firestore document can supply a value like attacker\r\nSet-Cookie: session=hijacked. When Chi constructs the response and includes the header value, the injected CRLF sequence causes header splitting. The injected header may then be interpreted by the client, leading to HTTP response splitting, cache poisoning, or session fixation depending on deployment and client behavior.
The risk is compounded when Firestore documents are used to store configuration or metadata that the application trusts. Because Firestore rules do not enforce header-safe character constraints, developers must treat all Firestore data as potentially untrusted. The unauthenticated scan capability of middleBrick can identify endpoints that pull data from Firestore and reflect it into headers, surfacing this class of issue during security checks. Without proper input validation and output encoding, the attack surface remains exposed.
Firestore-Specific Remediation in Chi — concrete code fixes
Remediation focuses on two controls: strict input validation on data entering Firestore and rigorous output encoding when reading data for headers. Firestore does not provide built-in header-safe sanitization, so the application layer in Chi must enforce it. Below are concrete, idiomatic examples using the official Google Cloud Firestore client for Clojure via interop, and safe header construction in Chi.
1. Sanitize before writing to Firestore
Validate and normalize user input before storing it. For header-affecting fields, reject or encode characters that could enable injection, such as carriage return (\r) and line feed (\n).
(ns myapp.firestore
(:require [clojure.string :as str]))
(defn safe-display-name [input]
(if (re-matches #"[\w\s\-_]{1,100}" input)
input
(throw (IllegalArgumentException. "Invalid display name"))))
(defn write-user [db user-id display-name]
(let [safe-name (safe-display-name display-name)]
(.set db (str "users/" user-id) #js {:displayName safe-name})))
2. Encode output when constructing headers in Chi
When reading data from Firestore for use in headers, apply header-specific encoding and avoid direct concatenation. Use a strict allowlist approach for header values.
(ns myapp.handler
(:require [compojure.core :refer [GET defroutes]]
[ring.util.response :as resp]
[myapp.firestore :as fs]))
(defn safe-header-value [value]
;; Remove or replace CRLF characters; allow only printable ASCII
(-> value
(str/replace #"[\r\n]" "")
(str/replace #"[^\x20-\x7e]" "")))
(defroutes app-routes
(GET "/user/:id" [id]
(let [db (fs/get-db)
doc (fs/get-user-by-id db id)
raw-name (get doc "displayName")
header-name (safe-header-value raw-name)
response (resp/response (str "User: " header-name))]
(-> response
(resp/header "X-User-Name" header-name)
(resp/status 200)))))n
3. Centralize header construction to avoid duplication
Create a helper that ensures all header values derived from Firestore are processed consistently, reducing the chance of accidental bypass.
(ns myapp.headers
(:require [clojure.string :as str]))
(defn set-safe-header [response header value]
(let [clean (str/replace (str/replace value #"[\r\n]" "") "[^\x20-\x7e]" "")]
(resp/header response header clean)))
;; Usage in a Chi route
(GET "/example" []
(let [db (fs/get-db)
doc (fs/get-doc db "settings/theme")
title (get doc "pageTitle")]
(-> (resp/response "ok")
(set-safe-header "X-Page-Title" title)
(resp/status 200))))
These patterns ensure that data sourced from Firestore is never directly trusted when used in HTTP headers. By validating on write and encoding on output, the application mitigates Crlf Injection while preserving the utility of Firestore as a backend store.