HIGH command injectionrailsjwt tokens

Command Injection in Rails with Jwt Tokens

Command Injection in Rails with Jwt Tokens — how this specific combination creates or exposes the vulnerability

Command injection in Ruby on Rails occurs when untrusted input is concatenated into system commands executed via system, exec, or backticks. When JWT tokens are involved, risk arises at two points: (1) the token payload is untrusted input that may be passed into shell commands, and (2) token handling code may be improperly secured, enabling an attacker to influence command execution indirectly.

Consider a Rails service that decodes a JWT and uses a claim to build a shell command. If the developer does not validate or sanitize the claim, an attacker can supply a malicious token with a crafted payload that leads to command injection. For example, a token containing { "org": "acme; id" } could be interpolated into a system call:

payload = { "org" => "acme; id" }
org = payload["org"]
system("curl https://api.example.com/org/#{org}")

Here, the attacker-controlled claim org appends ; id to the URL argument, but because the value is used in a shell context, command injection becomes possible. Even if the JWT signature is verified, the decoded claims must be treated as untrusted input.

Another scenario involves background jobs or admin tooling that reads JWTs from logs, headers, or parameters and passes them to diagnostic commands. If the token is logged and later used in a shell script without escaping, an attacker who can influence the token (e.g., via account registration or a compromised client) may inject commands through log injection or indirect execution paths.

JWT-specific risk also emerges when token handling libraries or custom middleware expose debug endpoints that echo token contents to shell commands for troubleshooting. Such endpoints should never be exposed in production, as they provide a direct injection vector tied to the token’s contents.

Because middleBrick scans the unauthenticated attack surface, it can detect endpoints where JWT claims are reflected into command-like behavior without proper input validation, highlighting the absence of sandboxing or strict allowlists for external input.

Jwt Tokens-Specific Remediation in Rails — concrete code fixes

To remediate command injection when using JWT tokens in Rails, avoid shell interpolation entirely and use safe patterns. Never pass untrusted token claims directly to system, exec, or backticks. Instead, use language-native libraries or APIs that do not invoke a shell, and enforce strict allowlists for any values that must influence behavior.

1. Use Ruby native methods instead of shell commands

Replace shell-based operations with Ruby or language-safe libraries. For example, use an HTTP client rather than curl:

require 'net/http'
require 'uri'
payload = { "org" => "acme" }
org = payload["org"]
uri = URI("https://api.example.com/org/#{org}")
response = Net::HTTP.get(uri)

This approach removes the shell from the execution path, eliminating command injection risk regardless of token content.

2. If shell commands are unavoidable, use strict allowlists and escaping

When shell interaction is necessary, validate and restrict input to a known set of safe values, and escape all dynamic parts. For example:

allowed_orgs = %w[acme example trusted]
org = payload["org"]
if allowed_orgs.include?(org)
  system("curl", "https://api.example.com/org/#{org}")
else
  raise "Invalid org"
end

Using the multi-argument form of system bypasses shell interpolation, but you must still validate each argument. Do not rely on escaping user input for shell commands; prefer native alternatives.

3. Secure JWT verification and claim handling

Ensure JWT verification is performed with a trusted library and that claims are validated before use. Do not use token contents to construct command arguments without strict validation:

begin
  decoded = JWT.decode(token, Rails.application.secrets.secret_key_base, true, { algorithm: 'HS256' })
  claims = decoded.first
rescue JWT::DecodeError
  head :unauthorized
  return
end

After decoding, apply allowlists and schema checks to claims. Treat the token as an opaque credential for authentication, not as a source of shell parameters.

4. Audit logging without shell exposure

If logging or tooling requires inspecting token contents, ensure logs are written safely and never passed to shell commands. Use structured logging and avoid string interpolation into shell-like contexts.

middleBrick’s LLM/AI Security checks include system prompt leakage and active prompt injection testing, which can surface risky patterns where token-derived data might reach unintended execution paths. The scanner also checks for Input Validation and Unsafe Consumption issues, helping you identify places where JWT claims could be improperly handled.

By combining secure JWT handling with safe command execution patterns, you reduce the attack surface and prevent command injection even when tokens are involved.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

If my JWTs are signed, are the claims safe to use in system commands?
No. Signature verification ensures the token hasn’t been tampered with, but it does not make claims safe for shell use. Always treat decoded claims as untrusted input and avoid interpolating them into commands; use native libraries and strict allowlists.
Can middleBrick detect command injection risks that involve JWT tokens?
Yes. middleBrick tests unauthenticated attack surfaces and includes Input Validation and Unsafe Consumption checks that can identify endpoints where JWT claims are reflected into command-like behavior without proper sanitization or allowlisting.