brakeman 3.1.5 → 3.2.0.pre1
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 +11 -0
- data/lib/brakeman.rb +4 -4
- data/lib/brakeman/call_index.rb +22 -31
- data/lib/brakeman/checks.rb +59 -73
- data/lib/brakeman/checks/check_basic_auth_timing_attack.rb +0 -21
- data/lib/brakeman/checks/check_cross_site_scripting.rb +2 -2
- data/lib/brakeman/checks/check_render.rb +9 -1
- data/lib/brakeman/checks/check_sql.rb +3 -3
- data/lib/brakeman/processors/alias_processor.rb +1 -1
- data/lib/brakeman/processors/base_processor.rb +8 -0
- data/lib/brakeman/processors/erb_template_processor.rb +1 -1
- data/lib/brakeman/processors/erubis_template_processor.rb +1 -1
- data/lib/brakeman/processors/haml_template_processor.rb +2 -1
- data/lib/brakeman/processors/lib/basic_processor.rb +16 -0
- data/lib/brakeman/processors/lib/find_all_calls.rb +4 -2
- data/lib/brakeman/processors/lib/find_call.rb +1 -1
- data/lib/brakeman/processors/lib/render_path.rb +2 -1
- data/lib/brakeman/report/ignore/config.rb +3 -3
- data/lib/brakeman/report/report_csv.rb +1 -2
- data/lib/brakeman/report/report_json.rb +1 -4
- data/lib/brakeman/tracker.rb +21 -0
- data/lib/brakeman/util.rb +4 -3
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +2 -2
- data/lib/ruby_parser/bm_sexp.rb +23 -23
- metadata +8 -44
- data/lib/brakeman/report/initializers/faster_csv.rb +0 -7
- data/lib/brakeman/report/initializers/multi_json.rb +0 -29
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 1e770766f6b12a78d68bb5578ca2f03edc16dbb0
         | 
| 4 | 
            +
              data.tar.gz: d16b6325409502c5828ce379e364e43fbc10ec9e
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 79dbc7972a53fd175306dd50e21943b1825870fa2273b489bb2fef00c7870c5f0c5fc48e90b919d78b57dd2ff46b1a1be7fdee40f55f545d8a0cbecfe0878826
         | 
| 7 | 
            +
              data.tar.gz: 647e2c2f42057c5f2d64a4e5166f3541ed1764062d4b6bed7668e6ba31429214486dbb8a495435dc144a98f52ec7357330640cb2730c71157a236b23bd7fdbb4
         | 
    
        data/CHANGES
    CHANGED
    
    | @@ -1,3 +1,14 @@ | |
| 1 | 
            +
            # 3.2.0.pre1
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            * Support calls using `&.` operator
         | 
| 4 | 
            +
            * Update ruby_parser dependency to 3.8.1
         | 
| 5 | 
            +
            * Remove `fastercsv` dependency
         | 
| 6 | 
            +
            * Fix finding calls with `targets: nil`
         | 
| 7 | 
            +
            * Remove `multi-json` dependecy
         | 
| 8 | 
            +
            * Handle CoffeeScript in HAML
         | 
| 9 | 
            +
            * Avoid render warnings about params[:action]/params[:controller]
         | 
| 10 | 
            +
            * Index calls in class bodies but outside methods
         | 
| 11 | 
            +
             | 
| 1 12 | 
             
            # 3.1.5
         | 
| 2 13 |  | 
| 3 14 | 
             
            * Fix CodeClimate construction of --only-files (Will Fleming)
         | 
    
        data/lib/brakeman.rb
    CHANGED
    
    | @@ -407,20 +407,20 @@ module Brakeman | |
| 407 407 |  | 
| 408 408 | 
             
              # Compare JSON ouptut from a previous scan and return the diff of the two scans
         | 
| 409 409 | 
             
              def self.compare options
         | 
| 410 | 
            -
                require ' | 
| 410 | 
            +
                require 'json'
         | 
| 411 411 | 
             
                require 'brakeman/differ'
         | 
| 412 412 | 
             
                raise ArgumentError.new("Comparison file doesn't exist") unless File.exist? options[:previous_results_json]
         | 
| 413 413 |  | 
| 414 414 | 
             
                begin
         | 
| 415 | 
            -
                  previous_results =  | 
| 416 | 
            -
                rescue  | 
| 415 | 
            +
                  previous_results = JSON.parse(File.read(options[:previous_results_json]), :symbolize_names => true)[:warnings]
         | 
| 416 | 
            +
                rescue JSON::ParserError
         | 
| 417 417 | 
             
                  self.notify "Error parsing comparison file: #{options[:previous_results_json]}"
         | 
| 418 418 | 
             
                  exit!
         | 
| 419 419 | 
             
                end
         | 
| 420 420 |  | 
| 421 421 | 
             
                tracker = run(options)
         | 
| 422 422 |  | 
| 423 | 
            -
                new_results =  | 
| 423 | 
            +
                new_results = JSON.parse(tracker.report.to_json, :symbolize_names => true)[:warnings]
         | 
| 424 424 |  | 
| 425 425 | 
             
                Brakeman::Differ.new(new_results, previous_results).diff
         | 
| 426 426 | 
             
              end
         | 
    
        data/lib/brakeman/call_index.rb
    CHANGED
    
    | @@ -5,8 +5,8 @@ class Brakeman::CallIndex | |
| 5 5 |  | 
| 6 6 | 
             
              #Initialize index with calls from FindAllCalls
         | 
| 7 7 | 
             
              def initialize calls
         | 
| 8 | 
            -
                @calls_by_method = Hash.new
         | 
| 9 | 
            -
                @calls_by_target = Hash.new
         | 
| 8 | 
            +
                @calls_by_method = Hash.new { |h, k| h[k] = [] }
         | 
| 9 | 
            +
                @calls_by_target = Hash.new { |h, k| h[k] = [] }
         | 
| 10 10 |  | 
| 11 11 | 
             
                index_calls calls
         | 
| 12 12 | 
             
              end
         | 
| @@ -45,7 +45,7 @@ class Brakeman::CallIndex | |
| 45 45 |  | 
| 46 46 | 
             
                #Find calls with no explicit target
         | 
| 47 47 | 
             
                #with either :target => nil or :target => false
         | 
| 48 | 
            -
                elsif options.key? :target and not target and method
         | 
| 48 | 
            +
                elsif (options.key? :target or options.key? :targets) and not target and method
         | 
| 49 49 | 
             
                  calls = calls_by_method method
         | 
| 50 50 | 
             
                  calls = filter_by_target calls, nil
         | 
| 51 51 |  | 
| @@ -66,44 +66,35 @@ class Brakeman::CallIndex | |
| 66 66 | 
             
              end
         | 
| 67 67 |  | 
| 68 68 | 
             
              def remove_template_indexes template_name = nil
         | 
| 69 | 
            -
                @calls_by_method.each do | | 
| 70 | 
            -
                   | 
| 71 | 
            -
                     | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 75 | 
            -
                @calls_by_target.each do |name, calls|
         | 
| 76 | 
            -
                  calls.delete_if do |call|
         | 
| 77 | 
            -
                    from_template call, template_name
         | 
| 69 | 
            +
                [@calls_by_method, @calls_by_target].each do |calls_by|
         | 
| 70 | 
            +
                  calls_by.each do |name, calls|
         | 
| 71 | 
            +
                    calls.delete_if do |call|
         | 
| 72 | 
            +
                      from_template call, template_name
         | 
| 73 | 
            +
                    end
         | 
