Padding Oracle in Chi with Jwt Tokens
Padding Oracle in Chi with Jwt Tokens — how this specific combination creates or exposes the vulnerability
A Padding Oracle attack against JWT tokens in the Chi framework occurs when an application decrypts or verifies tokens in a way that reveals whether padding or decryption errors are distinct from other validation failures. Chi is an HTTP web framework for the OCaml ecosystem, and while it does not enforce JWT handling, developers commonly integrate JWT validation using libraries. If the validation routine returns different HTTP status codes, timing differences, or error messages depending on whether a padding error occurs versus a signature mismatch, an attacker can use this behavior as an oracle.
Consider a typical integration where a developer decodes and verifies a JWT using HMAC (HS256) or RSA (RS256). If the runtime raises an exception or returns a specific error when padding is invalid, and a different response when the token structure is valid but the signature fails, this discrepancy becomes an oracle. An attacker can iteratively craft ciphertexts, observe responses, and gradually recover the plaintext or the signing key. This is especially relevant when tokens contain sensitive claims (e.g., user roles, permissions) and are transmitted over insecure channels or stored in cookies without integrity protection.
In Chi, a vulnerable route might look like this in practice: the endpoint reads an Authorization header, passes the token to a JWT library, and relies on the library’s error handling to decide the response. If the library throws distinct exceptions for padding errors, the attacker can automate requests to infer information about the key or the token content. This maps to OWASP API Top 10 API1:2023 – Broken Object Level Authorization when combined with BOLA/IDOR-like enumeration, and it can also expose issues under Data Exposure and Authentication checks during a middleBrick scan.
Real-world CVEs in other ecosystems (e.g., CVE-2016-10555 in Java JWT libraries) demonstrate how padding oracles can bypass authentication entirely. While Chi itself does not define JWT behavior, integrations must ensure constant-time verification and opaque error handling. middleBrick’s 12 security checks, including Authentication, Input Validation, and Data Exposure, are designed to detect such timing and error-leakage patterns during unauthenticated scans. The LLM/AI Security module further tests for prompt injection or system prompt leakage, which is orthogonal but highlights how endpoint behavior can unintentionally reveal internal logic.
To mitigate, developers must standardize responses so that any invalid token yields the same status code, message, and timing characteristics. This includes avoiding early returns on decryption failures, suppressing stack traces, and using libraries that support secure verification modes. middleBrick’s scan can identify these inconsistencies by probing endpoints with malformed tokens and analyzing response variations, providing prioritized findings with severity and remediation guidance without requiring credentials or agent installation.
Jwt Tokens-Specific Remediation in Chi — concrete code fixes
Remediation focuses on making token validation side-channel resistant and ensuring consistent behavior in Chi routes. Below are concrete, working examples using common OCaml JWT libraries (e.g., jwt or ocaml-jwt). The goal is to avoid branching on padding errors and to return a uniform response for all invalid tokens.
Example 1: Constant-time verification with uniform error handling
open Lwt
open Cohttp
open Cohttp_lwt_unix
open Jwt
let verify_token token secret req_body =
let open Lwt_result.Syntax in
let response_error () =
Server.respond_string ~status:`Unauthorized ~body:"Unauthorized" () in
match decode_and_verify `Hmac secret token with
| Ok claims -
(* Proceed only if verification succeeds; no early returns on padding issues *)
Server.respond_string ~status:`OK ~body:("claims:" ^ (Yojson.Safe.to_string @@ `Assoc ["payload", `String claims]))
| Error err -
(* Log the error internally if needed, but return the same response *)
response_error ()
let handler req body =
let headers = Request.headers req in
match Header.get headers "authorization" with
| None -
Server.respond_string ~status:`Bad_request ~body:"Missing auth" ()
| Some auth_header -
let parts = String.split_on_char ' ' auth_header in
match parts with
| ["Bearer"; token] -
verify_token token "your-256bit-secret" body
| _ -
Server.respond_string ~status:`Bad_request ~body:"Invalid auth format" ()
Example 2: Middleware approach to normalize validation outcomes
open Lwt
open Cohttp
open Cohttp_lwt_unix
open Jwt
let jwt_auth_middleware secret next_handler req body =
let open Lwt_result.Syntax in
let headers = Request.headers req in
match Header.get headers "authorization" with
| None -
next_handler req body (* or return unauthorized consistently *)
| Some auth_header -
let parts = String.split_on_char ' ' auth_header in
match parts with
| ["Bearer"; token] -
(* Use a function that never throws on padding; returns Error on any failure *)
(match verify_token ?timeout:None ~secret token with
| Ok claims -
(* Extend request metadata with claims for downstream handlers *)
let req' = Request.add_attr req "jwt_claims" claims in
next_handler req' body
| Error _ -
(* Uniform rejection for any invalid token *)
Server.respond_string ~status:`Unauthorized ~body:"Unauthorized" ())
| _ -
Server.respond_string ~status:`Bad_request ~body:"Invalid auth format" ()
(* Usage in a Chi router *)
let api_routes =
let open Chi in
[ get "/protected" (jwt_auth_middleware "your-256bit-secret" (fun req body -
Lwt.return (Server.respond_string ~status:`OK ~body:"OK" ())))
]
Operational guidance
- Use libraries that support constant-time comparison for HMAC and RSA-PKCS1/OAEP decryption to reduce timing differences.
- Ensure all error paths in Chi return the same HTTP status code (e.g., 401) and avoid verbose error messages that could aid an oracle.
- Validate token structure before processing claims to reject malformed tokens early, but without revealing why validation failed.
- Rotate secrets regularly and use strong key sizes; prefer RS256 with proper key management where feasible.
middleBrick can be run via the CLI (middlebrick scan <url>), GitHub Action, or MCP Server to detect inconsistencies in error handling and timing that indicate a padding oracle risk. Findings include severity, remediation steps, and mapping to frameworks like OWASP API Top 10 without requiring authentication or agents.