HIGH command injectiongrape

Command Injection in Grape

How Command Injection Manifests in Grape

Command injection vulnerabilities in Grape APIs occur when user input is passed directly to system commands without proper sanitization. In Grape applications, this typically happens through endpoints that interact with the operating system, execute shell commands, or interface with external processes.

A common pattern in Grape APIs is accepting file paths or identifiers from request parameters and using them in system calls. For example:

post '/execute' do
  command = params[:command]
  result = `#{command}`
  { output: result }
end

This endpoint is vulnerable because it directly interpolates user input into a shell command. An attacker could send command=id; cat /etc/passwd to execute arbitrary commands on the server.

Another Grape-specific scenario involves file operations. Consider this endpoint that processes uploaded files:

post '/process' do
  filename = params[:filename]
  `convert #{filename} -resize 200x200 output.png`
  { status: 'processed' }
end

If an attacker uploads a file named test.png; rm -rf /, the shell will execute both the convert command and the malicious rm command.

Environment variable manipulation is another vector. Grape APIs often use environment variables for configuration, but if these are exposed or manipulated through endpoints:

get '/env' do
  var = params[:var]
  `echo $#{var}`
end

An attacker could use var=PATH; ls / to list directory contents or access sensitive information.

Process spawning functions in Ruby are particularly dangerous when used in Grape APIs. The system, exec, and backtick operators all invoke the shell, creating injection opportunities:

post '/run' do
  program = params[:program]
  system(program)
end

Even seemingly safe operations can be vulnerable. File path traversal combined with command execution:

get '/file' do
  path = params[:path]
  `cat #{path}`
end

An attacker could use path=/etc/passwd; ls -la to read files and list directories.

Grape-Specific Detection

Detecting command injection in Grape APIs requires both static code analysis and dynamic runtime testing. Static analysis tools can identify dangerous patterns like string interpolation in system calls, but they may miss context-specific vulnerabilities.

middleBrick's black-box scanning approach is particularly effective for Grape APIs because it tests the actual runtime behavior without requiring source code access. The scanner identifies command injection by:

  • Testing parameter injection points with known shell metacharacters (;, &, &&, ||, |)
  • Analyzing HTTP response codes and timing to detect successful command execution
  • Checking for command output in API responses
  • Testing common injection payloads like id, whoami, and ls

For Grape APIs specifically, middleBrick scans for patterns common in Ruby web applications:

# Dangerous patterns middleBrick detects
`#{user_input}`          # Backtick execution
exec(user_input)        # Direct exec
Kernel.system(user_input) # System call
IO.popen(user_input)    # Pipe execution
Open3.capture3(user_input) # Capture execution

The scanner also tests for indirect command injection through file operations, environment variable usage, and process spawning functions that Grape APIs commonly employ.

middleBrick's LLM/AI security module adds another layer of detection for Grape APIs that use AI/ML features. It tests for prompt injection that could lead to command execution through AI model interfaces, a growing concern as APIs integrate with language models.

Runtime detection in development environments can include monitoring system calls and logging suspicious patterns. Tools like strace or Ruby's Process::Status can help identify when user input reaches system commands.

Grape-Specific Remediation

Remediating command injection in Grape APIs requires eliminating shell command execution entirely or implementing strict input validation and parameterization. The safest approach is to avoid shell commands whenever possible.

Instead of using shell commands for file operations, use Ruby's native file handling:

# Vulnerable
`cat #{path}`

# Secure
File.read(path)

For image processing that might have used ImageMagick commands, use Ruby libraries:

# Vulnerable
`convert #{filename} -resize 200x200 output.png`

# Secure
require 'mini_magick'
image = MiniMagick::Image.open(filename)
image.resize('200x200')
image.write('output.png')

When shell commands are unavoidable, use the multi-argument form that bypasses the shell:

# Vulnerable - shell interpolation
`ls -la #{dir}`

# Secure - array form, no shell
system('ls', '-la', dir)

For complex commands, use Ruby's Open3 with explicit argument arrays:

require 'open3'

# Secure - explicit arguments
command = ['find', dir, '-name', '*.rb']
stdout, stderr, status = Open3.capture3(*command)

Input validation is critical. Implement strict whitelisting for acceptable inputs:

# Allow only alphanumeric filenames
def sanitize_filename(name)
  return nil unless name =~ /\/(^[a-zA-Z0-9_\-\.]+$)/
  name
end

# Validate paths against allowed directories
def validate_path(path, base_dir)
  full_path = File.expand_path(path, base_dir)
  return nil unless full_path.start_with?(base_dir)
  full_path
end

For Grape APIs, use parameter validation with Grape's built-in features:

module API
  class SecureAPI < Grape::API
    params do
      requires :command, type: String, regexp: /\/(^[a-zA-Z0-9_\-\.]+$)/
    end
    post '/execute' do
      # Safe because regex validation occurred
      command = params[:command]
      # Use safe execution method
      result = safe_execute(command)
      { output: result }
    end
  end
end

Implement a security middleware in Grape to scan for dangerous patterns before execution:

class CommandInjectionProtection
  DANGEROUS_PATTERNS = [
    /;\|s\|/,
    /\&\/u,
    /\|\/u,
    /\$\{(.*?)\}\/u
  ]

  def initialize(app)
    @app = app
  end

  def call(env)
    # Check for dangerous patterns in parameters
    params = Rack::Request.new(env).params
    if contains_dangerous_patterns?(params)
      return [400, {}, ['Forbidden: potential command injection']]
    end
    @app.call(env)
  end

  private

  def contains_dangerous_patterns?(params)
    params.values.any? do |value|
      next false unless value.is_a?(String)
      DANGEROUS_PATTERNS.any? { |pattern| pattern.match?(value) }
    end
  end
end

Finally, implement comprehensive logging and monitoring for any remaining system interactions to detect attempted exploitation:

# Log all system command executions
def safe_execute(command, *args)
  logger.warn("Executing system command: #{command} #{args.join(' ')}")
  system(command, *args)
rescue StandardError => e
  logger.error("System command failed: #{e.message}")
  raise
end

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

How can I test my Grape API for command injection vulnerabilities?
Use middleBrick's black-box scanning by submitting your API URL - it tests for command injection by injecting shell metacharacters and analyzing responses. For manual testing, try payloads like test; whoami or test && ls -la in parameters that might reach system commands. Look for command output in responses or changes in HTTP status codes.
What's the difference between command injection and SQL injection in Grape APIs?
Command injection targets the operating system shell and can execute arbitrary OS commands, potentially giving full server access. SQL injection targets database queries. While both involve injecting malicious input, command injection is often more severe because it can lead to complete system compromise, data exfiltration, or lateral movement within your network.