HIGH prototype pollutionchimutual tls

Prototype Pollution in Chi with Mutual Tls

Prototype Pollution in Chi with Mutual Tls — how this specific combination creates or exposes the vulnerability

Prototype pollution in Chi with mutual TLS occurs when an API endpoint that uses mutual TLS for client authentication manipulates objects derived from parsed request data (such as query parameters, headers, or JSON body) in a way that modifies shared prototype objects. Chi is a lightweight HTTP library for Clojure that uses ring-style request maps. If application code passes values from a request directly into data structures that are later merged into prototypes or used to update shared maps, an attacker can inject properties like __proto__, constructor.prototype, or use property accessors to alter behavior across requests.

Mutual TLS ensures the client presents a valid certificate, which authenticates the caller before the request reaches Chi handlers. However, mutual TLS does not sanitize or validate the content of the request. A common pattern is to extract a client certificate field (e.g., subject or serial number) and use it to key a cache or configuration map. If the application merges user-controlled data (e.g., JSON payload) into that map without copying or freezing the structure, an attacker can pollute the shared prototype used by the map or its nested objects. This can lead to privilege escalation or data leakage when later handlers rely on polluted properties.

For example, a handler might do the following: take an authenticated identity derived from the client certificate, merge it with incoming JSON, and pass it downstream. If the JSON contains { "__proto__": { "isAdmin": true } }, and the merge operation modifies the prototype of maps used in the runtime, subsequent checks for admin privileges may incorrectly return true. Because mutual TLS only authenticates the client and does not constrain how the application uses request-derived data, the vulnerability resides in the application’s data handling, not in the TLS layer.

In Chi, request maps are immutable data structures, but developers can inadvertently create mutable global state or reuse maps in ways that expose prototype pollution. Attack patterns include using assoc on shared atoms or refs that derive from request values, or passing raw values into functions that rely on prototype-based inheritance semantics in JavaScript interop. The OWASP API Top 10 category "Broken Object Level Authorization" often intersects with prototype pollution when object identifiers are derived from polluted properties.

An attacker can also exploit prototype pollution to affect logging, monitoring, or serialization libraries used alongside Chi. If these libraries share prototypes and the application passes attacker-controlled values into them, the pollution can propagate to outputs, leading to SSRF or credential exposure. Therefore, even with mutual TLS enforcing transport-level identity, the application must treat all request-derived data as untrusted and avoid mutating shared structures.

Real-world CVEs involving prototype pollution (e.g., CVE-2020-7598 in lodash) illustrate the class of issue: attacker-supplied keys that modify Object.prototype. In Chi integrations that involve JavaScript objects via interop or libraries that rely on prototype chains, similar risks exist if input is merged without isolation.

Mutual Tls-Specific Remediation in Chi — concrete code fixes

Remediation focuses on isolating request-derived data from shared prototypes and treating all input as untrusted, even when mutual TLS provides client authentication. In Chi, prefer using immutable data transformations and avoid mutating shared state with values extracted from the request. Use selective extraction and strict schema validation rather than broad merging.

Example 1: Safe extraction and validation without prototype mutation

(ns myapp.handler
  (:require [cheshire.core :as json]
            [ring.util.request :as req]))

(defn safe-handler [request]
  (let [client-cert (some-> request :client-cert :subject)
        body       (json/parse-string (req/body-string request) true)
        ;; Validate body against a schema; do not merge into shared structures
        validated (validate-body body)
        ;; Use isolated data, not derived from shared prototypes
        context    {:client-cert client-cert
                    :data validated}]
    {:status 200
     :body   (json/generate-string context)}))

Example 2: Avoiding shared atom mutation with request values

(ns myapp.state
  (:require [clojure.core.async :refer [chan >! <!]]))

(def cache (atom {}))

(defn update-cache-safe [request]
  (let [cert-serial (get-in request [:client-cert :serial])
        ;; Derive a key from the certificate, not from request body
        key (str "cert-" cert-serial)
        payload (json/parse-string (req/body-string request) true)]
    ;; Use a transient or isolated map; do not merge into a shared prototype
    (swap! cache assoc key (assoc payload :cert-serial cert-serial))))

Example 3: Using schema validation to reject unexpected properties

(ns myapp.validation
  (:require [malli.core :as m]
            [malli.error :as me]))

(def schema
  [:map
   [:data :string]
   [:optional [:client-id string?]]])

(defn validate-body [data]
  (if (m/validate schema data)
    data
    (throw (ex-info "Invalid payload" {:errors (me/humanize (m/explain schema data))}))))

Example 4: Chi route that ensures no shared state pollution

(ns myapp.routes
  (:require [compojure.core :refer [defroutes POST]]
            [ring.util.response :as resp]
            [myapp.validation :refer [validate-body]]))

(defroutes api-routes
  (POST "/submit" [request]
    (let [body (validate-body (json/parse-string (req/body-string request) true))]
      ;; Process body without referencing or mutating shared prototypes
      (resp/json-response {:status "ok" :received body}))))

These examples emphasize that mutual TLS secures the channel and client identity but does not protect against malformed or malicious request content. By validating schemas, avoiding broad merges, and not storing request-derived values in shared or prototype-inheriting structures, you mitigate prototype pollution risks in Chi applications.

Frequently Asked Questions

Does mutual TLS prevent prototype pollution in Chi APIs?
No. Mutual TLS authenticates clients but does not sanitize request data. Prototype pollution depends on how application code handles input; always validate and isolate data.
What are the key remediation steps for Chi applications using mutual TLS?
Validate all inputs against a strict schema, avoid merging request data into shared or global structures, use immutable transformations, and never derive behavior from untrusted properties such as __proto__.