brakeman-lib 4.8.2 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES.md +13 -0
- data/lib/brakeman.rb +16 -0
- data/lib/brakeman/checks/check_csrf_token_forgery_cve.rb +28 -0
- data/lib/brakeman/checks/check_deserialize.rb +21 -1
- data/lib/brakeman/checks/check_mass_assignment.rb +19 -4
- data/lib/brakeman/checks/check_model_attr_accessible.rb +1 -1
- data/lib/brakeman/checks/check_permit_attributes.rb +1 -1
- data/lib/brakeman/checks/check_skip_before_filter.rb +4 -4
- data/lib/brakeman/checks/check_template_injection.rb +32 -0
- data/lib/brakeman/commandline.rb +25 -1
- data/lib/brakeman/options.rb +4 -0
- data/lib/brakeman/processors/alias_processor.rb +2 -3
- data/lib/brakeman/processors/lib/find_all_calls.rb +27 -12
- data/lib/brakeman/report/ignore/config.rb +4 -0
- data/lib/brakeman/scanner.rb +4 -1
- data/lib/brakeman/tracker.rb +3 -1
- data/lib/brakeman/tracker/constants.rb +8 -7
- data/lib/brakeman/util.rb +16 -0
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning_codes.rb +2 -0
- metadata +20 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 43b7d1a166362e6f078be06194adde0e9acc6f6ee5bbe6b54212a4dddb0335ad
         | 
| 4 | 
            +
              data.tar.gz: fd3fcf8965f5125991e51dce67d18415ca3f5db6f431a4076c16acbf1a3bd906
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: a929f04cb48c9ccb434cfa3ee47791d263a1fc3d30acdea4459c25c8c7bcab7d72887369f893de1eed5418a059dd07e55a98157bd2729967f1b9e4c72a4b94f5
         | 
| 7 | 
            +
              data.tar.gz: ead62901264f2d1230512894820ad8160ce6115a19ac32dd2ea3474ebb9b9a723e2090077ea6780b38c0b9d3f3b59e4c93ad55d8dbf613f9426475796a167ab3
         | 
    
        data/CHANGES.md
    CHANGED
    
    | @@ -1,3 +1,16 @@ | |
| 1 | 
            +
            # 4.9.0 - 2020-08-04
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            * Add check for CVE-2020-8166 (Jamie Finnigan)
         | 
| 4 | 
            +
            * Avoid warning when `safe_yaml` is used via `YAML.load(..., safe: true)`
         | 
| 5 | 
            +
            * Add check for user input in `ERB.new` (Matt Hickman)
         | 
| 6 | 
            +
            * Add `--ensure-ignore-notes` (Eli Block)
         | 
| 7 | 
            +
            * Remove whitelist/blacklist language, add clarifications
         | 
| 8 | 
            +
            * Do not warn about mass assignment with `params.permit!.slice`
         | 
| 9 | 
            +
            * Add "full call" information to call index results
         | 
| 10 | 
            +
            * Ignore `params.permit!` in path helpers
         | 
| 11 | 
            +
            * Treat `Dir.glob` as safe source of values in guards
         | 
| 12 | 
            +
            * Always scan `environment.rb`
         | 
| 13 | 
            +
             | 
| 1 14 | 
             
            # 4.8.2 - 2020-05-12
         | 
| 2 15 |  | 
| 3 16 | 
             
            * Add check for CVE-2020-8159
         | 
    
        data/lib/brakeman.rb
    CHANGED
    
    | @@ -20,6 +20,10 @@ module Brakeman | |
| 20 20 | 
             
              #option is set
         | 
| 21 21 | 
             
              Errors_Found_Exit_Code = 7
         | 
| 22 22 |  | 
| 23 | 
            +
              #Exit code returned when an ignored warning has no note and
         | 
| 24 | 
            +
              #--ensure-ignore-notes is set
         | 
| 25 | 
            +
              Empty_Ignore_Note_Exit_Code = 8
         | 
| 26 | 
            +
             | 
| 23 27 | 
             
              @debug = false
         | 
| 24 28 | 
             
              @quiet = false
         | 
| 25 29 | 
             
              @loaded_dependencies = []
         | 
| @@ -498,6 +502,18 @@ module Brakeman | |
| 498 502 | 
             
                end
         | 
| 499 503 | 
             
              end
         | 
| 500 504 |  | 
| 505 | 
            +
              # Returns an array of alert fingerprints for any ignored warnings without
         | 