| 78 74 | 
             
                  end
         | 
| 79 75 | 
             
                end
         | 
| 80 76 | 
             
              end
         | 
| 81 77 |  | 
| 82 78 | 
             
              def remove_indexes_by_class classes
         | 
| 83 | 
            -
                @calls_by_method.each do | | 
| 84 | 
            -
                   | 
| 85 | 
            -
                     | 
| 86 | 
            -
             | 
| 87 | 
            -
             | 
| 88 | 
            -
             | 
| 89 | 
            -
                @calls_by_target.each do |name, calls|
         | 
| 90 | 
            -
                  calls.delete_if do |call|
         | 
| 91 | 
            -
                    call[:location][:type] == :class and classes.include? call[:location][:class]
         | 
| 79 | 
            +
                [@calls_by_method, @calls_by_target].each do |calls_by|
         | 
| 80 | 
            +
                  calls_by.each do |name, calls|
         | 
| 81 | 
            +
                    calls.delete_if do |call|
         | 
| 82 | 
            +
                      call[:location][:type] == :class and classes.include? call[:location][:class]
         | 
| 83 | 
            +
                    end
         | 
| 92 84 | 
             
                  end
         | 
| 93 85 | 
             
                end
         | 
| 94 86 | 
             
              end
         | 
| 95 87 |  | 
| 96 88 | 
             
              def index_calls calls
         | 
| 97 89 | 
             
                calls.each do |call|
         | 
| 98 | 
            -
                  @calls_by_method[call[:method]] ||= []
         | 
| 99 90 | 
             
                  @calls_by_method[call[:method]] << call
         | 
| 100 91 |  | 
| 101 | 
            -
                   | 
| 102 | 
            -
             | 
| 103 | 
            -
             | 
| 104 | 
            -
             | 
| 105 | 
            -
             | 
