Shellshock in Hanami with Mutual Tls
Shellshock in Hanami with Mutual Tls — how this specific combination creates or exposes the vulnerability
Shellshock (CVE-2014-6271 and related variants) is a command injection vulnerability in Bash that arises from improper environment variable handling. In a Hanami application, which is a Ruby web framework, Shellshock can be triggered when the app invokes system commands or spawns subprocesses with user-controlled data that propagates into the environment. This commonly occurs through CGI-style invocations, background job processors, or any code that uses system, exec, or backticks with unsanitized input.
When Mutual TLS (mTLS) is enforced, the server requests and validates client certificates. Hanami can integrate mTLS at the reverse proxy or load balancer (e.g., NGINX, HAProxy) or within the app via a middleware that inspects client certificates. If the certificate validation logic or associated metadata (such as the Common Name or Subject Alternative Names from the client certificate) is used to construct command-line arguments—intentionally or inadvertently—attackers may inject shell metacharacters into certificate fields that are later passed to Bash. For example, a malicious client certificate containing crafted values in its Distinguished Name could be concatenated into a logging or revocation-check command, turning a trusted mTLS channel into a vector for remote code execution.
In a typical Hanami deployment with mTLS, the application may rely on the web server to terminate TLS and forward client certificate details via headers (e.g., X-SSL-Client-Cert). If Hanami code parses these headers and uses them in system calls—such as invoking openssl to validate a certificate fingerprint—unsanitized input from the attacker’s certificate can lead to command injection. The combination of a framework that performs system calls and an mTLS setup that exposes attacker-influenced data increases the risk of Shellshock exploitation when input validation is insufficient.
An example of a vulnerable Hanami service might involve a background task that checks certificate revocation via a shell command:
cert_fingerprint = ENV['SSL_CLIENT_CERT_FP']
system("openssl verify -CAfile /path/to/ca.pem #{cert_fingerprint}")
If cert_fingerprint contains shell metacharacters (e.g., ; rm -rf /), the command injection occurs. MiddleBrick scans detect such patterns by correlating OpenAPI specifications with runtime behavior, identifying endpoints that accept certificate-derived input and checking for insecure command construction.
Mutual Tls-Specific Remediation in Hanami — concrete code fixes
To remediate Shellshock risks in Hanami when using mTLS, avoid passing any client-influenced data directly into shell commands. Instead, use language-native libraries for cryptographic operations and strictly validate and sanitize any data derived from mTLS certificates.
Below are concrete, secure code examples for handling mTLS in Hanami without invoking the shell.
1. Use Ruby’s OpenSSL library instead of shelling out
Replace system calls for certificate verification with Ruby’s built-in OpenSSL API. This removes the shell as an intermediary and prevents injection.
require 'openssl'
require 'base64'
cert_der = Base64.strict_decode64(ENV['SSL_CLIENT_CERT_B64'])
cert = OpenSSL::X509::Certificate.new(cert_der)
# Verify against a trusted CA store
store = OpenSSL::X509::Store.new
store.add_file('/path/to/ca.pem')
store.verify(cert)
2. Validate certificate fields safely
If you need to inspect certificate fields (e.g., Common Name), treat them as untrusted input. Do not concatenate them into commands or eval-like constructs. Use strict allowlists for expected values.
allowed_organizations = ['MyTrustedOrg']
cert = OpenSSL::X509::Certificate.new(cert_der)
subject = cert.subject
org = subject.collect(&:value).find { |val| subject.to_a.flatten.include?('O') }
if allowed_organizations.include?(org)
# Proceed with trusted logic
else
raise 'Unauthorized certificate organization'
end
3. Configure Hanami middleware to reject invalid mTLS without shell interaction
Implement a Rack middleware that validates client certificates using Ruby and integrates cleanly with Hanami’s pipeline. This avoids any need for shell-based checks.
# lib/middleware/client_cert_auth.rb
class ClientCertAuth
def initialize(app)
@app = app
end
def call(env)
cert_der = env['SSL_CLIENT_CERT']&.to_der
if cert_der
cert = OpenSSL::X509::Certificate.new(cert_der)
# Perform validation using Ruby, not shell
if valid_certificate?(cert)
@app.call(env)
else
[403, { 'Content-Type' => 'text/plain' }, ['Forbidden']]
end
else
[400, { 'Content-Type' => 'text/plain' }, ['Bad Request']]
end
end
private
def valid_certificate?(cert)
# Implement your validation logic here, e.g., check issuer, expiry, CN allowlist
true
end
end
# config/initializers/middleware.rb
Hanami.configure do
middleware.insert_after Rack::Runtime, ClientCertAuth
end
By using these approaches, you maintain the security benefits of mTLS while eliminating Shellshock risks. MiddleBrick’s scans can help verify that no dangerous shell invocations remain in your API surface and that certificate handling adheres to secure coding practices.