Skip to main content

    Code injection prevention for Ruby

    This is a code injection prevention cheat sheet by Semgrep, Inc. It contains code patterns of potential ways to run arbitrary code in an application. Instead of scrutinizing code for exploitable vulnerabilities, the recommendations in this cheat sheet pave a safe road for developers that mitigate the possibility of code injection in your code. By following these recommendations, you can be reasonably sure your code is free of code injection.

    Check your project using Semgrep

    The following command runs an optimized set of rules for your project:

    semgrep --config p/default

    1. Evaluating code

    1.A. Evaluating code with eval

    Evaluating code can be dangerous if dynamic content is used as input. If this input originates from outside of the program it can lead to a code injection vulnerability.

    Examples:

    # safe
    str = "hello"
    eval "str + ' Fred'"

    # vulnerable
    str = "hello"
    user_input = "system('cat /etc/passwd')" # Value supplied by user
    eval "str + #{user_input}"
    class Thing
    end

    # safe
    Thing.module_eval(%q{def hello() "Hello there!" end})

    # vulnerable
    user_input = "system('cat /etc/passwd')" # Value supplied by user
    Thing.module_eval(%q{def hello() "#{user_input}" end})

    References

    Mitigation

    • Don't use eval(), class_eval(), module_eval(), or instance_eval() if possible.
    • If you need to use eval(), class_eval(), module_eval(), or instance_eval() with non-literal values, ensure that executed content is not controllable by external sources.
    • If it's not possible, strip everything except alphanumeric characters from the input.

    Semgrep rule

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

    1.B. Evaluating code with RubyVM::InstructionSequence

    The InstructionSequence class represents compiled instructions for the Ruby Virtual Machine. See details in RubyVM::InstructionSequence documentation. The RubyVM class itself is not intended for regular users. As the RubyVM class enables compiling code it may insecurely interpret user input. Providing user input to this class or its methods can result in a code injection vulnerability.

    Example:

    # safe
    RubyVM::InstructionSequence.compile("a = 1 + 2")

    # vulnerable
    user_input = "system('cat /etc/passwd')" # Value supplied by user
    RubyVM::InstructionSequence.compile("a = 1 + #{user_input}")

    References

    Mitigation

    • Don't use RubyVM, or RubyVM::InstructionSequence if possible.
    • If you need to use RubyVM or RubyVM::InstructionSequence with non-literal values or user input, ensure that inputs are from trusted sources.

    Semgrep rule

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

    Not finding what you need in this doc? Ask questions in our Community Slack group, or see Support for other ways to get help.