| 506 | 
            +
              # notes found in the specified ignore file (if it exists).
         | 
| 507 | 
            +
              def self.ignore_file_entries_with_empty_notes file
         | 
| 508 | 
            +
                return [] unless file
         | 
| 509 | 
            +
             | 
| 510 | 
            +
                require 'brakeman/report/ignore/config'
         | 
| 511 | 
            +
             | 
| 512 | 
            +
                config = IgnoreConfig.new(file, nil)
         | 
| 513 | 
            +
                config.read_from_file
         | 
| 514 | 
            +
                config.already_ignored_entries_with_empty_notes.map { |i| i[:fingerprint] }
         | 
| 515 | 
            +
              end
         | 
| 516 | 
            +
             | 
| 501 517 | 
             
              def self.filter_warnings tracker, options
         | 
| 502 518 | 
             
                require 'brakeman/report/ignore/config'
         | 
| 503 519 |  | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            require 'brakeman/checks/base_check'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class Brakeman::CheckCSRFTokenForgeryCVE < Brakeman::BaseCheck
         | 
| 4 | 
            +
              Brakeman::Checks.add self
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              @description = "Checks for versions with CSRF token forgery vulnerability (CVE-2020-8166)"
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              def run_check
         | 
| 9 | 
            +
                fix_version = case
         | 
| 10 | 
            +
                  when version_between?('0.0.0', '5.2.4.2')
         | 
| 11 | 
            +
                    '5.2.4.3'
         | 
| 12 | 
            +
                  when version_between?('6.0.0', '6.0.3')
         | 
| 13 | 
            +
                    '6.0.3.1'
         | 
| 14 | 
            +
                  else
         | 
| 15 | 
            +
                    nil
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                if fix_version
         | 
| 19 | 
            +
                  warn :warning_type => "Cross-Site Request Forgery",
         | 
| 20 | 
            +
                    :warning_code => :CVE_2020_8166,
         | 
| 21 | 
            +
                    :message => msg(msg_version(rails_version), " has a vulnerability that may allow CSRF token forgery. Upgrade to ", msg_version(fix_version), " or patch"),
         | 
| 22 | 
            +
                    :confidence => :medium,
         | 
| 23 | 
            +
                    :gem_info => gemfile_or_environment,
         | 
| 24 | 
            +
                    :link => "https://groups.google.com/g/rubyonrails-security/c/NOjKiGeXUgw"
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
            end
         | 
| 28 | 
            +
             | 
| @@ -13,7 +13,23 @@ class Brakeman::CheckDeserialize < Brakeman::BaseCheck | |
| 13 13 | 
             
              end
         | 
| 14 14 |  | 
| 15 15 | 
             
              def check_yaml
         | 
| 16 | 
            -
                check_methods :YAML, : | 
| 16 | 
            +
                check_methods :YAML, :load_documents, :load_stream, :parse_documents, :parse_stream
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                # Check for safe_yaml gem use with YAML.load(..., safe: true)
         | 
| 19 | 
            +
                if uses_safe_yaml?
         | 
| 20 | 
            +
                  tracker.find_call(target: :YAML, method: :load).each do |result|
         | 
| 21 | 
            +
                    call = result[:call]
         | 
| 22 | 
            +
                    options = call.second_arg
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    if hash? options and true? hash_access(options, :safe)
         | 
| 25 | 
            +
                      next
         | 
| 26 | 
            +
                    else
         | 
| 27 | 
            +
                      check_deserialize result, :YAML
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
                else
         | 
| 31 | 
            +
                  check_methods :YAML, :load
         | 
| 32 | 
            +
                end
         | 
| 17 33 | 
             
              end
         | 
| 18 34 |  | 
| 19 35 | 
             
              def check_csv
         | 
| @@ -102,4 +118,8 @@ class Brakeman::CheckDeserialize < Brakeman::BaseCheck | |
| 102 118 |  | 
| 103 119 | 
             
                false
         | 
| 104 120 | 
             
              end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
              def uses_safe_yaml?
         | 
| 123 | 
            +
                tracker.config.has_gem? :safe_yaml
         | 
| 124 | 
            +
              end
         | 
| 105 125 | 
             
            end
         | 
| @@ -160,12 +160,27 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck | |
| 160 160 | 
             
              # Look for and warn about uses of Parameters#permit! for mass assignment
         | 
| 161 161 | 
             
              def check_permit!
         | 
| 162 162 | 
             
                tracker.find_call(:method => :permit!, :nested => true).each do |result|
         | 