| 106 | 
            -
                    @calls_by_target[ | 
| 92 | 
            +
                  target = call[:target]
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  if not target.is_a? Sexp
         | 
| 95 | 
            +
                    @calls_by_target[target] << call
         | 
| 96 | 
            +
                  elsif target.node_type == :params or target.node_type == :session
         | 
| 97 | 
            +
                    @calls_by_target[target.node_type] << call
         | 
| 107 98 | 
             
                  end
         | 
| 108 99 | 
             
                end
         | 
| 109 100 | 
             
              end
         | 
| @@ -115,7 +106,7 @@ class Brakeman::CallIndex | |
| 115 106 | 
             
                method = options[:method] || options[:methods]
         | 
| 116 107 |  | 
| 117 108 | 
             
                calls = calls_by_method method
         | 
| 118 | 
            -
             | 
| 109 | 
            +
             | 
| 119 110 | 
             
                return [] if calls.nil?
         | 
| 120 111 |  | 
| 121 112 | 
             
                calls = filter_by_chain calls, target
         | 
| @@ -145,7 +136,7 @@ class Brakeman::CallIndex | |
| 145 136 | 
             
                elsif method.is_a? Regexp
         | 
| 146 137 | 
             
                  calls_by_methods_regex method
         | 
| 147 138 | 
             
                else
         | 
| 148 | 
            -
                  @calls_by_method[method.to_sym] | 
| 139 | 
            +
                  @calls_by_method[method.to_sym]
         | 
| 149 140 | 
             
                end
         | 
| 150 141 | 
             
              end
         | 
| 151 142 |  | 
| @@ -169,7 +160,7 @@ class Brakeman::CallIndex | |
| 169 160 | 
             
              end
         | 
| 170 161 |  | 
| 171 162 | 
             
              def calls_with_no_target
         | 
| 172 | 
            -
                @calls_by_target[nil] | 
| 163 | 
            +
                @calls_by_target[nil]
         | 
| 173 164 | 
             
              end
         | 
| 174 165 |  | 
| 175 166 | 
             
              def filter calls, key, value
         | 
    
        data/lib/brakeman/checks.rb
    CHANGED
    
    | @@ -93,91 +93,49 @@ class Brakeman::Checks | |
| 93 93 | 
             
              #Run all the checks on the given Tracker.
         | 
| 94 94 | 
             
              #Returns a new instance of Checks with the results.
         | 
| 95 95 | 
             
              def self.run_checks(app_tree, tracker)
         | 
| 96 | 
            -
                 | 
| 97 | 
            -
                  self.run_checks_parallel(app_tree, tracker)
         | 
| 98 | 
            -
                else
         | 
| 99 | 
            -
                  self.run_checks_sequential(app_tree, tracker)
         | 
| 100 | 
            -
                end
         | 
| 101 | 
            -
              end
         | 
| 102 | 
            -
             | 
| 103 | 
            -
              #Run checks sequentially
         | 
| 104 | 
            -
              def self.run_checks_sequential(app_tree, tracker)
         | 
| 96 | 
            +
                checks = self.checks_to_run(tracker)
         | 
| 105 97 | 
             
                check_runner = self.new :min_confidence => tracker.options[:min_confidence]
         | 
| 106 | 
            -
             | 
| 107 | 
            -
                self.checks_to_run(tracker).each do |c|
         | 
| 108 | 
            -
                  check_name = get_check_name c
         | 
| 109 | 
            -
             | 
| 110 | 
            -
                  #Run or don't run check based on options
         | 
| 111 | 
            -
                  unless tracker.options[:skip_checks].include? check_name or
         | 
| 112 | 
            -
                    (tracker.options[:run_checks] and not tracker.options[:run_checks].include? check_name)
         | 
| 113 | 
            -
             | 
| 114 | 
            -
                    Brakeman.notify " - #{check_name}"
         | 
| 115 | 
            -
             | 
| 116 | 
            -
                    check = c.new(app_tree, tracker)
         | 
| 117 | 
            -
             | 
| 118 | 
            -
                    begin
         | 
| 119 | 
            -
                      check.run_check
         | 
| 120 | 
            -
                    rescue => e
         | 
| 121 | 
            -
                      tracker.error e
         | 
| 122 | 
            -
                    end
         | 
| 123 | 
            -
             | 
| 124 | 
            -
                    check.warnings.each do |w|
         | 
| 125 | 
            -
                      check_runner.add_warning w
         | 
| 126 | 
            -
                    end
         | 
| 127 | 
            -
             | 
| 128 | 
            -
                    #Maintain list of which checks were run
         | 
| 129 | 
            -
                    #mainly for reporting purposes
         | 
| 130 | 
            -
                    check_runner.checks_run << check_name[5..-1]
         | 
| 131 | 
            -
                  end
         | 
| 132 | 
            -
                end
         | 
| 133 | 
            -
             | 
| 134 | 
            -
                check_runner
         | 
| 98 | 
            +
                self.actually_run_checks(checks, check_runner, app_tree, tracker)
         | 
| 135 99 | 
             
              end
         | 
| 136 100 |  | 
| 137 | 
            -
               | 
| 138 | 
            -
             | 
| 139 | 
            -
                 | 
| 101 | 
            +
              def self.actually_run_checks(checks, check_runner, app_tree, tracker)
         | 
| 102 | 
            +
                threads = [] # Results for parallel
         | 
| 103 | 
            +
                results = [] # Results for sequential
         | 
| 104 | 
            +
                parallel = tracker.options[:parallel_checks]
         | 
| 140 105 | 
             
                error_mutex = Mutex.new
         | 
| 141 106 |  | 
| 142 | 
            -
                 | 
| 143 | 
            -
             | 
| 144 | 
            -
                self.checks_to_run(tracker).each do |c|
         | 
| 107 | 
            +
                checks.each do |c|
         | 
| 145 108 | 
             
                  check_name = get_check_name c
         | 
| 109 | 
            +
                  Brakeman.notify " - #{check_name}"
         | 
| 146 110 |  | 
| 147 | 
            -
                   | 
| 148 | 
            -
                  unless tracker.options[:skip_checks].include? check_name or
         | 
| 149 | 
            -
                    (tracker.options[:run_checks] and not tracker.options[:run_checks].include? check_name)
         | 
| 150 | 
            -
             | 
| 151 | 
            -
                    Brakeman.notify " - #{check_name}"
         | 
| 152 | 
            -
             | 
| 111 | 
            +
                  if parallel
         | 
| 153 112 | 
             
                    threads << Thread.new do
         | 
| 154 | 
            -
                       | 
| 155 | 
            -
             | 
| 156 | 
            -
                      begin
         | 
| 157 | 
            -
                        check.run_check
         | 
| 158 | 
            -
                      rescue => e
         | 
| 159 | 
            -
                        error_mutex.synchronize do
         | 
| 160 | 
            -
                          tracker.error e
         | 
| 161 | 
            -
                        end
         | 
| 162 | 
            -
                      end
         | 
| 163 | 
            -
             | 
| 164 | 
            -
                      check.warnings
         | 
| 113 | 
            +
                      self.run_a_check(c, error_mutex, app_tree, tracker)
         | 
| 165 114 | 
             
                    end
         | 
| 166 | 
            -
             | 
| 167 | 
            -
                     | 
| 168 | 
            -
                    #mainly for reporting purposes
         | 
| 169 | 
            -
                    check_runner.checks_run << check_name[5..-1]
         | 
| 115 | 
            +
                  else
         | 
| 116 | 
            +
                    results << self.run_a_check(c, error_mutex, app_tree, tracker)
         | 
| 170 117 | 
             
                  end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                  #Maintain list of which checks were run
         | 
| 120 | 
            +
                  #mainly for reporting purposes
         | 
| 121 | 
            +
                  check_runner.checks_run << check_name[5..-1]
         | 
| 171 122 | 
             
                end
         | 
| 172 123 |  | 
| 173 124 | 
             
                threads.each { |t| t.join }
         | 
| 174 125 |  | 
| 175 126 | 
             
                Brakeman.notify "Checks finished, collecting results..."
         | 
| 176 127 |  | 
| 177 | 
            -
                 | 
| 178 | 
            -
             | 
| 179 | 
            -
             | 
| 180 | 
            -
             | 
| 128 | 
            +
                if parallel
         | 
| 129 | 
            +
                  threads.each do |thread|
         | 
| 130 | 
            +
                    thread.value.each do |warning|
         | 
| 131 | 
            +
                      check_runner.add_warning warning
         | 
| 132 | 
            +
                    end
         | 
| 133 | 
            +
                  end
         | 
| 134 | 
            +
                else
         | 
| 135 | 
            +
                  results.each do |warnings|
         | 
| 136 | 
            +
                    warnings.each do |warning|
         | 
| 137 | 
            +
                      check_runner.add_warning warning
         | 
| 138 | 
            +
                    end
         | 
| 181 139 | 
             
                  end
         | 
| 182 140 | 
             
                end
         | 
| 183 141 |  | 
| @@ -191,11 +149,39 @@ class Brakeman::Checks | |
| 191 149 | 
             
              end
         | 
| 192 150 |  | 
| 193 151 | 
             
              def self.checks_to_run tracker
         | 
| 194 | 
            -
                if tracker.options[:run_all_checks] or tracker.options[:run_checks]
         | 
| 195 | 
            -
             | 
| 196 | 
            -
             | 
| 197 | 
            -
             | 
| 152 | 
            +
                to_run = if tracker.options[:run_all_checks] or tracker.options[:run_checks]
         | 
| 153 | 
            +
                           @checks + @optional_checks
         | 
| 154 | 
            +
                         else
         | 
| 155 | 
            +
                           @checks
         | 
| 156 | 
            +
                         end
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                self.filter_checks to_run, tracker
         | 
| 159 | 
            +
              end
         | 
| 160 | 
            +
             | 
| 161 | 
            +
              def self.filter_checks checks, tracker
         | 
| 162 | 
            +
                skipped = tracker.options[:skip_checks]
         | 
| 163 | 
            +
                explicit = tracker.options[:run_checks]
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                checks.reject do |c|
         | 
| 166 | 
            +
                  check_name = self.get_check_name(c)
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                  skipped.include? check_name or
         | 
| 169 | 
            +
                    (explicit and not explicit.include? check_name)
         | 
| 170 | 
            +
                end
         | 
| 171 | 
            +
              end
         | 
| 172 | 
            +
             | 
| 173 | 
            +
              def self.run_a_check klass, mutex, app_tree, tracker
         | 
| 174 | 
            +
                check = klass.new(app_tree, tracker)
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                begin
         | 
| 177 | 
            +
                  check.run_check
         | 
| 178 | 
            +
                rescue => e
         | 
| 179 | 
            +
                  mutex.synchronize do
         | 
| 180 | 
            +
                    tracker.error e
         | 
| 181 | 
            +
                  end
         | 
| 198 182 | 
             
                end
         | 
| 183 | 
            +
             | 
| 184 | 
            +
                check.warnings
         | 
| 199 185 | 
             
              end
         | 
| 200 186 | 
             
            end
         | 
| 201 187 |  | 
| @@ -17,31 +17,10 @@ class Brakeman::CheckBasicAuthTimingAttack < Brakeman::BaseCheck | |
| 17 17 | 
             
                             return
         | 
| 18 18 | 
             
                           end
         | 
| 19 19 |  | 
| 20 | 
            -
                check_basic_auth_filter
         | 
| 21 20 | 
             
                check_basic_auth_call
         | 
| 22 21 | 
             
              end
         | 
| 23 22 |  | 
| 24 | 
            -
              def check_basic_auth_filter
         | 
| 25 | 
            -
                controllers = tracker.controllers.select do |name, c|
         | 
| 26 | 
            -
                  c.options[:http_basic_authenticate_with]
         | 
| 27 | 
            -
                end
         | 
| 28 | 
            -
             | 
| 29 | 
            -
                Hash[controllers].each do |name, controller|
         | 
| 30 | 
            -
                  controller.options[:http_basic_authenticate_with].each do |call|
         | 
| 31 | 
            -
                    warn :controller => name,
         | 
| 32 | 
            -
                      :warning_type => "Timing Attack",
         | 
| 33 | 
            -
                      :warning_code => :CVE_2015_7576,
         | 
| 34 | 
            -
                      :message => "Basic authentication in Rails #{rails_version} is vulnerable to timing attacks. Upgrade to #@upgrade",
         | 
| 35 | 
            -
                      :code => call,
         | 
| 36 | 
            -
                      :confidence => CONFIDENCE[:high],
         | 
| 37 | 
            -
                      :file => controller.file,
         | 
| 38 | 
            -
                      :link => "https://groups.google.com/d/msg/rubyonrails-security/ANv0HDHEC3k/mt7wNGxbFQAJ"
         | 
| 39 | 
            -
                  end
         | 
| 40 | 
            -
                end
         | 
| 41 | 
            -
              end
         | 
| 42 | 
            -
             | 
| 43 23 | 
             
              def check_basic_auth_call
         | 
| 44 | 
            -
                # This is relatively unusual, but found in the wild
         | 
| 45 24 | 
             
                tracker.find_call(target: nil, method: :http_basic_authenticate_with).each do |result|
         | 
| 46 25 | 
             
                  warn :result => result,
         | 
| 47 26 | 
             
                    :warning_type => "Timing Attack",
         | 
| @@ -99,7 +99,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck | |
| 99 99 | 
             
                    link_path = "cross_site_scripting"
         | 
| 100 100 | 
             
                    warning_code = :cross_site_scripting
         | 
| 101 101 |  | 
| 102 | 
            -
                    if node_type?(out, :call, :attrasgn) && out.method == :to_json
         | 
| 102 | 
            +
                    if node_type?(out, :call, :safe_call, :attrasgn, :safe_attrasgn) && out.method == :to_json
         | 
| 103 103 | 
             
                      message += " in JSON hash"
         | 
| 104 104 | 
             
                      link_path += "_to_json"
         | 
| 105 105 | 
             
                      warning_code = :xss_to_json
         | 
| @@ -334,7 +334,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck | |
| 334 334 | 
             
              end
         | 
| 335 335 |  | 
| 336 336 | 
             
              def html_safe_call? exp
         | 
| 337 | 
            -
                exp.value | 
| 337 | 
            +
                call? exp.value and exp.value.method == :html_safe
         | 
| 338 338 | 
             
              end
         | 
| 339 339 |  | 
| 340 340 | 
             
              def ignore_call? target, method
         | 
| @@ -35,7 +35,6 @@ class Brakeman::CheckRender < Brakeman::BaseCheck | |
| 35 35 | 
             
                if sexp? view and not duplicate? result
         | 
| 36 36 | 
             
                  add_result result
         | 
| 37 37 |  | 
| 38 | 
            -
             | 
| 39 38 | 
             
                  if input = has_immediate_user_input?(view)
         | 
| 40 39 | 
             
                    if string_interp? view
         | 
| 41 40 | 
             
                      confidence = CONFIDENCE[:med]
         | 
| @@ -49,6 +48,7 @@ class Brakeman::CheckRender < Brakeman::BaseCheck | |
| 49 48 | 
             
                  end
         | 
| 50 49 |  | 
| 51 50 | 
             
                  return if input.type == :model #skip models
         | 
| 51 | 
            +
                  return if safe_param? input.match
         | 
| 52 52 |  | 
| 53 53 | 
             
                  message = "Render path contains #{friendly_type_of input}"
         | 
| 54 54 |  | 
| @@ -71,6 +71,7 @@ class Brakeman::CheckRender < Brakeman::BaseCheck | |
| 71 71 | 
             
                if sexp? view and not duplicate? result
         | 
| 72 72 | 
             
                  if params? view
         | 
| 73 73 | 
             
                    add_result result
         | 
| 74 | 
            +
                    return if safe_param? view
         | 
| 74 75 |  | 
| 75 76 | 
             
                    warn :result => result,
         | 
| 76 77 | 
             
                      :warning_type => "Remote Code Execution",
         | 
| @@ -81,4 +82,11 @@ class Brakeman::CheckRender < Brakeman::BaseCheck | |
| 81 82 | 
             
                  end
         | 
| 82 83 | 
             
                end
         | 
| 83 84 | 
             
              end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
              def safe_param? exp
         | 
| 87 | 
            +
                if params? exp and call? exp and exp.method == :[]
         | 
| 88 | 
            +
                  arg = exp.first_arg
         | 
| 89 | 
            +
                  symbol? arg and [:controller, :action].include? arg.value
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
              end
         | 
| 84 92 | 
             
            end 
         | 
| @@ -64,9 +64,9 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck | |
| 64 64 | 
             
                    second_arg = args[2]
         | 
| 65 65 | 
             
                    next unless sexp? second_arg
         | 
| 66 66 |  | 
| 67 | 
            -
                    if second_arg.node_type == :iter and node_type? second_arg.block, :block, :call
         | 
| 67 | 
            +
                    if second_arg.node_type == :iter and node_type? second_arg.block, :block, :call, :safe_call
         | 
| 68 68 | 
             
                      process_scope_with_block(name, args)
         | 
| 69 | 
            -
                    elsif second_arg | 
| 69 | 
            +
                    elsif call? second_arg
         | 
| 70 70 | 
             
                      call = second_arg
         | 
| 71 71 | 
             
                      scope_calls << scope_call_hash(call, name, call.method)
         | 
| 72 72 | 
             
                    else
         | 
| @@ -107,7 +107,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck | |
| 107 107 | 
             
                  find_calls = Brakeman::FindAllCalls.new(tracker)
         | 
| 108 108 | 
             
                  find_calls.process_source(block, :class => model_name, :method => scope_name)
         | 
| 109 109 | 
             
                  find_calls.calls.each { |call| process_result(call) if @sql_targets.include?(call[:method]) }
         | 
| 110 | 
            -
                elsif block | 
| 110 | 
            +
                elsif call? block
         | 
| 111 111 | 
             
                  while call? block
         | 
| 112 112 | 
             
                    process_result :target => block.target, :method => block.method, :call => block,
         | 
| 113 113 | 
             
                     :location => { :type => :class, :class => model_name, :method => scope_name }
         | 
| @@ -296,7 +296,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor | |
| 296 296 |  | 
| 297 297 | 
             
              # Handles x = y = z = 1
         | 
| 298 298 | 
             
              def get_rhs exp
         | 
| 299 | 
            -
                if node_type? exp, :lasgn, :iasgn, :gasgn, :attrasgn, :cvdecl, :cdecl
         | 
| 299 | 
            +
                if node_type? exp, :lasgn, :iasgn, :gasgn, :attrasgn, :safe_attrasgn, :cvdecl, :cdecl
         | 
| 300 300 | 
             
                  get_rhs(exp.rhs)
         | 
| 301 301 | 
             
                else
         | 
| 302 302 | 
             
                  exp
         | 
| @@ -68,6 +68,14 @@ class Brakeman::BaseProcessor < Brakeman::SexpProcessor | |
| 68 68 | 
             
                call
         | 
| 69 69 | 
             
              end
         | 
| 70 70 |  | 
| 71 | 
            +
              def process_safe_call exp
         | 
| 72 | 
            +
                if self.respond_to? :process_call
         | 
| 73 | 
            +
                  process_call exp
         | 
| 74 | 
            +
                else
         | 
| 75 | 
            +
                  process_default exp
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
             | 
| 71 79 | 
             
              #String with interpolation.
         | 
| 72 80 | 
             
              def process_dstr exp
         | 
| 73 81 | 
             
                exp = exp.dup
         | 
| @@ -25,7 +25,7 @@ class Brakeman::ErbTemplateProcessor < Brakeman::TemplateProcessor | |
| 25 25 |  | 
| 26 26 | 
             
                    arg = exp.first_arg
         | 
| 27 27 |  | 
| 28 | 
            -
                    if arg | 
| 28 | 
            +
                    if call? arg and arg.method == :to_s #erb always calls to_s on output
         | 
| 29 29 | 
             
                      arg = arg.target
         | 
| 30 30 | 
             
                    end
         | 
| 31 31 |  | 
| @@ -21,7 +21,7 @@ class Brakeman::ErubisTemplateProcessor < Brakeman::TemplateProcessor | |
| 21 21 | 
             
                    arg = exp.first_arg
         | 
| 22 22 |  | 
| 23 23 | 
             
                    #We want the actual content
         | 
| 24 | 
            -
                    if arg | 
| 24 | 
            +
                    if call? arg and (arg.method == :to_s or arg.method == :html_safe!)
         | 
| 25 25 | 
             
                      arg = arg.target
         | 
| 26 26 | 
             
                    end
         | 
| 27 27 |  | 
| @@ -5,6 +5,7 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor | |
| 5 5 | 
             
              HAML_FORMAT_METHOD = /format_script_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)/
         | 
