HIGH cache poisoningchijwt tokens

Cache Poisoning in Chi with Jwt Tokens

Cache Poisoning in Chi with Jwt Tokens — how this specific combination creates or exposes the vulnerability

Cache poisoning in the context of a Chi web application that uses JWT tokens occurs when an attacker manipulates cached responses so that malicious or sensitive data is served to other users. Chi is a minimalistic HTTP routing library for Common Lisp, and when it serves responses that include authorization information encoded in JWT tokens, improper cache key design can cause responses tied to one user’s token to be reused for another user’s request.

Consider a route that returns user profile data and caches the result based only on the request path, ignoring differences in the Authorization header. If a response containing a JWT token in an Authorization header is cached, a subsequent request from a different user that hits the same cache entry may receive the cached response with the previous user’s JWT token embedded in any downstream calls or in the response body (e.g., if the server echoes the token or a claim from it). This effectively leaks credentials or tokens across users.

The vulnerability is compounded when the cache key excludes the Authorization header or a subset of claims within the JWT token. Attackers can probe endpoints that issue tokens and observe whether cached responses differ based on token claims. Because Chi does not inherently manage caching, developers must ensure that cache keys incorporate the Authorization header or a hash of relevant JWT claims (such as the subject or issuer) to prevent cross-user contamination.

Real-world examples include APIs that cache GET responses where the Authorization bearer token is present but not part of the cache key, or APIs that embed JWTs in JSON responses and cache those responses. Tools like middleBrick can detect such risky patterns by scanning the API surface and identifying missing authorization differentiation in cache-sensitive endpoints, providing prioritized findings and remediation guidance.

Jwt Tokens-Specific Remediation in Chi — concrete code fixes

To remediate cache poisoning risks when using JWT tokens in Chi, ensure that cache keys incorporate the Authorization header or a normalized representation of the JWT claims that affect the response. Below are concrete code examples demonstrating how to include the Authorization header in the cache key and how to safely handle JWTs within Chi routes.

Example 1: Cache key includes Authorization header

Using a simple in-memory cache where the key is derived from the request URI and the Authorization header value.

(ql:quickload '(:chi :cl-json :ironclad))

(defpackage #:my-api
  (:use #:cl #:chi)
  (:import-from #:ironclad #:sha256-digest))
(in-package #:my-api)

(defvar *cache* (make-hash-table :test #'equal))

(defun cache-key (request)
  (let ((uri (format nil "~a" (chi:request-uri request)))
        (auth (or (getf (chi:request-headers request) "authorization") "no-auth")))
    (sha256-digest (concatenate 'string uri "|" auth))))

(defun get-cached-response (key)
  (gethash key *cache*))

(defun set-cached-response (key response)
  (setf (gethash key *cache*) response))

(define-route app ()
  (GET "/profile"
    (let* ((key (cache-key request))
           (cached (get-cached-response key)))
      (if cached
          (progn (format t "Cache hit for ~a~%" key)
                 cached)
          (let ((token (getf (chi:request-headers request) "authorization"))
                (profile (format nil "{\"user\": \"~a\", \"token\": \"~a\"}" "alice" token)))
            (set-cached-response key profile)
            profile))))))

Example 2: Normalize JWT claims for cache key (do not cache sensitive raw tokens)

Instead of caching raw tokens, extract non-sensitive claims and use them in the cache key. This prevents token leakage while still allowing cache differentiation.

(defun extract-subject-from-jwt (token)
  ;; Simplified: in production use a JWT library to decode and verify the token structure
  (when token
    (let ((parts (split-sequence:split-sequence #\. token)))
      (when (= (length parts) 3)
        (let ((payload (babel:octets-to-string (ironclad:base64-decrypt (second parts)))))
          (ignore-errors
            (let ((json (cl-json:decode-json-from-string payload)))
              (gethash "sub" json)))))))

(defun cache-key-safe (request)
  (let ((uri (format nil "~a" (chi:request-uri request)))
        (auth (or (getf (chi:request-headers request) "authorization") "")))
    (if (search "Bearer " auth)
        (let* ((token (subseq auth 7))
               (subject (extract-subject-from-jwt token)))
          (sha256-digest (format nil "~a|~a" uri (or subject "no-subject"))))
        (sha256-digest uri))))

These examples illustrate how to incorporate JWT-related data into cache keys to avoid poisoning. middleBrick can validate that your endpoints differentiate cache keys appropriately and flag endpoints where Authorization is ignored, reducing the risk of token leakage across users.

Frequently Asked Questions

Can cache poisoning occur if JWT tokens are stored in cookies instead of headers?
Yes. If responses are cached based on the request URI alone and cookies containing JWTs are sent by the browser, an attacker can cause cached responses with one user's token to be served to another user. Include cookie or Authorization header variance in cache keys.
Does middleBrick detect cache poisoning risks related to JWT tokens?
Yes. middleBrick scans endpoints to identify cases where Authorization or token-bearing headers are excluded from cache-sensitive routing and provides prioritized findings with remediation guidance.