ruby.lang.security.no-eval.ruby-eval

Community Favorite
profile photo of semgrepsemgrep
Author
46,113
Download Count*

Use of eval with user-controllable input detected. This can lead to attackers running arbitrary code. Ensure external data does not reach here, otherwise this is a security vulnerability. Consider other ways to do this without eval.

Run Locally

Run in CI

Defintion

rules:
  - id: ruby-eval
    message: Use of eval with user-controllable input detected. This can lead  to
      attackers running arbitrary code. Ensure external data does not  reach
      here, otherwise this is a security vulnerability. Consider  other ways to
      do this without eval.
    severity: WARNING
    metadata:
      likelihood: HIGH
      impact: MEDIUM
      confidence: MEDIUM
      category: security
      cwe2022-top25: true
      cwe2021-top25: true
      cwe:
        - "CWE-94: Improper Control of Generation of Code ('Code Injection')"
      owasp:
        - A03:2021 - Injection
      references:
        - https://owasp.org/Top10/A03_2021-Injection
      source-rule-url: https://github.com/presidentbeef/brakeman/blob/main/lib/brakeman/checks/check_evaluation.rb
      subcategory:
        - vuln
      technology:
        - ruby
        - rails
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Code Injection
    languages:
      - ruby
    mode: taint
    pattern-sources:
      - pattern-either:
          - pattern: params
          - pattern: cookies
          - patterns:
              - pattern: |
                  RubyVM::InstructionSequence.compile(...)
              - pattern-not: |
                  RubyVM::InstructionSequence.compile("...")
    pattern-sinks:
      - patterns:
          - pattern-either:
              - pattern: $X.eval
              - pattern: $X.class_eval
              - pattern: $X.instance_eval
              - pattern: $X.module_eval
              - pattern: $X.eval(...)
              - pattern: $X.class_eval(...)
              - pattern: $X.instance_eval(...)
              - pattern: $X.module_eval(...)
              - pattern: eval(...)
              - pattern: class_eval(...)
              - pattern: module_eval(...)
              - pattern: instance_eval(...)
          - pattern-not: $M("...",...)

Examples

no-eval.rb

# ruleid:ruby-eval
Array.class_eval(cookies['tainted_cookie'])

def zen
  41
end

# ok:ruby-eval
eval("def zen; 42; end")

puts zen

class Thing
end
a = %q{def hello() "Hello there!" end}
# not user-controllable, this is ok
# ok:ruby-eval
Thing.module_eval(a)
puts Thing.new.hello()
b = params['something']
# ruleid:ruby-eval
Thing.module_eval(b)

# ruleid:ruby-eval
eval(b)
# ruleid:ruby-eval
eval(b,some_binding)

def get_binding(param)
  binding
end
b = get_binding("hello")
# ok:ruby-eval
b.eval("some_func")

# ok:ruby-eval
eval("some_func",b)

# ruleid:ruby-eval
eval(params['cmd'],b)

# ruleid:ruby-eval
eval(params.dig('cmd'))

# ruleid:ruby-eval
eval(cookies.delete('foo'))

# ruleid:ruby-eval
RubyVM::InstructionSequence.compile(foo).eval

# ok:ruby-eval
RubyVM::InstructionSequence.compile("1 + 2").eval

iseq = RubyVM::InstructionSequence.compile(foo)
# ruleid:ruby-eval
iseq.eval


iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
# ok:ruby-eval
iseq.eval