Command Injection in Sinatra with Bearer Tokens
Command Injection in Sinatra with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Command Injection occurs when an application passes unsanitized user input to system shell commands. In Sinatra, this risk is amplified when Bearer Token handling logic is coupled with dynamic command construction, because token extraction and validation code may inadvertently pass attacker-controlled data to shell utilities. A typical pattern is reading the Authorization header, extracting the token, and then using it in a subprocess call without proper sanitization, which can allow an attacker to inject shell metacharacters.
Consider a Sinatra endpoint that validates a Bearer token by invoking an external command to inspect token metadata (for example, calling openssl or a custom script). If the token value is concatenated directly into the command string, characters such as semicolons, ampersands, or backticks enable command chaining. For example, a token like abc; cat /etc/passwd could cause the application to execute unintended commands. This becomes a full Command Injection when the runtime environment has access to a shell and the application’s process runs with elevated privileges or accesses sensitive resources.
The combination is particularly dangerous because Bearer Tokens are often treated as opaque strings, but if the application logic uses them in system-level operations (e.g., logging, revocation checks, or integration with external services) via shell commands, it exposes a pathway for attackers to escape the application context. Attack techniques resemble standard Command Injection patterns, such as using &&, ||, or newlines to chain commands. In the context of API security scanning, middleBrick identifies such unsafe consumption by correlating OpenAPI specifications with runtime behavior, flagging endpoints where token-derived input flows into subprocess execution without validation or escaping.
An example vulnerable Sinatra route:
require 'sinatra'
require 'json'
get '/validate' do
auth = request.env['HTTP_AUTHORIZATION']
if auth && auth.start_with?('Bearer ')
token = auth.split(' ').last
# Unsafe: token used directly in shell command
result = `openssl enc -d -in token.bin -k #{token}`
{ result: result }.to_json
else
status 401
{ error: 'Missing or invalid Authorization header' }.to_json
end
end
In this snippet, the token extracted from the Bearer header is interpolated into an OpenSSL command. An attacker supplying a token like dummy && id could execute arbitrary commands. middleBrick’s 12 security checks, including Unsafe Consumption and Input Validation, detect this by analyzing the spec-to-runtime data flow and highlighting where uncontrolled input reaches shell-level operations.
Bearer Tokens-Specific Remediation in Sinatra — concrete code fixes
Remediation focuses on eliminating shell command construction entirely or strictly validating and isolating any external invocation. The safest approach is to avoid system commands for token handling and use native Ruby libraries for cryptographic or validation tasks. When external commands are unavoidable, use parameterized execution that bypasses the shell.
First, prefer pure-Ruby validation instead of shelling out. For JWT validation, use a library like jwt to decode and verify signatures without invoking external processes:
require 'sinatra'
require 'json'
require 'jwt'
SECRET_KEY = 'your-secret'
get '/validate' do
auth = request.env['HTTP_AUTHORIZATION']
if auth && auth.start_with?('Bearer ')
token = auth.split(' ').last
begin
decoded = JWT.decode(token, SECRET_KEY, true, { algorithm: 'HS256' })
{ valid: true, payload: decoded.first }.to_json
rescue JWT::DecodeError
status 401
{ error: 'Invalid token' }.to_json
end
else
status 401
{ error: 'Missing or invalid Authorization header' }.to_json
end
end
If you must invoke an external binary, avoid shell interpolation by using Open3.capture3 with explicit argument arrays, which prevents the shell from interpreting metacharacters in the token:
require 'sinatra'
require 'json'
require 'open3'
get '/validate' do
auth = request.env['HTTP_AUTHORIZATION']
if auth && auth.start_with?('Bearer ')
token = auth.split(' ').last
# Safe: arguments passed as array, no shell interpolation
stdout, stderr, status = Open3.capture3('openssl', 'enc', '-d', '-in', 'token.bin', '-k', token)
if status.success?
{ result: stdout }.to_json
else
status 500
{ error: stderr }.to_json
end
else
status 401
{ error: 'Missing or invalid Authorization header' }.to_json
end
end
Additionally, enforce strict input validation by whitelisting allowed characters in the token before any processing. Although Bearer tokens are typically base64url-encoded, you can reject tokens containing shell-dangerous characters when they must be used in external contexts:
require 'sinatra'
require 'json'
def safe_token?(token)
# Allow only base64url-safe characters
token.match?(\A[a-zA-Z0-9\-_]+\z)
end
get '/validate' do
auth = request.env['HTTP_AUTHORIZATION']
if auth && auth.start_with?('Bearer ')
token = auth.split(' ').last
unless safe_token?(token)
status 400
{ error: 'Invalid token format' }.to_json
end
# Proceed with safe token usage
{ received: token[0..10] + '...' }.to_json
else
status 401
{ error: 'Missing or invalid Authorization header' }.to_json
end
end
middleBrick’s GitHub Action can be added to CI/CD pipelines to automatically flag endpoints where token-derived input reaches subprocess calls, ensuring that future changes do not reintroduce Unsafe Consumption or improper input handling. The CLI tool also supports scanning these patterns locally during development.
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 |