HIGH command injectionsinatrafirestore

Command Injection in Sinatra with Firestore

Command Injection in Sinatra with Firestore — how this specific combination creates or exposes the vulnerability

Command Injection occurs when untrusted input is concatenated into a system command and executed by the operating system. In a Sinatra application that interacts with Google Cloud Firestore, the risk emerges not from Firestore itself, but from how the application constructs shell commands that include data derived from Firestore documents or request parameters. For example, a Sinatra route might read a document ID or a user-controlled field from Firestore and then pass it to a shell utility such as gsutil, curl, or a custom binary using Ruby’s system, exec, or backticks. If the input is not strictly validated and sanitized, an attacker can inject additional shell commands, leading to arbitrary command execution on the host.

Consider a scenario where a Sinatra app retrieves a Firestore document containing a user-supplied filename and then uses that filename in a shell command to generate a report:

require 'sinatra'
require "google/cloud/firestore"

firestore = Google::Cloud::Firestore.new
bucket_ref = firestore.doc("config/report_bucket").get
bucket_name = bucket_ref[:name]

get '/generate' do
  filename = params[:filename]
  # Dangerous: user input concatenated into a shell command
  output = `gsutil cat gs://#{bucket_name}/#{filename}`
  output
end

In this example, an attacker could supply filename as ../../etc/passwd; id, causing the shell to read sensitive files and execute id. The Firestore read is benign, but the unchecked use of its data in a shell context creates the injection path.

Another pattern involves background processing or administrative scripts that use Firestore-stored configuration to invoke system tools. If a document contains a webhook URL or a command template, and the Sinatra app interpolates those values into a shell command without escaping, the attack surface expands. For instance, using system with multiple arguments can still be unsafe if the arguments are built by string interpolation rather than passed as an array:

config = firestore.doc("tools/convert").get
command = config[:path]
system("#{command} --input #{params[:input]}") # Unsafe: injection via input or command path

Even when using Firestore to store trusted configuration, the runtime values from HTTP requests remain the primary injection vector. The combination of Sinatra’s flexible routing, Ruby’s system command helpers, and Firestore as a source of dynamic data requires strict input validation and safe command construction practices to avoid Command Injection.

Firestore-Specific Remediation in Sinatra — concrete code fixes

Remediation focuses on preventing untrusted data from reaching the shell. The safest approach is to avoid shell interpolation entirely and use language-native operations. When working with Google Cloud Storage via Firestore configuration, prefer the Firestore client and Cloud Storage client libraries instead of shelling out to gsutil. Below are concrete, secure patterns for Sinatra applications.

1. Use the Cloud Storage client library instead of shell commands

Replace shell-based file access with the official Google Cloud Storage Ruby client. This eliminates shell injection and leverages built-in authentication and error handling:

require 'sinatra'
require "google/cloud/firestore"
require "google/cloud/storage"

firestore = Google::Cloud::Firestore.new
storage = Google::Cloud::Storage.new

get '/read_file' do
  bucket_name = firestore.doc("config/bucket").get[:name]
  filename = params[:filename]

  # Validate filename to prevent path traversal
  unless filename.match?(\A[a-zA-Z0-9._\-]+\z)
    halt 400, "Invalid filename"
  end

  file = storage.bucket(bucket_name).file(filename)
  if file && file.exists?
    file.download
  else
    halt 404, "File not found"
  end
end

2. If shell commands are unavoidable, use strict allowlists and the array form

When shell execution is necessary, pass arguments as an array to avoid shell word splitting and injection. Validate and restrict values to a known set:

ALLOWED_REPORTS = ["daily", "weekly", "monthly"]

get '/report' do
  report_type = params[:type]
  unless ALLOWED_REPORTS.include?(report_type)
    halt 400, "Invalid report type"
  end

  config = firestore.doc("reports/config").get
  # Safe: arguments passed as array, no shell interpolation
  output = IO.popen([config[:report_binary], "--type", report_type], &:read)
  output
end

3. Sanitize and validate all inputs derived from Firestore and HTTP sources

Treat Firestore document fields as untrusted if they can be influenced by external processes. Use strict regular expressions or allowlists for any string that will be used in system contexts. For numeric IDs, enforce integer validation:

get '/user_data' do
  user_id = params[:id].to_i
  # Additional checks can be applied, e.g., range validation
  user_doc = firestore.doc("users/#{user_id}").get
  user_doc ? user_doc.data.to_json : halt(404, "Not found")
end

By combining input validation, safe libraries, and avoiding shell interpolation, Sinatra applications can securely use Firestore data without introducing Command Injection vulnerabilities.

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

Can Command Injection occur if Firestore stores only numeric IDs?
Yes, if those numeric IDs are concatenated into shell commands without validation. Always treat Firestore fields as untrusted and validate or cast them before use.
Does middleBrick detect Command Injection risks involving Firestore in Sinatra apps?
middleBrick scans unauthenticated attack surfaces and can identify exposed endpoints and risky patterns. Refer to its findings and remediation guidance to harden Sinatra routes that interact with Firestore.