| 6 6 | 
             
              HAML_HELPERS = s(:colon2, s(:const, :Haml), :Helpers)
         | 
| 7 7 | 
             
              JAVASCRIPT_FILTER = s(:colon2, s(:colon2, s(:const, :Haml), :Filters), :Javascript)
         | 
| 8 | 
            +
              COFFEE_FILTER = s(:colon2, s(:colon2, s(:const, :Haml), :Filters), :Coffee)
         | 
| 8 9 |  | 
| 9 10 | 
             
              #Processes call, looking for template output
         | 
| 10 11 | 
             
              def process_call exp
         | 
| @@ -90,7 +91,7 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor | |
| 90 91 | 
             
                elsif target == nil and method == :find_and_preserve
         | 
| 91 92 | 
             
                  process exp.first_arg
         | 
| 92 93 | 
             
                elsif method == :render_with_options
         | 
| 93 | 
            -
                  if target == JAVASCRIPT_FILTER
         | 
| 94 | 
            +
                  if target == JAVASCRIPT_FILTER or target == COFFEE_FILTER
         | 
| 94 95 | 
             
                    @javascript = true
         | 
| 95 96 | 
             
                  end
         | 
| 96 97 |  | 
| @@ -14,4 +14,20 @@ class Brakeman::BasicProcessor < Brakeman::SexpProcessor | |
| 14 14 | 
             
              def process_default exp
         | 