| 163 | 
            -
                  if params? result[:call].target | 
| 164 | 
            -
                     | 
| 163 | 
            +
                  if params? result[:call].target
         | 
| 164 | 
            +
                    unless inside_safe_method? result or calls_slice? result
         | 
| 165 | 
            +
                      warn_on_permit! result
         | 
| 166 | 
            +
                    end
         | 
| 165 167 | 
             
                  end
         | 
| 166 168 | 
             
                end
         | 
| 167 169 | 
             
              end
         | 
| 168 170 |  | 
| 171 | 
            +
              # Ignore blah_some_path(params.permit!)
         | 
| 172 | 
            +
              def inside_safe_method? result
         | 
| 173 | 
            +
                parent_call = result.dig(:parent, :call)
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                call? parent_call and
         | 
| 176 | 
            +
                  parent_call.method.match(/_path$/)
         | 
| 177 | 
            +
              end
         | 
| 178 | 
            +
             | 
| 179 | 
            +
              def calls_slice? result
         | 
| 180 | 
            +
                result[:chain].include? :slice or
         | 
| 181 | 
            +
                  (result[:full_call] and result[:full_call][:chain].include? :slice)
         | 
| 182 | 
            +
              end
         | 
| 183 | 
            +
             | 
| 169 184 | 
             
              # Look for actual use of params in mass assignment to avoid
         | 
| 170 185 | 
             
              # warning about uses of Parameters#permit! without any mass assignment
         | 
| 171 186 | 
             
              # or when mass assignment is restricted by model instead.
         | 
| @@ -191,7 +206,7 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck | |
| 191 206 | 
             
                warn :result => result,
         | 
| 192 207 | 
             
                  :warning_type => "Mass Assignment",
         | 
| 193 208 | 
             
                  :warning_code => :mass_assign_permit!,
         | 
| 194 | 
            -
                  :message =>  | 
| 209 | 
            +
                  :message => msg('Specify exact keys allowed for mass assignment instead of using ', msg_code('permit!'), ' which allows any keys'),
         | 
| 195 210 | 
             
                  :confidence => confidence
         | 
| 196 211 | 
             
              end
         | 
| 197 212 |  | 
| @@ -203,7 +218,7 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck | |
| 203 218 | 
             
                    warn :result => result,
         | 
| 204 219 | 
             
                      :warning_type => "Mass Assignment",
         | 
| 205 220 | 
             
                      :warning_code => :mass_assign_permit_all,
         | 
| 206 | 
            -
                      :message =>  | 
| 221 | 
            +
                      :message => msg('Mass assignment is globally enabled. Disable and specify exact keys using ', msg_code('params.permit'), ' instead'),
         | 
| 207 222 | 
             
                      :confidence => :high
         | 
| 208 223 | 
             
                  end
         | 
| 209 224 | 
             
                end
         | 
| @@ -8,7 +8,7 @@ require 'brakeman/checks/base_check' | |
| 8 8 | 
             
            class Brakeman::CheckModelAttrAccessible < Brakeman::BaseCheck
         | 
| 9 9 | 
             
              Brakeman::Checks.add self
         | 
| 10 10 |  | 
| 11 | 
            -
              @description = "Reports models which have dangerous attributes defined  | 
| 11 | 
            +
              @description = "Reports models which have dangerous attributes defined via attr_accessible"
         | 
