ruby.rails.security.injection.tainted-url-host.tainted-url-host

profile photo of semgrepsemgrep
Author
unknown
Download Count*

User data flows into the host portion of this manually-constructed URL. This could allow an attacker to send data to their own server, potentially exposing sensitive data such as cookies or authorization information sent with this request. They could also probe internal servers or other resources that the server runnig this code can access. (This is called server-side request forgery, or SSRF.) Do not allow arbitrary hosts. Use the ssrf_filter gem and guard the url construction with SsrfFilter(...), or create an allowlist for approved hosts.

Run Locally

Run in CI

Defintion

rules:
  - id: tainted-url-host
    languages:
      - ruby
    severity: WARNING
    message: User data flows into the host portion of this manually-constructed URL.
      This could allow an attacker to send data to their own server, potentially
      exposing sensitive data such as cookies or authorization information sent
      with this request. They could also probe internal servers or other
      resources that the server runnig this code can access. (This is called
      server-side request forgery, or SSRF.) Do not allow arbitrary hosts. Use
      the `ssrf_filter` gem and guard the url construction with
      `SsrfFilter(...)`, or create an allowlist for approved hosts.
    metadata:
      cwe:
        - "CWE-79: Improper Neutralization of Input During Web Page Generation
          ('Cross-site Scripting')"
      owasp:
        - A07:2017 - Cross-Site Scripting (XSS)
        - A03:2021 - Injection
      category: security
      technology:
        - rails
      references:
        - https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html
        - https://github.com/arkadiyt/ssrf_filter
      cwe2022-top25: true
      cwe2021-top25: true
      subcategory:
        - vuln
      likelihood: MEDIUM
      impact: HIGH
      confidence: MEDIUM
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Cross-Site-Scripting (XSS)
    mode: taint
    pattern-sanitizers:
      - pattern: SsrfFilter
    pattern-sources:
      - patterns:
          - pattern-either:
              - pattern: params
              - pattern: request
    pattern-sinks:
      - patterns:
          - pattern-either:
              - patterns:
                  - pattern: |
                      $URLSTR
                  - pattern-regex: \w+:\/\/#{.*}
              - patterns:
                  - pattern-either:
                      - pattern: Kernel::sprintf("$URLSTR", ...)
                      - pattern: |
                          "$URLSTR" + $EXPR
                      - pattern: |
                          "$URLSTR" % $EXPR
                  - metavariable-pattern:
                      metavariable: $URLSTR
                      language: generic
                      pattern: $SCHEME:// ...

Examples

tainted-url-host.rb

# cf. https://github.com/rails/rails/blob/939fe523126198d43ecedeacc05dd7fdb1eae3d9/actionpack/test/controller/action_pack_assertions_test.rb

# frozen_string_literal: true

require "abstract_unit"
require "controller/fake_controllers"
require "ssrf_filter"

class ActionPackAssertionsController < ActionController::Base
  def nothing() head :ok end

  # ok: tainted-url-host
  def hello_xml_world() render template: "test/hello_xml_world"; end

  def assign_this
    @howdy = "ho"
    # ok: tainted-url-host
    render inline: "Mr. Henke"
  end

  def render_based_on_parameters
    # ok: tainted-url-host
    render plain: "Mr. #{params[:name]}"
  end

  def render1
    # ruleid: tainted-url-host
    render inline: "<a href='http://#{params[:name]}/path'></div>"
  end

  def render2
    # ruleid: tainted-url-host
    render inline: "<a href='https://%s/path'></div>" % params[:name]
  end

  def render3
    name = params[:name]
    # ruleid: tainted-url-host
    render inline: "https://%s/%s" % name, "blah"
  end

  def render4
    name = params[:name]
    # ruleid: tainted-url-host
    render inline: Kernel::sprintf("ws://%s", name)
  end

  def render_boo
    # ok: tainted-url-host
    render html: "boo, %s" % params[:name]
  end

  def raise_exception_on_post_ok
    raise "post" if request.post?
    # ok: tainted-url-host
    render plain: strip_tags("<h1>request method: %s</h1>" % request.env['REQUEST_METHOD'])
  end

  def raise_exception_on_post_ok2
    raise "post" if request.post?
    # ok: tainted-url-host
    render plain: sanitize("<h1>request method: %s</h1>" % request.env['REQUEST_METHOD'])
  end

  def sanitized
    # ok: tainted-url-host
    response = SsrfFilter.get(params[:url])
    response
  end
end