| 15 15 | 
             
                process_all exp
         | 
| 16 16 | 
             
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def process_safe_call exp
         | 
| 19 | 
            +
                if self.respond_to? :process_call
         | 
| 20 | 
            +
                  process_call exp
         | 
| 21 | 
            +
                else
         | 
| 22 | 
            +
                  process_default exp
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              def process_safe_attrasgn exp
         | 
| 27 | 
            +
                if self.respond_to? :process_attrasgn
         | 
| 28 | 
            +
                  process_attrasgn exp
         | 
| 29 | 
            +
                else
         | 
| 30 | 
            +
                  process_default exp
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 17 33 | 
             
            end
         | 
| @@ -24,11 +24,13 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor | |
| 24 24 |  | 
| 25 25 | 
             
              #Process body of method
         | 
| 26 26 | 
             
              def process_defn exp
         | 
| 27 | 
            +
                return exp unless @current_method
         | 
| 27 28 | 
             
                process_all exp.body
         | 
| 28 29 | 
             
              end
         | 
| 29 30 |  | 
| 30 31 | 
             
              #Process body of method
         | 
| 31 32 | 
             
              def process_defs exp
         | 
| 33 | 
            +
                return exp unless @current_method
         | 
| 32 34 | 
             
                process_all exp.body
         | 
| 33 35 | 
             
              end
         | 
| 34 36 |  | 
| @@ -139,7 +141,7 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor | |
| 139 141 | 
             
                    @current_class || @current_module || nil
         | 
| 140 142 | 
             
                  when :params, :session, :cookies
         | 
| 141 143 | 
             
                    exp.node_type
         | 
| 142 | 
            -
                  when :call
         | 
| 144 | 
            +
                  when :call, :safe_call
         | 
| 143 145 | 
             
                    if include_calls
         | 
| 144 146 | 
             
                      if exp.target.nil?
         | 
| 145 147 | 
             
                        exp.method
         | 
| @@ -165,7 +167,7 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor | |
| 165 167 | 
             
              #Returns method chain as an array
         | 
| 166 168 | 
             
              #For example, User.human.alive.all would return [:User, :human, :alive, :all]
         | 
| 167 169 | 
             
              def get_chain call
         | 
| 168 | 
            -
                if node_type? call, :call, :attrasgn
         | 
| 170 | 
            +
                if node_type? call, :call, :attrasgn, :safe_call, :safe_attrasgn
         | 
| 169 171 | 
             
                  get_chain(call.target) + [call.method]
         | 
| 170 172 | 
             
                elsif call.nil?
         | 
| 171 173 | 
             
                  []
         | 
| @@ -102,7 +102,7 @@ class Brakeman::FindCall < Brakeman::BasicProcessor | |
| 102 102 | 
             
                #  User.find(:first, :conditions => "user = '#{params['user']}').name
         | 
| 103 103 | 
             
                #
         | 
| 104 104 | 
             
                #A search for User.find will not match this unless @in_depth is true.
         | 
| 105 | 
            -
                if @in_depth and  | 
| 105 | 
            +
                if @in_depth and call? exp.target
         | 
| 106 106 | 
             
                  process exp.target
         | 
| 107 107 | 
             
                end
         | 
| 108 108 |  | 
| @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            require 'set'
         | 
| 2 | 
            -
            require ' | 
| 2 | 
            +
            require 'json'
         | 
| 3 3 |  | 
| 4 4 | 
             
            module Brakeman
         | 
| 5 5 | 
             
              class IgnoreConfig
         | 
| @@ -75,7 +75,7 @@ module Brakeman | |
| 75 75 | 
             
                # Read configuration to file
         | 
| 76 76 | 
             
                def read_from_file file = @file
         | 
| 77 77 | 
             
                  if File.exist? file
         | 
| 78 | 
            -
                    @already_ignored =  | 
| 78 | 
            +
                    @already_ignored = JSON.parse(File.read(file), :symbolize_names => true)[:ignored_warnings]
         | 
| 79 79 | 
             
                  else
         | 
| 80 80 | 
             
                    Brakeman.notify "[Notice] Could not find ignore configuration in #{file}"
         | 
| 81 81 | 
             
                    @already_ignored = []
         | 
| @@ -107,7 +107,7 @@ module Brakeman | |
| 107 107 | 
             
                  }
         | 
| 108 108 |  | 
| 109 109 | 
             
                  File.open file, "w" do |f|
         | 
| 110 | 
            -
                    f.puts  | 
| 110 | 
            +
                    f.puts JSON.pretty_generate(output)
         | 
| 111 111 | 
             
                  end
         | 
| 112 112 | 
             
                end
         | 
| 113 113 |  | 
| @@ -1,6 +1,3 @@ | |
| 1 | 
            -
            Brakeman.load_brakeman_dependency 'multi_json'
         | 
| 2 | 
            -
            require 'brakeman/report/initializers/multi_json'
         | 
| 3 | 
            -
             | 
| 4 1 | 
             
            class Brakeman::Report::JSON < Brakeman::Report::Base
         | 
| 5 2 | 
             
              def generate_report
         | 
| 6 3 | 
             
                errors = tracker.errors.map{|e| { :error => e[:error], :location => e[:backtrace][0] }}
         | 
| @@ -32,7 +29,7 @@ class Brakeman::Report::JSON < Brakeman::Report::Base | |
| 32 29 | 
             
                  :errors => errors
         | 
| 33 30 | 
             
                }
         | 
| 34 31 |  | 
| 35 | 
            -
                 | 
| 32 | 
            +
                JSON.pretty_generate report_info
         | 
| 36 33 | 
             
              end
         | 
| 37 34 |  | 
| 38 35 | 
             
              def convert_to_hashes warnings
         | 
    
        data/lib/brakeman/tracker.rb
    CHANGED
    
    | @@ -115,6 +115,23 @@ class Brakeman::Tracker | |