| 12 12 |  | 
| 13 13 | 
             
              SUSP_ATTRS = [
         | 
| 14 14 | 
             
                [:admin, :high], # Very dangerous unless some Rails authorization used
         | 
| @@ -3,7 +3,7 @@ require 'brakeman/checks/base_check' | |
| 3 3 | 
             
            class Brakeman::CheckPermitAttributes < Brakeman::BaseCheck
         | 
| 4 4 | 
             
              Brakeman::Checks.add self
         | 
| 5 5 |  | 
| 6 | 
            -
              @description = "Warn on potentially dangerous attributes  | 
| 6 | 
            +
              @description = "Warn on potentially dangerous attributes allowed via permit"
         | 
| 7 7 |  | 
| 8 8 | 
             
              SUSPICIOUS_KEYS = {
         | 
| 9 9 | 
             
                admin: :high,
         | 
| @@ -4,8 +4,8 @@ require 'brakeman/checks/base_check' | |
| 4 4 | 
             
            #
         | 
| 5 5 | 
             
            #  skip_before_filter :verify_authenticity_token, :except => [...]
         | 
| 6 6 | 
             
            #
         | 
| 7 | 
            -
            #which is essentially a  | 
| 8 | 
            -
            #ones listed) versus a  | 
| 7 | 
            +
            #which is essentially a skip-by-default approach (no actions are checked EXCEPT the
         | 
| 8 | 
            +
            #ones listed) versus a enforce-by-default approach (ONLY the actions listed will skip
         | 
| 9 9 | 
             
            #the check)
         | 
| 10 10 | 
             
            class Brakeman::CheckSkipBeforeFilter < Brakeman::BaseCheck
         | 
| 11 11 | 
             
              Brakeman::Checks.add self
         | 
| @@ -26,7 +26,7 @@ class Brakeman::CheckSkipBeforeFilter < Brakeman::BaseCheck | |
| 26 26 | 
             
                  warn :class => controller.name, #ugh this should be a controller warning, too
         | 
| 27 27 | 
             
                    :warning_type => "Cross-Site Request Forgery",
         | 
| 28 28 | 
             
                    :warning_code => :csrf_blacklist,
         | 
| 29 | 
            -
                    :message => msg(" | 
| 29 | 
            +
                    :message => msg("List specific actions (", msg_code(":only => [..]"), ") when skipping CSRF check"),
         | 
| 30 30 | 
             
                    :code => filter,
         | 
| 31 31 | 
             
                    :confidence => :medium,
         | 
| 32 32 | 
             
                    :file => controller.file
         | 
| @@ -35,7 +35,7 @@ class Brakeman::CheckSkipBeforeFilter < Brakeman::BaseCheck | |
| 35 35 | 
             
                  warn :controller => controller.name,
         | 
| 36 36 | 
             
                    :warning_code => :auth_blacklist,
         | 
| 37 37 | 
             
                    :warning_type => "Authentication",
         | 
| 38 | 
            -
                    :message => msg(" | 
| 38 | 
            +
                    :message => msg("List specific actions (", msg_code(":only => [..]"), ") when skipping authentication"),
         | 
| 39 39 | 
             
                    :code => filter,
         | 
| 40 40 | 
             
                    :confidence => :medium,
         | 
| 41 41 | 
             
                    :link_path => "authentication_whitelist",
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            require 'brakeman/checks/base_check'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class Brakeman::CheckTemplateInjection < Brakeman::BaseCheck
         | 
| 4 | 
            +
              Brakeman::Checks.add self
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              @description = "Searches for evaluation of user input through template injection"
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              #Process calls
         | 
| 9 | 
            +
              def run_check
         | 
| 10 | 
            +
                Brakeman.debug "Finding ERB.new calls"
         | 
| 11 | 
            +
                erb_calls = tracker.find_call :target => :ERB, :method => :new, :nested => true
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                Brakeman.debug "Processing ERB.new calls"
         | 
| 14 | 
            +
                erb_calls.each do |call|
         | 
| 15 | 
            +
                  process_result call
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              #Warns if eval includes user input
         | 
| 20 | 
            +
              def process_result result
         | 
| 21 | 
            +
                return unless original? result
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                if input = include_user_input?(result[:call].arglist)
         | 
| 24 | 
            +
                  warn :result => result,
         | 
| 25 | 
            +
                    :warning_type => "Template Injection",
         | 
| 26 | 
            +
                    :warning_code => :erb_template_injection,
         | 
| 27 | 
            +
                    :message => msg(msg_input(input), " used directly in ", msg_code("ERB"), " template, which might enable remote code execution"),
         | 
| 28 | 
            +
                    :user_input => input,
         | 
| 29 | 
            +
                    :confidence => :high
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end
         | 
    
        data/lib/brakeman/commandline.rb
    CHANGED
    
    | @@ -102,6 +102,13 @@ module Brakeman | |
| 102 102 | 
             
                      app_path = "."
         | 
| 103 103 | 
             
                    end
         | 
| 104 104 |  | 
| 105 | 
            +
                    if options[:ensure_ignore_notes] and options[:previous_results_json]
         | 
| 106 | 
            +
                      warn '[Notice] --ensure-ignore-notes may not be used at the same ' \
         | 
| 107 | 
            +
                           'time as --compare. Deactivating --ensure-ignore-notes. ' \
         | 
| 108 | 
            +
                           'Please see `brakeman --help` for valid options'
         | 
| 109 | 
            +
                      options[:ensure_ignore_notes] = false
         | 
| 110 | 
            +
                    end
         | 
| 111 | 
            +
             | 
| 105 112 | 
             
                    return options, app_path
         | 
| 106 113 | 
             
                  end
         | 
| 107 114 |  | 
| @@ -115,7 +122,20 @@ module Brakeman | |
| 115 122 |  | 
| 116 123 | 
             
                  # Runs a regular report based on the options provided.
         | 
| 117 124 | 
             
                  def regular_report options
         | 
| 118 | 
            -
                    tracker = run_brakeman options | 
| 125 | 
            +
                    tracker = run_brakeman options
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                    ensure_ignore_notes_failed = false
         | 
| 128 | 
            +
                    if tracker.options[:ensure_ignore_notes]
         | 
| 129 | 
            +
                      fingerprints = Brakeman::ignore_file_entries_with_empty_notes tracker.ignored_filter&.file
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                      unless fingerprints.empty?
         | 
| 132 | 
            +
                        ensure_ignore_notes_failed = true
         | 
| 133 | 
            +
                        warn '[Error] Notes required for all ignored warnings when ' \
         | 
| 134 | 
            +
                          '--ensure-ignore-notes is set. No notes provided for these ' \
         | 
| 135 | 
            +
                          'warnings: '
         | 
| 136 | 
            +
                        fingerprints.each { |f| warn f }
         | 
| 137 | 
            +
                      end
         | 
| 138 | 
            +
                    end
         | 
| 119 139 |  | 
| 120 140 | 
             
                    if tracker.options[:exit_on_warn] and not tracker.filtered_warnings.empty?
         | 
| 121 141 | 
             
                      quit Brakeman::Warnings_Found_Exit_Code
         | 
| @@ -124,6 +144,10 @@ module Brakeman | |
| 124 144 | 
             
                    if tracker.options[:exit_on_error] and tracker.errors.any?
         | 
| 125 145 | 
             
                      quit Brakeman::Errors_Found_Exit_Code
         | 
| 126 146 | 
             
                    end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                    if ensure_ignore_notes_failed
         | 
| 149 | 
            +
                      quit Brakeman::Empty_Ignore_Note_Exit_Code
         | 
| 150 | 
            +
                    end
         | 
| 127 151 | 
             
                  end
         | 
| 128 152 |  | 
| 129 153 | 
             
                  # Actually run Brakeman.
         | 
    
        data/lib/brakeman/options.rb
    CHANGED
    
    | @@ -67,6 +67,10 @@ module Brakeman::Options | |
| 67 67 | 
             
                      options[:ensure_latest] = true
         | 
| 68 68 | 
             
                    end
         | 
| 69 69 |  | 
| 70 | 
            +
                    opts.on "--ensure-ignore-notes", "Fail when an ignored warnings does not include a note" do
         | 
| 71 | 
            +
                      options[:ensure_ignore_notes] = true
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
             | 
| 70 74 | 
             
                    opts.on "-3", "--rails3", "Force Rails 3 mode" do
         | 
| 71 75 | 
             
                      options[:rails3] = true
         | 
| 72 76 | 
             
                    end
         | 
| @@ -82,7 +82,6 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor | |
| 82 82 | 
             
              def replace exp, int = 0
         | 
| 83 83 | 
             
                return exp if int > 3
         | 
| 84 84 |  | 
| 85 | 
            -
             | 
| 86 85 | 
             
                if replacement = env[exp] and not duplicate? replacement
         | 
| 87 86 | 
             
                  replace(replacement.deep_clone(exp.line), int + 1)
         | 
| 88 87 | 
             
                elsif tracker and replacement = tracker.constant_lookup(exp) and not duplicate? replacement
         | 
| @@ -731,14 +730,14 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor | |
| 731 730 | 
             
              def array_include_all_literals? exp
         | 
| 732 731 | 
             
                call? exp and
         | 
| 733 732 | 
             
                exp.method == :include? and
         | 
| 734 | 
            -
                all_literals? exp.target
         | 
| 733 | 
            +
                (all_literals? exp.target or dir_glob? exp.target)
         | 
| 735 734 | 
             
              end
         | 
| 736 735 |  | 
| 737 736 | 
             
              def array_detect_all_literals? exp
         | 
| 738 737 | 
             
                call? exp and
         | 
| 739 738 | 
             
                [:detect, :find].include? exp.method and
         | 
| 740 739 | 
             
                exp.first_arg.nil? and
         | 
| 741 | 
            -
                all_literals? exp.target
         | 
| 740 | 
            +
                (all_literals? exp.target or dir_glob? exp.target)
         | 
| 742 741 | 
             
              end
         | 
| 743 742 |  | 
| 744 743 | 
             
              #Sets @inside_if = true
         | 
| @@ -20,6 +20,7 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor | |
| 20 20 | 
             
                @current_template = opts[:template]
         | 
| 21 21 | 
             
                @current_file = opts[:file]
         | 
| 22 22 | 
             
                @current_call = nil
         | 
| 23 | 
            +
                @full_call = nil
         | 
| 23 24 | 
             
                process exp
         | 
| 24 25 | 
             
              end
         | 
| 25 26 |  | 
| @@ -137,7 +138,8 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor | |
| 137 138 | 
             
                            :call => exp,
         | 
| 138 139 | 
             
                            :nested => false,
         | 
| 139 140 | 
             
                            :location => make_location,
         | 
| 140 | 
            -
                            :parent => @current_call | 
| 141 | 
            +
                            :parent => @current_call,
         | 
| 142 | 
            +
                            :full_call => @full_call }.freeze
         | 
| 141 143 | 
             
              end
         | 
| 142 144 |  | 
| 143 145 | 
             
              #Gets the target of a call as a Symbol
         | 
| @@ -214,34 +216,47 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor | |
| 214 216 | 
             
              #Return info hash for a call Sexp
         | 
| 215 217 | 
             
              def create_call_hash exp
         | 
| 216 218 | 
             
                target = get_target exp.target
         | 
| 217 | 
            -
             | 
| 218 | 
            -
                if call? target or node_type? target, :dxstr # need to index `` even if target of a call
         | 
| 219 | 
            -
                  already_in_target = @in_target
         | 
| 220 | 
            -
                  @in_target = true
         | 
| 221 | 
            -
                  process target
         | 
| 222 | 
            -
                  @in_target = already_in_target
         | 
| 223 | 
            -
             | 
| 224 | 
            -
                  target = get_target(target, :include_calls)
         | 
| 225 | 
            -
                end
         | 
| 219 | 
            +
                target_symbol = get_target(target, :include_calls)
         | 
| 226 220 |  | 
| 227 221 | 
             
                method = exp.method
         | 
| 228 222 |  | 
| 229 223 | 
             
                call_hash = {
         | 
| 230 | 
            -
                  :target =>  | 
| 224 | 
            +
                  :target => target_symbol,
         | 
| 231 225 | 
             
                  :method => method,
         | 
| 232 226 | 
             
                  :call => exp,
         | 
| 233 227 | 
             
                  :nested => @in_target,
         | 
| 234 228 | 
             
                  :chain => get_chain(exp),
         | 
| 235 229 | 
             
                  :location => make_location,
         | 
| 236 | 
            -
                  :parent => @current_call
         | 
| 230 | 
            +
                  :parent => @current_call,
         | 
| 231 | 
            +
                  :full_call => @full_call
         | 
| 237 232 | 
             
                }
         | 
| 238 233 |  | 
| 234 | 
            +
                unless @in_target
         | 
| 235 | 
            +
                  @full_call = call_hash
         | 
| 236 | 
            +
                end
         | 
| 237 | 
            +
             | 
| 238 | 
            +
                # Process up the call chain
         | 
| 239 | 
            +
                if call? target or node_type? target, :dxstr # need to index `` even if target of a call
         | 
| 240 | 
            +
                  already_in_target = @in_target
         | 
| 241 | 
            +
                  @in_target = true
         | 
| 242 | 
            +
                  process target
         | 
| 243 | 
            +
                  @in_target = already_in_target
         | 
| 244 | 
            +
                end
         | 
| 245 | 
            +
             | 
| 246 | 
            +
                # Process call arguments
         | 
| 247 | 
            +
                # but add the current call as the 'parent'
         | 
| 248 | 
            +
                # to any calls in the arguments
         | 
| 239 249 | 
             
                old_parent = @current_call
         | 
| 240 250 | 
             
                @current_call = call_hash
         | 
| 241 251 |  | 
| 252 | 
            +
                # Do not set @full_call when processing arguments
         | 
| 253 | 
            +
                old_full_call = @full_call
         | 
| 254 | 
            +
                @full_call = nil
         | 
| 255 | 
            +
             | 
| 242 256 | 
             
                process_call_args exp
         | 
| 243 257 |  | 
| 244 258 | 
             
                @current_call = old_parent
         | 
| 259 | 
            +
                @full_call = old_full_call
         | 
| 245 260 |  | 
| 246 261 | 
             
                call_hash
         | 
| 247 262 | 
             
              end
         | 
    
        data/lib/brakeman/scanner.rb
    CHANGED
    
    | @@ -94,11 +94,14 @@ class Brakeman::Scanner | |
| 94 94 | 
             
              #
         | 
| 95 95 | 
             
              #Stores parsed information in tracker.config
         | 
| 96 96 | 
             
              def process_config
         | 
| 97 | 
            +
                # Sometimes folks like to put constants in environment.rb
         | 
| 98 | 
            +
                # so let's always process it even for newer Rails versions
         | 
| 99 | 
            +
                process_config_file "environment.rb"
         | 
| 100 | 
            +
             | 
| 97 101 | 
             
                if options[:rails3] or options[:rails4] or options[:rails5] or options[:rails6]
         | 
| 98 102 | 
             
                  process_config_file "application.rb"
         | 
| 99 103 | 
             
                  process_config_file "environments/production.rb"
         | 
| 100 104 | 
             
                else
         | 
| 101 | 
            -
                  process_config_file "environment.rb"
         | 
| 102 105 | 
             
                  process_config_file "gems.rb"
         | 
| 103 106 | 
             
                end
         | 
| 104 107 |  | 
    
        data/lib/brakeman/tracker.rb
    CHANGED
    
    | @@ -198,8 +198,10 @@ class Brakeman::Tracker | |
| 198 198 | 
             
                @constants.add name, value, context unless @options[:disable_constant_tracking]
         | 
| 199 199 | 
             
              end
         | 
| 200 200 |  | 
| 201 | 
            +
              # This method does not return all constants at this time,
         | 
| 202 | 
            +
              # just ones with "simple" values.
         | 
| 201 203 | 
             
              def constant_lookup name
         | 
| 202 | 
            -
                @constants. | 
| 204 | 
            +
                @constants.get_simple_value name unless @options[:disable_constant_tracking]
         | 
| 203 205 | 
             
              end
         | 
| 204 206 |  | 
| 205 207 | 
             
              def find_class name
         | 
| @@ -1,7 +1,10 @@ | |
| 1 1 | 
             
            require 'brakeman/processors/output_processor'
         | 
| 2 | 
            +
            require 'brakeman/util'
         | 
| 2 3 |  | 
| 3 4 | 
             
            module Brakeman
         | 
| 4 5 | 
             
              class Constant
         | 
| 6 | 
            +
                include Brakeman::Util
         | 
| 7 | 
            +
             | 
| 5 8 | 
             
                attr_reader :name, :name_array, :file, :value, :context
         | 
| 6 9 |  | 
| 7 10 | 
             
                def initialize name, value, context = {}
         | 
| @@ -107,13 +110,11 @@ module Brakeman | |
| 107 110 | 
             
                  @constants[base_name] << Constant.new(name, value, context)
         | 
| 108 111 | 
             
                end
         | 
| 109 112 |  | 
| 110 | 
            -
                 | 
| 111 | 
            -
                 | 
| 112 | 
            -
             | 
| 113 | 
            -
                 | 
| 114 | 
            -
             | 
| 115 | 
            -
                def get_literal name
         | 
| 116 | 
            -
                  if x = self[name] and literal? x
         | 
| 113 | 
            +
                # Returns constant values that are not too complicated.
         | 
| 114 | 
            +
                # Right now that means literal values (string, array, etc.)
         | 
| 115 | 
            +
                # or calls on Dir.glob(..).whatever.
         | 
| 116 | 
            +
                def get_simple_value name
         | 
| 117 | 
            +
                  if x = self[name] and (literal? x or dir_glob? x)
         | 
| 117 118 | 
             
                    x
         | 
| 118 119 | 
             
                  else
         | 
| 119 120 | 
             
                    nil
         | 
    
        data/lib/brakeman/util.rb
    CHANGED
    
    | @@ -293,6 +293,22 @@ module Brakeman::Util | |
| 293 293 | 
             
                exp.is_a? Sexp and types.include? exp.node_type
         | 
| 294 294 | 
             
              end
         | 
| 295 295 |  | 
| 296 | 
            +
              LITERALS = [:lit, :false, :str, :true, :array, :hash]
         | 
| 297 | 
            +
             | 
| 298 | 
            +
              def literal? exp
         | 
| 299 | 
            +
                exp.is_a? Sexp and LITERALS.include? exp.node_type
         | 
| 300 | 
            +
              end
         | 
| 301 | 
            +
             | 
| 302 | 
            +
              DIR_CONST = s(:const, :Dir)
         | 
| 303 | 
            +
             | 
| 304 | 
            +
              # Dir.glob(...).whatever
         | 
| 305 | 
            +
              def dir_glob? exp
         | 
| 306 | 
            +
                exp = exp.block_call if node_type? exp, :iter
         | 
| 307 | 
            +
                return unless call? exp
         | 
| 308 | 
            +
             | 
| 309 | 
            +
                (exp.target == DIR_CONST and exp.method == :glob) or dir_glob? exp.target
         | 
| 310 | 
            +
              end
         | 
| 311 | 
            +
             | 
| 296 312 | 
             
              #Returns true if the given _exp_ contains a :class node.
         | 
| 297 313 | 
             
              #
         | 
| 298 314 | 
             
              #Useful for checking if a module is just a module or if it is a namespace.
         | 
    
        data/lib/brakeman/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: brakeman-lib
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 4. | 
| 4 | 
            +
              version: 4.9.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Justin Collins
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2020- | 
| 11 | 
            +
            date: 2020-08-04 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: minitest
         | 
| @@ -52,6 +52,20 @@ dependencies: | |
| 52 52 | 
             
                - - ">="
         | 
| 53 53 | 
             
                  - !ruby/object:Gem::Version
         | 
| 54 54 | 
             
                    version: '0'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: simplecov-html
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - '='
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: 0.10.2
         | 
| 62 | 
            +
              type: :development
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - '='
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: 0.10.2
         | 
| 55 69 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 56 70 | 
             
              name: ruby_parser
         | 
| 57 71 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -187,7 +201,7 @@ dependencies: | |
| 187 201 | 
             
                    version: 1.3.6
         | 
| 188 202 | 
             
                - - "<="
         | 
| 189 203 | 
             
                  - !ruby/object:Gem::Version
         | 
| 190 | 
            -
                    version: 4. | 
| 204 | 
            +
                    version: '4.1'
         | 
| 191 205 | 
             
              type: :runtime
         | 
| 192 206 | 
             
              prerelease: false
         | 
| 193 207 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| @@ -197,7 +211,7 @@ dependencies: | |
| 197 211 | 
             
                    version: 1.3.6
         | 
| 198 212 | 
             
                - - "<="
         | 
| 199 213 | 
             
                  - !ruby/object:Gem::Version
         | 
| 200 | 
            -
                    version: 4. | 
| 214 | 
            +
                    version: '4.1'
         | 
| 201 215 | 
             
            description: Brakeman detects security vulnerabilities in Ruby on Rails applications
         | 
| 202 216 | 
             
              via static analysis. This package declares gem dependencies instead of bundling
         | 
| 203 217 | 
             
              them.
         | 
| @@ -222,6 +236,7 @@ files: | |
| 222 236 | 
             
            - lib/brakeman/checks/check_cookie_serialization.rb
         | 
| 223 237 | 
             
            - lib/brakeman/checks/check_create_with.rb
         | 
| 224 238 | 
             
            - lib/brakeman/checks/check_cross_site_scripting.rb
         | 
| 239 | 
            +
            - lib/brakeman/checks/check_csrf_token_forgery_cve.rb
         | 
| 225 240 | 
             
            - lib/brakeman/checks/check_default_routes.rb
         | 
| 226 241 | 
             
            - lib/brakeman/checks/check_deserialize.rb
         | 
| 227 242 | 
             
            - lib/brakeman/checks/check_detailed_exceptions.rb
         | 
| @@ -283,6 +298,7 @@ files: | |
| 283 298 | 
             
            - lib/brakeman/checks/check_strip_tags.rb
         | 
| 284 299 | 
             
            - lib/brakeman/checks/check_symbol_dos.rb
         | 
| 285 300 | 
             
            - lib/brakeman/checks/check_symbol_dos_cve.rb
         | 
| 301 | 
            +
            - lib/brakeman/checks/check_template_injection.rb
         | 
| 286 302 | 
             
            - lib/brakeman/checks/check_translate_bug.rb
         | 
| 287 303 | 
             
            - lib/brakeman/checks/check_unsafe_reflection.rb
         | 
| 288 304 | 
             
            - lib/brakeman/checks/check_unscoped_find.rb
         |