HIGH command injectiongrapebearer tokens

Command Injection in Grape with Bearer Tokens

Command Injection in Grape with Bearer Tokens — how this specific combination creates or exposes the vulnerability

Command Injection occurs when an API passes untrusted input directly to a system shell or to a process builder without proper sanitization or validation. In Grape, a Ruby API framework, this often manifests in endpoints that invoke system commands via system, backticks, or Open3 methods, using data that should have been controlled or validated. When Bearer Tokens are used for authentication, developers may assume that because the request includes a token, the endpoint is safe from injection. This assumption is dangerous: authentication and input validation are independent concerns.

Consider a Grape endpoint that uses a token to identify a user but then passes an unchecked parameter to a shell command. For example, an endpoint might accept a filename intended to be processed by an external tool and embed it directly in a command string. Even if the request includes a valid Bearer Token, an authenticated or unauthenticated attacker who can control the parameter can inject additional shell commands. This is because the token does not constrain what the parameter can contain; it only attests identity.

In Grape, routes are defined as classes that inherit from Grape::API. If a developer writes an endpoint like the following, the stage is set for Command Injection:

class MyResource < Grape::API
  format :json

  desc 'Process a file', requires: [:token]
  params do
    requires :filename, type: String, desc: 'Name of the file to process'
    requires :token, type: String, desc: 'Bearer token'
  end
  get :process do
    # Dangerous: directly interpolating user input into a shell command
    result = `process_file #{params[:filename]}`
    { output: result }
  end
end

In this example, the Bearer token might be validated via an before block or an authentication helper, but the filename parameter is used verbatim in a backtick command. An attacker who obtains or guesses a valid token (or sends a request without token enforcement) can manipulate filename to execute arbitrary shell commands, such as ; ls -la or | cat /etc/passwd. The token does not mitigate this because the vulnerability lies in how the input is handled, not in whether the caller is authenticated.

Grape does not inherently sanitize external input. Developers must treat all parameters as untrusted, regardless of authentication method. The combination of Grape endpoints and Bearer Tokens can create a false sense of security, leading to overlooked input validation. This is especially risky when endpoints interact with system utilities, file operations, or external scripts.

Bearer Tokens-Specific Remediation in Grape — concrete code fixes

To prevent Command Injection in Grape when using Bearer Tokens, focus on strict input validation, avoiding shell interaction, and isolating authentication from execution logic. Below are concrete, safe patterns.

1. Avoid Shell Commands Entirely

The most reliable mitigation is to avoid invoking shell commands with user input. Use native Ruby libraries for file operations instead of shelling out.

class MyResource < Grape::API
  format :json

  helpers do
    def authenticate!
      # Example: validate Bearer token
      token = request.env['HTTP_AUTHORIZATION']&.split(' ')&.last
      error!('Unauthorized', 401) unless token == 'expected-token-value'
    end
  end

  before { authenticate! }

  desc 'List directory contents', requires: [:token]
  get :list do
    # Safe: use Ruby's Dir, no shell involved
    { entries: Dir.entries('/safe/path') }
  end
end

2. Strict Allowlist Validation

If shell interaction is unavoidable, validate input against an allowlist of known-safe values.

class MyResource < Grape::API
  format :json

  params do
    requires :action, type: String, values: ['start', 'stop', 'status']
    requires :token, type: String
  end

  helpers do
    def authenticate!
      token = request.env['HTTP_AUTHORIZATION']&.split(' ')&.last
      error!('Unauthorized', 401) unless token == 'expected-token-value'
    end
  end

  before { authenticate! }

  desc 'Execute a controlled action'
  post :control do
    # Safe: only predefined actions are allowed
    case params[:action]
    when 'start'
      system('service myapp start')
    when 'stop'
      system('service myapp stop')
    when 'status'
      system('service myapp status')
    end
    { result: 'ok' }
  end
end

3. Use Open3 with Explicit Arguments

If you must execute external commands, use Open3 with an array of arguments to avoid shell interpretation.

require 'open3'

class MyResource < Grape::API
  format :json

  params do
    requires :filename, type: String, regexp: /^[a-zA-Z0-9_.-]+$/ # strict regex
    requires :token, type: String
  end

  helpers do
    def authenticate!
      token = request.env['HTTP_AUTHORIZATION']&.split(' ')&.last
      error!('Unauthorized', 401) unless token == 'expected-token-value'
    end
  end

  before { authenticate! }

  desc 'Process a file safely'
  post :process do
    # Safe: arguments passed as array, no shell interpolation
    stdout, stderr, status = Open3.capture3('process_file', params[:filename])
    { stdout: stdout, stderr: stderr, status: status.exitstatus }
  end
end

4. Centralize Authentication and Logging

Ensure Bearer Token validation is centralized and that suspicious inputs are logged for review, without relying on the token to enforce input safety.

class MyResource < Grape::API
  format :json

  helpers do
    def authenticate!
      auth_header = request.env['HTTP_AUTHORIZATION']
      unless auth_header&.start_with?('Bearer ') && valid_token?(auth_header.split(' ').last)
        error!('Unauthorized', 401)
      end
    end

    def valid_token?(token)
      # Compare tokens securely, e.g., using ActiveSupport::SecurityUtils.secure_compare
      token == 'expected-token-value'
    end
  end

  before { authenticate! }

  desc 'Safe endpoint with logging'
  params do
    requires :filename, type: String, regexp: /^[\w\-]+\.txt$/ # restrictive regex
  end
  post :upload do
    # Log potentially malicious attempts
    Rack::Logger.warn("Suspicious input: #{params[:filename]}") unless params[:filename] =~ /^safe_/ 
    { message: 'accepted' }
  end
end

In all cases, the Bearer Token ensures the caller is authenticated, but input validation and safe execution practices are required to prevent Command Injection. middleBrick can help identify such risky endpoints during scans, providing findings tied to frameworks like OWASP API Top 10.

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

Does a valid Bearer token protect my Grape endpoint from Command Injection?
No. Bearer Token authentication verifies identity but does not sanitize input. Command Injection depends on how parameters are used; always validate and avoid direct shell interpolation.
How can I test my Grape API for Command Injection without a pentest?
Use tools that support unauthenticated scanning with Bearer Token contexts. middleBrick can scan your endpoint by submitting the URL and including the token in the Authorization header to test authenticated surfaces safely.