| 115 115 | 
             
                end
         | 
| 116 116 | 
             
              end
         | 
| 117 117 |  | 
| 118 | 
            +
             | 
| 119 | 
            +
              def each_class
         | 
| 120 | 
            +
                classes = [self.controllers, self.models]
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                if @options[:index_libs]
         | 
| 123 | 
            +
                  classes << self.libs
         | 
| 124 | 
            +
                end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                classes.each do |set|
         | 
| 127 | 
            +
                  set.each do |set_name, collection|
         | 
| 128 | 
            +
                    collection.src.each do |file, src|
         | 
| 129 | 
            +
                      yield src, set_name, file
         | 
| 130 | 
            +
                    end
         | 
| 131 | 
            +
                  end
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
              end
         | 
| 134 | 
            +
             | 
| 118 135 | 
             
              #Find a method call.
         | 
| 119 136 | 
             
              #
         | 
| 120 137 | 
             
              #Options:
         | 
| @@ -178,6 +195,10 @@ class Brakeman::Tracker | |
| 178 195 | 
             
                  finder.process_source definition, :class => set_name, :method => method_name, :file => file
         | 
| 179 196 | 
             
                end
         | 
| 180 197 |  | 
| 198 | 
            +
                self.each_class do |definition, set_name, file|
         | 
| 199 | 
            +
                  finder.process_source definition, :class => set_name, :file => file
         | 
| 200 | 
            +
                end
         | 
| 201 | 
            +
             | 
| 181 202 | 
             
                self.each_template do |name, template|
         | 
| 182 203 | 
             
                  finder.process_source template.src, :template => template, :file => template.file
         | 
| 183 204 | 
             
                end
         | 
    
        data/lib/brakeman/util.rb
    CHANGED
    
    | @@ -167,7 +167,8 @@ module Brakeman::Util | |
| 167 167 |  | 
| 168 168 | 
             
              #Check if _exp_ represents a method call: s(:call, ...)
         | 
| 169 169 | 
             
              def call? exp
         | 
| 170 | 
            -
                exp.is_a? Sexp and | 
| 170 | 
            +
                exp.is_a? Sexp and
         | 
| 171 | 
            +
                  (exp.node_type == :call or exp.node_type == :safe_call)
         | 
| 171 172 | 
             
              end
         | 
| 172 173 |  | 
| 173 174 | 
             
              #Check if _exp_ represents a Regexp: s(:lit, /.../)
         | 
| @@ -214,7 +215,7 @@ module Brakeman::Util | |
| 214 215 | 
             
                if exp.is_a? Sexp
         | 
| 215 216 | 
             
                  return true if exp.node_type == :params or ALL_PARAMETERS.include? exp
         | 
| 216 217 |  | 
| 217 | 
            -
                  if exp | 
| 218 | 
            +
                  if call? exp
         | 
| 218 219 | 
             
                    if params? exp[1]
         | 
| 219 220 | 
             
                      return true
         | 
| 220 221 | 
             
                    elsif exp[2] == :[]
         | 
| @@ -230,7 +231,7 @@ module Brakeman::Util | |
| 230 231 | 
             
                if exp.is_a? Sexp
         | 
| 231 232 | 
             
                  return true if exp.node_type == :cookies or exp == COOKIES
         | 
| 232 233 |  | 
| 233 | 
            -
                  if exp | 
| 234 | 
            +
                  if call? exp
         | 
| 234 235 | 
             
                    if cookies? exp[1]
         | 
| 235 236 | 
             
                      return true
         | 
| 236 237 | 
             
                    elsif exp[2] == :[]
         | 
    
        data/lib/brakeman/version.rb
    CHANGED
    
    
    
        data/lib/brakeman/warning.rb
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            require ' | 
| 1 | 
            +
            require 'json'
         | 
| 2 2 | 
             
            require 'digest/sha2'
         | 
| 3 3 | 
             
            require 'brakeman/warning_codes'
         | 
| 4 4 |  | 
| @@ -241,7 +241,7 @@ class Brakeman::Warning | |
| 241 241 | 
             
              end
         | 
| 242 242 |  | 
| 243 243 | 
             
              def to_json
         | 
| 244 | 
            -
                 | 
| 244 | 
            +
                JSON.generate self.to_hash
         | 
| 245 245 | 
             
              end
         | 
| 246 246 |  | 
| 247 247 | 
             
              private
         | 
    
        data/lib/ruby_parser/bm_sexp.rb
    CHANGED
    
    | @@ -141,13 +141,13 @@ class Sexp | |
| 141 141 | 
             
              #s(:call, s(:call, nil, :x, s(:arglist)), :y, s(:arglist, s(:lit, 1)))
         | 
| 142 142 | 
             
              #         ^-----------target-----------^
         | 
| 143 143 | 
             
              def target
         | 
| 144 | 
            -
                expect :call, :attrasgn
         | 
| 144 | 
            +
                expect :call, :attrasgn, :safe_call, :safe_attrasgn
         | 
| 145 145 | 
             
                self[1]
         | 
| 146 146 | 
             
              end
         | 
| 147 147 |  | 
| 148 148 | 
             
              #Sets the target of a method call:
         | 
| 149 149 | 
             
              def target= exp
         | 
| 150 | 
            -
                expect :call, :attrasgn
         | 
| 150 | 
            +
                expect :call, :attrasgn, :safe_call, :safe_attrasgn
         | 
| 151 151 | 
             
                @my_hash_value = nil
         | 
| 152 152 | 
             
                self[1] = exp
         | 
| 153 153 | 
             
              end
         | 
| @@ -157,10 +157,10 @@ class Sexp | |
| 157 157 | 
             
              #s(:call, s(:call, nil, :x, s(:arglist)), :y, s(:arglist, s(:lit, 1)))
         | 
| 158 158 | 
             
              #                        ^- method
         | 
| 159 159 | 
             
              def method
         | 
| 160 | 
            -
                expect :call, :attrasgn, :super, :zsuper, :result
         | 
| 160 | 
            +
                expect :call, :attrasgn, :safe_call, :safe_attrasgn, :super, :zsuper, :result
         | 
| 161 161 |  | 
| 162 162 | 
             
                case self.node_type
         | 
| 163 | 
            -
                when :call, :attrasgn
         | 
| 163 | 
            +
                when :call, :attrasgn, :safe_call, :safe_attrasgn
         | 
| 164 164 | 
             
                  self[2]
         | 
| 165 165 | 
             
                when :super, :zsuper
         | 
| 166 166 | 
             
                  :super
         | 
| @@ -170,14 +170,14 @@ class Sexp | |
| 170 170 | 
             
              end
         | 
| 171 171 |  | 
| 172 172 | 
             
              def method= name
         | 
| 173 | 
            -
                expect :call
         | 
| 173 | 
            +
                expect :call, :safe_call
         | 
| 174 174 |  | 
| 175 175 | 
             
                self[2] = name
         | 
| 176 176 | 
             
              end
         | 
| 177 177 |  | 
| 178 178 | 
             
              #Sets the arglist in a method call.
         | 
| 179 179 | 
             
              def arglist= exp
         | 
| 180 | 
            -
                expect :call, :attrasgn
         | 
| 180 | 
            +
                expect :call, :attrasgn, :safe_call, :safe_attrasgn
         | 
| 181 181 | 
             
                @my_hash_value = nil
         | 
| 182 182 | 
             
                start_index = 3
         | 
| 183 183 |  | 
| @@ -201,10 +201,10 @@ class Sexp | |
| 201 201 | 
             
              #    s(:call, s(:call, nil, :x, s(:arglist)), :y, s(:arglist, s(:lit, 1), s(:lit, 2)))
         | 
