HIGH prototype pollutionchijwt tokens

Prototype Pollution in Chi with Jwt Tokens

Prototype Pollution in Chi with Jwt Tokens — how this specific combination creates or exposes the vulnerability

Prototype pollution in Chi applications that rely on JWT tokens for session handling can occur when server-side code merges untrusted input into objects that later influence token creation, validation, or claims processing. Chi is a lightweight HTTP library for Clojure, and while it does not parse JSON by itself, developers often combine Chi routing with JSON libraries such as Cheshire to decode request bodies. If decoded JSON is merged into maps that are used to build JWT payloads or to control token verification logic, an attacker can inject properties like __proto__, constructor.prototype, or other keys that affect object behavior in subsequent operations.

Consider a scenario where a Chi handler decodes a JWT and then updates its claims by merging user-controlled data:

(ns example.handler
  (:require [cheshire.core :as json]
            [buddy.sign.jwt :as jwt]))

(defn update-claims [token params]
  (let [claims (jwt/unsign token "secret")
        merged (merge claims params)] ; vulnerable merge
    (jwt/sign merged "secret" {:alg :hs256})))

If params contains {"__proto__" {"admin" true}} and the JSON library is configured to map keys to JavaScript-style prototypes (or in a language where such keys affect object inheritance), the merged claims map may be altered in unexpected ways. In Clojure, this specific keyword does not mutate prototypes, but if the resulting map is later serialized to JSON and processed by a different runtime or library that does exhibit prototype pollution behavior, the injected property can change how the token is interpreted elsewhere in the system.

Another common pattern is using JWTs for API authentication while also accepting user input to determine scopes or roles included in the token. If an endpoint builds token claims by directly incorporating user-supplied maps without validation, an attacker can pollute the claims object and potentially escalate privileges:

(ns example.auth
  (:require [buddy.sign.jwt :as jwt]))

(defn issue-token [user-input]
  (jwt/sign (merge {:sub "user"} user-input) "secret" {:alg :hs256}))

An attacker sending role=admin or permissions=* can cause the issued token to grant unintended access. Even when using Chi’s routing to extract parameters, failing to validate and whitelist allowed fields before merging them into JWT-related data structures creates a pathway for privilege escalation or logic bypass via polluted objects that affect downstream authorization checks.

Prototype pollution in this context does not mean runtime JavaScript prototype corruption, but rather unwanted mutation of data structures that influence JWT handling. The risk emerges when decoded token data, user input, and business logic are combined without strict schema enforcement. The security impact includes token claim manipulation, unauthorized scope elevation, and bypass of intended access controls, which can lead to insecure authentication states or exposure of protected resources.

Jwt Tokens-Specific Remediation in Chi — concrete code fixes

To secure Chi applications that work with JWT tokens, apply strict input validation and avoid merging untrusted data directly into token payloads. Use explicit field selection and schema validation to ensure only expected keys are included. Below are concrete code examples demonstrating safer patterns.

Instead of a generic merge, define a function that extracts only safe claims:

(ns example.handler
  (:require [cheshire.core :as json]
            [buddy.sign.jwt :as jwt]
            [clojure.set :refer [rename-keys]]))

(defn safe-claims [token user-input]
  (let [claims (jwt/unsign token "secret")
        allowed-keys #{:sub :email :role}
        filtered (select-keys user-input allowed-keys)
        ;; rename keys if incoming names differ from JWT claim names
        mapped (rename-keys filtered {:role :scope})
        merged (merge claims (select-keys mapped [:scope]))]
    merged))

(defn update-claims [token params]
  (jwt/sign (safe-claims token params) "secret" {:alg :hs256}))

This approach ensures that only explicitly permitted fields from user input are incorporated into the JWT payload, preventing injection of malicious keys such as __proto__ or unexpected privilege attributes.

For issuing new tokens, validate and constrain all inputs before constructing the payload:

(ns example.auth
  (:require [buddy.sign.jwt :as jwt]
            [malli.core :as m]
            [malli.error :as perr]))

(def token-schema
  [:map
   [:sub string?]
   [:email string?]
   [:role {:optional true} #{:user :admin}]])

(defn issue-token [user-input]
  (if-let [v (m/validator token-schema)]
    (if (m/validate v user-input)
      (jwt/sign user-input "secret" {:alg :hs256})
      (throw (IllegalArgumentException. "Invalid token claims")))
    (throw (IllegalArgumentException. "Schema unavailable"))))

Using a schema validator such as Malli ensures that user input conforms to an expected shape and enumerated values before it is included in a JWT. This prevents both prototype-style pollution and privilege escalation via unexpected keys or values.

Additionally, configure Chi routes to extract parameters explicitly and pass only vetted data to token functions:

(ns example.routes
  (:require [compojure.core :refer [defroutes POST]]
            [ring.util.response :as resp]
            [example.auth :refer [issue-token]]))

(defroutes api-routes
  (POST "/token" request
    (let [params (-> request :params (select-keys ["sub" "email" "role"]))]
      (resp/json-response (issue-token params)))))

By selecting only known-safe keys from the request parameters and avoiding blind merges, you reduce the attack surface for token-related prototype pollution and ensure that JWT tokens reflect only intended claims. These practices align with secure coding guidance for handling authentication tokens and help maintain the integrity of protected endpoints.

Frequently Asked Questions

Can prototype pollution affect JWT verification logic in Chi applications?
Yes, if application code merges untrusted input into objects used during JWT verification or claim processing, injected properties can alter behavior. Mitigate by validating and filtering all inputs before they touch token logic.
Does middleBrick detect prototype pollution risks involving JWT tokens?
middleBrick scans API endpoints and can identify missing input validation and unsafe data handling patterns that may lead to prototype pollution, including issues involving JWT tokens. Findings include severity, details, and remediation guidance.