ruby.lang.security.bad-deserialization.bad-deserialization

Verifed by r2c
Community Favorite
profile photo of returntocorpreturntocorp
Author
97,918
Download Count*

Checks for unsafe deserialization. Objects in Ruby can be serialized into strings, then later loaded from strings. However, uses of load and object_load can cause remote code execution. Loading user input with MARSHAL or CSV can potentially be dangerous. Use JSON in a secure fashion instead.

Run Locally

Run in CI

Defintion

rules:
  - id: bad-deserialization
    mode: taint
    pattern-sources:
      - pattern-either:
          - pattern: params
          - pattern: cookies
    pattern-sinks:
      - pattern-either:
          - pattern: |
              CSV.load(...)
          - pattern: |
              Marshal.load(...)
          - pattern: |
              Marshal.restore(...)
          - pattern: |
              Oj.object_load(...)
          - pattern: |
              Oj.load($X)
    message: Checks for unsafe deserialization. Objects in Ruby can be serialized
      into strings, then later loaded from strings. However, uses of load and
      object_load can cause remote code execution. Loading user input with
      MARSHAL or CSV can potentially be dangerous. Use JSON in a secure fashion
      instead.
    metadata:
      references:
        - https://groups.google.com/g/rubyonrails-security/c/61bkgvnSGTQ/m/nehwjA8tQ8EJ
        - https://github.com/presidentbeef/brakeman/blob/main/lib/brakeman/checks/check_deserialize.rb
      category: security
      cwe:
        - "CWE-502: Deserialization of Untrusted Data"
      owasp:
        - A08:2017 - Insecure Deserialization
        - A08:2021 - Software and Data Integrity Failures
      technology:
        - ruby
      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]
    languages:
      - ruby
    severity: ERROR

Examples

bad-deserialization.rb

 def bad_deserialization
    o = Klass.new("hello\n")
    data = params['data']
    # ruleid: bad-deserialization
    obj = Marshal.load(data)

    o = Klass.new("hello\n")
    data = YAML.dump(o)
    # ok: bad-deserialization
    obj = YAML.load(data)

    o = Klass.new(params['hello'])
    data = CSV.dump(o)
    # ruleid: bad-deserialization
    obj = CSV.load(data)

    o = Klass.new("hello\n")
    data = cookies['some_field']
    # ruleid: bad-deserialization
    obj = Oj.object_load(data)
    # ruleid: bad-deserialization
    obj = Oj.load(data)
   # ok: bad-deserialization
   obj = Oj.load(data,options=some_safe_options)
 end

 def ok_deserialization
    o = Klass.new("hello\n")
    data = YAML.dump(o)
    # ok: bad-deserialization
    obj = YAML.load(data, safe: true)

    filename = File.read("test.txt")
    data = YAML.dump(filename)
    # ok: bad-deserialization
    YAML.load(filename)

    # ok: bad-deserialization
    YAML.load(File.read("test.txt"))
 end