| 202 202 | 
             
              #                                                 ^------------ arglist ------------^
         | 
| 203 203 | 
             
              def arglist
         | 
| 204 | 
            -
                expect :call, :attrasgn, :super, :zsuper
         | 
| 204 | 
            +
                expect :call, :attrasgn, :safe_call, :safe_attrasgn, :super, :zsuper
         | 
| 205 205 |  | 
| 206 206 | 
             
                case self.node_type
         | 
| 207 | 
            -
                when :call, :attrasgn
         | 
| 207 | 
            +
                when :call, :attrasgn, :safe_call, :safe_attrasgn
         | 
| 208 208 | 
             
                  self[3..-1].unshift :arglist
         | 
| 209 209 | 
             
                when :super, :zsuper
         | 
| 210 210 | 
             
                  if self[1]
         | 
| @@ -220,10 +220,10 @@ class Sexp | |
| 220 220 | 
             
              #    s(:call, s(:call, nil, :x, s(:arglist)), :y, s(:arglist, s(:lit, 1), s(:lit, 2)))
         | 
| 221 221 | 
             
              #                                                             ^--------args--------^
         | 
| 222 222 | 
             
              def args
         | 
| 223 | 
            -
                expect :call, :attrasgn, :super, :zsuper
         | 
| 223 | 
            +
                expect :call, :attrasgn, :safe_call, :safe_attrasgn, :super, :zsuper
         | 
| 224 224 |  | 
| 225 225 | 
             
                case self.node_type
         | 
| 226 | 
            -
                when :call, :attrasgn
         | 
| 226 | 
            +
                when :call, :attrasgn, :safe_call, :safe_attrasgn
         | 
| 227 227 | 
             
                  if self[3]
         | 
| 228 228 | 
             
                    self[3..-1]
         | 
| 229 229 | 
             
                  else
         | 
| @@ -239,11 +239,11 @@ class Sexp | |
| 239 239 | 
             
              end
         | 
| 240 240 |  | 
| 241 241 | 
             
              def each_arg replace = false
         | 
| 242 | 
            -
                expect :call, :attrasgn, :super, :zsuper
         | 
| 242 | 
            +
                expect :call, :attrasgn, :safe_call, :safe_attrasgn, :super, :zsuper
         | 
| 243 243 | 
             
                range = nil
         | 
| 244 244 |  | 
| 245 245 | 
             
                case self.node_type
         | 
| 246 | 
            -
                when :call, :attrasgn
         | 
| 246 | 
            +
                when :call, :attrasgn, :safe_call, :safe_attrasgn
         | 
| 247 247 | 
             
                  if self[3]
         | 
| 248 248 | 
             
                    range = (3...self.length)
         | 
| 249 249 | 
             
                  end
         | 
| @@ -270,43 +270,43 @@ class Sexp | |
| 270 270 |  | 
| 271 271 | 
             
              #Returns first argument of a method call.
         | 
| 272 272 | 
             
              def first_arg
         | 
| 273 | 
            -
                expect :call, :attrasgn
         | 
| 273 | 
            +
                expect :call, :attrasgn, :safe_call, :safe_attrasgn
         | 
| 274 274 | 
             
                self[3]
         | 
| 275 275 | 
             
              end
         | 
| 276 276 |  | 
| 277 277 | 
             
              #Sets first argument of a method call.
         | 
| 278 278 | 
             
              def first_arg= exp
         | 
| 279 | 
            -
                expect :call, :attrasgn
         | 
| 279 | 
            +
                expect :call, :attrasgn, :safe_call, :safe_attrasgn
         | 
| 280 280 | 
             
                @my_hash_value = nil
         | 
| 281 281 | 
             
                self[3] = exp
         | 
| 282 282 | 
             
              end
         | 
| 283 283 |  | 
| 284 284 | 
             
              #Returns second argument of a method call.
         | 
| 285 285 | 
             
              def second_arg
         | 
| 286 | 
            -
                expect :call, :attrasgn
         | 
| 286 | 
            +
                expect :call, :attrasgn, :safe_call, :safe_attrasgn
         | 
| 287 287 | 
             
                self[4]
         | 
| 288 288 | 
             
              end
         | 
| 289 289 |  | 
| 290 290 | 
             
              #Sets second argument of a method call.
         | 
| 291 291 | 
             
              def second_arg= exp
         | 
| 292 | 
            -
                expect :call, :attrasgn
         | 
| 292 | 
            +
                expect :call, :attrasgn, :safe_call, :safe_attrasgn
         | 
| 293 293 | 
             
                @my_hash_value = nil
         | 
| 294 294 | 
             
                self[4] = exp
         | 
| 295 295 | 
             
              end
         | 
| 296 296 |  | 
| 297 297 | 
             
              def third_arg
         | 
| 298 | 
            -
                expect :call, :attrasgn
         | 
| 298 | 
            +
                expect :call, :attrasgn, :safe_call, :safe_attrasgn
         | 
| 299 299 | 
             
                self[5]
         | 
| 300 300 | 
             
              end
         | 
| 301 301 |  | 
| 302 302 | 
             
              def third_arg= exp
         | 
| 303 | 
            -
                expect :call, :attrasgn
         | 
| 303 | 
            +
                expect :call, :attrasgn, :safe_call, :safe_attrasgn
         | 
| 304 304 | 
             
                @my_hash_value = nil
         | 
| 305 305 | 
             
                self[5] = exp
         | 
| 306 306 | 
             
              end
         | 
| 307 307 |  | 
| 308 308 | 
             
              def last_arg
         | 
| 309 | 
            -
                expect :call, :attrasgn
         | 
| 309 | 
            +
                expect :call, :attrasgn, :safe_call, :safe_attrasgn
         | 
| 310 310 |  | 
| 311 311 | 
             
                if self[3]
         | 
| 312 312 | 
             
                  self[-1]
         | 
| @@ -427,9 +427,9 @@ class Sexp | |
| 427 427 | 
             
              #    s(:lasgn, :x, s(:lit, 1))
         | 
| 428 428 | 
             
              #                  ^--rhs---^
         | 
| 429 429 | 
             
              def rhs
         | 
| 430 | 
            -
                expect :attrasgn, *ASSIGNMENT_BOOL
         | 
| 430 | 
            +
                expect :attrasgn, :safe_attrasgn, *ASSIGNMENT_BOOL
         | 
| 431 431 |  | 
| 432 | 
            -
                if self.node_type == :attrasgn
         | 
| 432 | 
            +
                if self.node_type == :attrasgn or self.node_type == :safe_attrasgn
         | 
| 433 433 | 
             
                  self[3]
         | 
| 434 434 | 
             
                else
         | 
| 435 435 | 
             
                  self[2]
         | 
| @@ -438,10 +438,10 @@ class Sexp | |
| 438 438 |  | 
| 439 439 | 
             
              #Sets the right hand side of assignment or boolean.
         | 
| 440 440 | 
             
              def rhs= exp
         | 
| 441 | 
            -
                expect :attrasgn, *ASSIGNMENT_BOOL
         | 
| 441 | 
            +
                expect :attrasgn, :safe_attrasgn, *ASSIGNMENT_BOOL
         | 
| 442 442 | 
             
                @my_hash_value = nil
         | 
| 443 443 |  | 
| 444 | 
            -
                if self.node_type == :attrasgn
         | 
| 444 | 
            +
                if self.node_type == :attrasgn or self.node_type == :safe_attrasgn
         | 
| 445 445 | 
             
                  self[3] = exp
         | 
| 446 446 | 
             
                else
         | 
| 447 447 | 
             
                  self[2] = exp
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: brakeman
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 3. | 
| 4 | 
            +
              version: 3.2.0.pre1
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Justin Collins
         | 
| @@ -9,7 +9,7 @@ autorequire: | |
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain:
         | 
| 11 11 | 
             
            - brakeman-public_cert.pem
         | 
| 12 | 
            -
            date: 2016- | 
| 12 | 
            +
            date: 2016-02-22 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies:
         | 
| 14 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 15 | 
             
              name: test-unit
         | 
| @@ -31,32 +31,26 @@ dependencies: | |
| 31 31 | 
             
                requirements:
         | 
| 32 32 | 
             
                - - "~>"
         | 
| 33 33 | 
             
                  - !ruby/object:Gem::Version
         | 
| 34 | 
            -
                    version: 3. | 
| 34 | 
            +
                    version: 3.8.1
         | 
| 35 35 | 
             
              type: :runtime
         | 
| 36 36 | 
             
              prerelease: false
         | 
| 37 37 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 38 38 | 
             
                requirements:
         | 
| 39 39 | 
             
                - - "~>"
         | 
| 40 40 | 
             
                  - !ruby/object:Gem::Version
         | 
| 41 | 
            -
                    version: 3. | 
| 41 | 
            +
                    version: 3.8.1
         | 
| 42 42 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 43 43 | 
             
              name: ruby2ruby
         | 
| 44 44 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 45 45 | 
             
                requirements:
         | 
| 46 | 
            -
                - - " | 
| 47 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 48 | 
            -
                    version: 2.1.1
         | 
| 49 | 
            -
                - - "<"
         | 
| 46 | 
            +
                - - "~>"
         | 
| 50 47 | 
             
                  - !ruby/object:Gem::Version
         | 
| 51 48 | 
             
                    version: 2.3.0
         | 
| 52 49 | 
             
              type: :runtime
         | 
| 53 50 | 
             
              prerelease: false
         | 
| 54 51 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 55 52 | 
             
                requirements:
         | 
| 56 | 
            -
                - - " | 
| 57 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 58 | 
            -
                    version: 2.1.1
         | 
| 59 | 
            -
                - - "<"
         | 
| 53 | 
            +
                - - "~>"
         | 
| 60 54 | 
             
                  - !ruby/object:Gem::Version
         | 
| 61 55 | 
             
                    version: 2.3.0
         | 
| 62 56 | 
             
            - !ruby/object:Gem::Dependency
         | 
| @@ -73,20 +67,6 @@ dependencies: | |
| 73 67 | 
             
                - - "~>"
         | 
| 74 68 | 
             
                  - !ruby/object:Gem::Version
         | 
| 75 69 | 
             
                    version: '1.4'
         | 
| 76 | 
            -
            - !ruby/object:Gem::Dependency
         | 
| 77 | 
            -
              name: fastercsv
         | 
| 78 | 
            -
              requirement: !ruby/object:Gem::Requirement
         | 
| 79 | 
            -
                requirements:
         | 
| 80 | 
            -
                - - "~>"
         | 
| 81 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 82 | 
            -
                    version: '1.5'
         | 
| 83 | 
            -
              type: :runtime
         | 
| 84 | 
            -
              prerelease: false
         | 
| 85 | 
            -
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 86 | 
            -
                requirements:
         | 
| 87 | 
            -
                - - "~>"
         | 
| 88 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 89 | 
            -
                    version: '1.5'
         | 
| 90 70 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 91 71 | 
             
              name: highline
         | 
| 92 72 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -175,20 +155,6 @@ dependencies: | |
| 175 155 | 
             
                - - "<"
         | 
| 176 156 | 
             
                  - !ruby/object:Gem::Version
         | 
| 177 157 | 
             
                    version: '4.0'
         | 
| 178 | 
            -
            - !ruby/object:Gem::Dependency
         | 
| 179 | 
            -
              name: multi_json
         | 
| 180 | 
            -
              requirement: !ruby/object:Gem::Requirement
         | 
| 181 | 
            -
                requirements:
         | 
| 182 | 
            -
                - - "~>"
         | 
| 183 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 184 | 
            -
                    version: '1.2'
         | 
| 185 | 
            -
              type: :runtime
         | 
| 186 | 
            -
              prerelease: false
         | 
| 187 | 
            -
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 188 | 
            -
                requirements:
         | 
| 189 | 
            -
                - - "~>"
         | 
| 190 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 191 | 
            -
                    version: '1.2'
         | 
| 192 158 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 193 159 | 
             
              name: safe_yaml
         | 
| 194 160 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -329,8 +295,6 @@ files: | |
| 329 295 | 
             
            - lib/brakeman/report/config/remediation.yml
         | 
| 330 296 | 
             
            - lib/brakeman/report/ignore/config.rb
         | 
| 331 297 | 
             
            - lib/brakeman/report/ignore/interactive.rb
         | 
| 332 | 
            -
            - lib/brakeman/report/initializers/faster_csv.rb
         | 
| 333 | 
            -
            - lib/brakeman/report/initializers/multi_json.rb
         | 
| 334 298 | 
             
            - lib/brakeman/report/renderer.rb
         | 
| 335 299 | 
             
            - lib/brakeman/report/report_base.rb
         | 
| 336 300 | 
             
            - lib/brakeman/report/report_codeclimate.rb
         | 
| @@ -382,9 +346,9 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 382 346 | 
             
                  version: '0'
         | 
| 383 347 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 384 348 | 
             
              requirements:
         | 
| 385 | 
            -
              - - " | 
| 349 | 
            +
              - - ">"
         | 
| 386 350 | 
             
                - !ruby/object:Gem::Version
         | 
| 387 | 
            -
                  version:  | 
| 351 | 
            +
                  version: 1.3.1
         | 
| 388 352 | 
             
            requirements: []
         | 
| 389 353 | 
             
            rubyforge_project: 
         | 
| 390 354 | 
             
            rubygems_version: 2.4.8
         | 
| @@ -1,29 +0,0 @@ | |
| 1 | 
            -
            #MultiJson interface changed in 1.3.0, but need
         | 
| 2 | 
            -
            #to support older MultiJson for Rails 3.1.
         | 
| 3 | 
            -
            mj_engine = nil
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            if MultiJson.respond_to? :default_adapter
         | 
| 6 | 
            -
              mj_engine = MultiJson.default_adapter
         | 
| 7 | 
            -
            else
         | 
| 8 | 
            -
              mj_engine = MultiJson.default_engine
         | 
| 9 | 
            -
             | 
| 10 | 
            -
              module MultiJson
         | 
| 11 | 
            -
                def self.dump *args
         | 
| 12 | 
            -
                  encode *args
         | 
| 13 | 
            -
                end
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                def self.load *args
         | 
| 16 | 
            -
                  decode *args
         | 
| 17 | 
            -
                end
         | 
| 18 | 
            -
              end
         | 
| 19 | 
            -
            end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
            #This is so OkJson will work with symbol values
         | 
| 22 | 
            -
            if mj_engine == :ok_json
         | 
| 23 | 
            -
              class Symbol
         | 
| 24 | 
            -
                def to_json
         | 
| 25 | 
            -
                  self.to_s.inspect
         | 
| 26 | 
            -
                end
         | 
| 27 | 
            -
              end
         | 
| 28 | 
            -
            end
         | 
| 29 | 
            -
             |