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

profile photo of semgrepsemgrep
Author
unknown
Download Count*

Unsafe deserialization from YAML. 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 YAML can potentially be dangerous. Use JSON in a secure fashion instead. However, loading YAML from a static file is not dangerous and should not be flagged.

Run Locally

Run in CI

Defintion

rules:
  - id: bad-deserialization-yaml
    patterns:
      - pattern: |
          YAML.load($...ARGS)
      - pattern-not: |
          YAML.load(..., safe: true, ...)
      - pattern-not: |
          YAML.load("...", ...)
      - pattern-not-inside: |
          YAML.load(..., File.read(...), ...)
      - pattern-not-inside: |
          $FILE = File.read(...)
          ...
          YAML.load(..., $FILE, ...)
      - pattern-not-inside: |
          $FILENAME = ...
          ...
          $FILE = File.read($FILENAME, ...)
          ...
          YAML.load(..., $FILE, ...)
      - pattern-not-inside: |
          YAML.load(..., $X.$Y(File.read(...)), ...)
      - pattern-not-inside: |
          YAML.load(..., $X.$Y(File.read(...)).$Z, ...)
      - pattern-not-inside: |
          $T = $MOD.$MET(File.read(...))
          ...
          YAML.load(..., $T, ...)
      - pattern-not-inside: |
          $T = $MOD.$MET(File.read(...))
          ...
          YAML.load(..., $T.$R, ...)
    fix: Psych.safe_load($...ARGS)
    message: Unsafe deserialization from YAML. 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 YAML
      can potentially be dangerous. Use JSON in a secure fashion instead.
      However, loading YAML from a static file is not dangerous and should not
      be flagged.
    metadata:
      cwe:
        - "CWE-502: Deserialization of Untrusted Data"
      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
      technology:
        - ruby
        - yaml
      owasp:
        - A08:2017 - Insecure Deserialization
        - A08:2021 - Software and Data Integrity Failures
      cwe2022-top25: true
      cwe2021-top25: true
      subcategory:
        - audit
      likelihood: LOW
      impact: HIGH
      confidence: LOW
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - "Insecure Deserialization "
    languages:
      - ruby
    severity: ERROR

Examples

bad-deserialization-yaml.rb

def bad_deserialization

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

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

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

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

   # ok: bad-deserialization-yaml
   obj = YAML::load(ERB.new(File.read("test.yml")).result)
   
   # ok: bad-deserialization-yaml
   obj = YAML::load(ERB.new(File.read("test.yml")))

   template = ERB.new(File.read("test.yml"))
   # ok: bad-deserialization-yaml
   obj = YAML::load(template)

   template = ERB.new(File.read("test.yml")).result
   # ok: bad-deserialization-yaml
   obj = YAML::load(template)

   template = ERB.new(File.read("test.yml"))
   # ok: bad-deserialization-yaml
   obj = YAML::load(template.result)

   # ok: bad-deserialization-yaml
   obj = YAML.load(File.read(File.join(Pathname.pwd, "hello.yml")))
end