Command Injection in Chi with Jwt Tokens
Command Injection in Chi with Jwt Tokens — how this specific combination creates or exposes the vulnerability
Command injection occurs when an application passes untrusted input to a system shell or to APIs that execute operating system commands. In the Chi web framework for Clojure, this risk can emerge when request handling logic constructs shell commands from user-controlled data such as parameters, headers, or cookies. The use of JWT tokens in this context does not directly execute commands, but it can expose command injection if token contents are trusted, parsed insecurely, or forwarded to OS-level operations without validation.
For example, if a Chi handler decodes a JWT and uses claims like sub or custom fields to build shell commands—such as passing a username claim into a script or system call—an attacker who can influence the token (via weak signing keys, token leakage, or a compromised client) can inject shell metacharacters. Consider a scenario where a token claim is used to generate a filename or to select a backend tool: (str "/usr/bin/report " token-subject). If the subject contains characters like ;, &, or backticks, the composed command may execute unintended operations.
Chi routes are typically built using ring.util.response and composable handlers; developers might inadvertently pass request parameters or token-derived data to functions like sh (from clojure.java.shell) without sanitization. This is especially risky when combined with administrative endpoints that execute privileged operations based on token roles. Even when JWTs are verified cryptographically, applications must treat all decoded payloads as untrusted input to OS processes. Attack patterns such as OWASP API Top 10 Injection apply here, and real-world cases have involved tokens with embedded commands leading to unauthorized file access or code execution.
middleBrick scans identify this class of risk by correlating API specifications and runtime behavior: if an endpoint accepts JWT-authenticated requests and also triggers external commands based on token-derived data, the scan flags command injection as a high-severity finding. The scanner does not assume trust in JWT contents and tests inputs that originate from token claims to detect unsafe command construction, helping teams catch issues that static analysis might miss when validation boundaries are unclear.
Jwt Tokens-Specific Remediation in Chi — concrete code fixes
Remediation focuses on strict input validation, avoiding shell command construction from token data, and using safe abstractions. Never concatenate JWT claims into shell commands. Instead, use parameterized calls or internal libraries that do not invoke a shell. Below are concrete code examples for Chi handlers that demonstrate insecure patterns and their secure alternatives.
Insecure pattern: using a JWT claim in clojure.java.shell/sh
(require '[cheshire.core :as json]
'[clojure.java.shell :as shell]
'[buddy.sign.jwt :as jwt])
(defn insecure-handler [request]
(let [token (some-> request :headers :authorization (re-find #"Bearer (.+)") second)
claims (jwt/unsign token "weak-secret")
username (:sub claims)]
(shell/sh "echo" (str "Hello " username)))) ; Command injection risk
This handler unsigns a JWT and uses the :sub claim directly in a shell command. An attacker with a token like eyJzdWIiOiAid193b3JsZC5leGUifQ== (decoded subject dev_user.exe) could cause unexpected behavior.
Secure pattern: avoid shell execution, use internal functions
(require '[cheshire.core :as json]
'[buddy.sign.jwt :as jwt])
(defn secure-handler [request]
(let [token (some-> request :headers :authorization (re-find #"Bearer (.+)") second)
claims (jwt/unsign token "your-strong-secret")
username (:sub claims)]
;; Use internal data processing instead of shell commands
{:status 200
:body (json/generate-string {:message (str "Hello " username)})}))
By removing shell/sh and handling data in-process, you eliminate command injection. If system operations are required, map claims to a controlled set of actions (e.g., a dispatch map) rather than interpolating them into commands.
Secure pattern: parameterized shell invocation (when shell use is unavoidable)
(require '[cheshire.core :as json]
'[clojure.java.shell :as shell]
'[buddy.sign.jwt :as jwt])
(defn safe-handler [request]
(let [token (some-> request :headers :authorization (re-find #"Bearer (.+)") second)
claims (jwt/unsign token "your-strong-secret")
username (:sub claims)
allowed-users #{"alice" "bob" "charlie"}]
(if (contains? allowed-users username)
;; Use array form to avoid shell parsing; no command injection surface
(shell/sh "printf" (str "Hello %s\n" username))
{:status 403 :body "Forbidden"})))
When a shell is necessary, use the array form of sh to bypass shell word splitting and metacharacter interpretation, and validate claims against a whitelist. This approach aligns with secure coding practices for API frameworks like Chi and mitigates risks associated with JWT-derived data.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |