brakeman 1.8.3 → 1.9.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/README.md +3 -27
  2. data/lib/brakeman.rb +36 -38
  3. data/lib/brakeman/app_tree.rb +90 -0
  4. data/lib/brakeman/call_index.rb +5 -38
  5. data/lib/brakeman/checks.rb +11 -11
  6. data/lib/brakeman/checks/base_check.rb +53 -29
  7. data/lib/brakeman/checks/check_cross_site_scripting.rb +11 -9
  8. data/lib/brakeman/checks/check_evaluation.rb +1 -1
  9. data/lib/brakeman/checks/check_execute.rb +3 -3
  10. data/lib/brakeman/checks/check_link_to.rb +15 -13
  11. data/lib/brakeman/checks/check_link_to_href.rb +1 -1
  12. data/lib/brakeman/checks/check_mail_to.rb +1 -1
  13. data/lib/brakeman/checks/check_mass_assignment.rb +27 -13
  14. data/lib/brakeman/checks/check_redirect.rb +4 -4
  15. data/lib/brakeman/checks/check_select_tag.rb +1 -1
  16. data/lib/brakeman/checks/check_select_vulnerability.rb +1 -1
  17. data/lib/brakeman/checks/check_send.rb +2 -2
  18. data/lib/brakeman/checks/check_session_settings.rb +12 -5
  19. data/lib/brakeman/checks/check_single_quotes.rb +3 -3
  20. data/lib/brakeman/checks/check_skip_before_filter.rb +4 -3
  21. data/lib/brakeman/checks/check_sql.rb +30 -30
  22. data/lib/brakeman/checks/check_translate_bug.rb +11 -10
  23. data/lib/brakeman/checks/check_validation_regex.rb +36 -11
  24. data/lib/brakeman/checks/check_without_protection.rb +1 -1
  25. data/lib/brakeman/options.rb +6 -2
  26. data/lib/brakeman/processor.rb +6 -5
  27. data/lib/brakeman/processors/alias_processor.rb +153 -38
  28. data/lib/brakeman/processors/base_processor.rb +16 -21
  29. data/lib/brakeman/processors/controller_alias_processor.rb +24 -11
  30. data/lib/brakeman/processors/controller_processor.rb +25 -25
  31. data/lib/brakeman/processors/erb_template_processor.rb +6 -7
  32. data/lib/brakeman/processors/erubis_template_processor.rb +2 -3
  33. data/lib/brakeman/processors/gem_processor.rb +5 -4
  34. data/lib/brakeman/processors/haml_template_processor.rb +4 -6
  35. data/lib/brakeman/processors/lib/find_all_calls.rb +3 -3
  36. data/lib/brakeman/processors/lib/find_call.rb +2 -2
  37. data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
  38. data/lib/brakeman/processors/lib/processor_helper.rb +24 -2
  39. data/lib/brakeman/processors/lib/rails2_config_processor.rb +13 -14
  40. data/lib/brakeman/processors/lib/rails2_route_processor.rb +9 -4
  41. data/lib/brakeman/processors/lib/rails3_config_processor.rb +8 -8
  42. data/lib/brakeman/processors/lib/rails3_route_processor.rb +23 -21
  43. data/lib/brakeman/processors/lib/render_helper.rb +2 -2
  44. data/lib/brakeman/processors/library_processor.rb +2 -2
  45. data/lib/brakeman/processors/model_processor.rb +16 -12
  46. data/lib/brakeman/processors/output_processor.rb +2 -1
  47. data/lib/brakeman/processors/template_alias_processor.rb +12 -8
  48. data/lib/brakeman/report.rb +28 -14
  49. data/lib/brakeman/rescanner.rb +5 -5
  50. data/lib/brakeman/scanner.rb +56 -94
  51. data/lib/brakeman/templates/header.html.erb +7 -2
  52. data/lib/brakeman/tracker.rb +14 -4
  53. data/lib/brakeman/util.rb +38 -17
  54. data/lib/brakeman/version.rb +1 -1
  55. data/lib/brakeman/warning.rb +14 -6
  56. data/lib/ruby_parser/bm_sexp.rb +157 -57
  57. data/lib/ruby_parser/bm_sexp_processor.rb +1 -2
  58. metadata +26 -25
  59. data/lib/ruby_parser/ruby18_parser.rb +0 -5544
  60. data/lib/ruby_parser/ruby19_parser.rb +0 -5756
  61. data/lib/ruby_parser/ruby_lexer.rb +0 -1349
  62. data/lib/ruby_parser/ruby_parser.rb +0 -5
  63. data/lib/ruby_parser/ruby_parser_extras.rb +0 -1057
@@ -1,7 +1,6 @@
1
1
  require 'brakeman/checks/base_check'
2
2
 
3
3
  #Check for vulnerability in translate() helper that allows cross-site scripting
4
- #http://groups.google.com/group/rubyonrails-security/browse_thread/thread/2b61d70fb73c7cc5
5
4
  class Brakeman::CheckTranslateBug < Brakeman::BaseCheck
6
5
  Brakeman::Checks.add self
7
6
 
@@ -12,32 +11,34 @@ class Brakeman::CheckTranslateBug < Brakeman::BaseCheck
12
11
  version_between?('3.0.0', '3.0.10') or
13
12
  version_between?('3.1.0', '3.1.1')
14
13
 
15
- if uses_translate?
16
- confidence = CONFIDENCE[:high]
14
+ confidence = if uses_translate?
15
+ CONFIDENCE[:high]
17
16
  else
18
- confidence = CONFIDENCE[:med]
17
+ CONFIDENCE[:med]
19
18
  end
20
19
 
21
20
  version = tracker.config[:rails_version]
21
+ description = "have a vulnerability in the translate helper with keys ending in _html"
22
22
 
23
- if version =~ /^3\.1/
24
- message = "Versions before 3.1.2 have a vulnerability in the translate helper."
23
+ message = if version =~ /^3\.1/
24
+ "Versions before 3.1.2 #{description}."
25
25
  elsif version =~ /^3\.0/
26
- message = "Versions before 3.0.11 have a vulnerability in translate helper."
26
+ "Versions before 3.0.11 #{description}."
27
27
  else
28
- message = "Rails 2.3.x using the rails_xss plugin have a vulnerability in translate helper."
28
+ "Rails 2.3.x using the rails_xss plugin #{description}}."
29
29
  end
30
30
 
31
31
  warn :warning_type => "Cross Site Scripting",
32
32
  :message => message,
33
33
  :confidence => confidence,
34
- :file => gemfile_or_environment
34
+ :file => gemfile_or_environment,
35
+ :link_path => "http://groups.google.com/group/rubyonrails-security/browse_thread/thread/2b61d70fb73c7cc5"
35
36
  end
36
37
  end
37
38
 
38
39
  def uses_translate?
39
40
  Brakeman.debug "Finding calls to translate() or t()"
40
41
 
41
- not tracker.find_call(:target => nil, :methods => [:t, :translate]).empty?
42
+ tracker.find_call(:target => nil, :methods => [:t, :translate]).any?
42
43
  end
43
44
  end
@@ -13,48 +13,73 @@ class Brakeman::CheckValidationRegex < Brakeman::BaseCheck
13
13
  @description = "Report uses of validates_format_of with improper anchors"
14
14
 
15
15
  WITH = Sexp.new(:lit, :with)
16
+ FORMAT = Sexp.new(:lit, :format)
16
17
 
17
18
  def run_check
18
19
  active_record_models.each do |name, model|
19
20
  @current_model = name
20
21
  format_validations = model[:options][:validates_format_of]
22
+
21
23
  if format_validations
22
24
  format_validations.each do |v|
23
- process_validator v
25
+ process_validates_format_of v
26
+ end
27
+ end
28
+
29
+ validates = model[:options][:validates]
30
+
31
+ if validates
32
+ validates.each do |v|
33
+ process_validates v
24
34
  end
25
35
  end
26
36
  end
27
37
  end
28
38
 
29
39
  #Check validates_format_of
30
- def process_validator validator
40
+ def process_validates_format_of validator
31
41
  if value = hash_access(validator.last, WITH)
32
42
  check_regex value, validator
33
43
  end
34
44
  end
35
45
 
46
+ #Check validates ..., :format => ...
47
+ def process_validates validator
48
+ hash_arg = validator.last
49
+ return unless hash? hash_arg
50
+
51
+ value = hash_access(hash_arg, FORMAT)
52
+
53
+ if hash? value
54
+ value = hash_access(value, WITH)
55
+ end
56
+
57
+ if value
58
+ check_regex value, validator
59
+ end
60
+ end
61
+
36
62
  #Issue warning if the regular expression does not use
37
63
  #+\A+ and +\z+
38
64
  def check_regex value, validator
39
65
  return unless regexp? value
40
66
 
41
67
  regex = value.value.inspect
42
- if regex =~ /^\/(.{2}).*(.{2})\/(m|i|x|n|e|u|s|o)*\z/
43
- if $1 != "\\A" or ($2 != "\\Z" and $2 != "\\z")
44
- warn :model => @current_model,
45
- :warning_type => "Format Validation",
46
- :message => "Insufficient validation for '#{get_name validator}' using #{value.value.inspect}. Use \\A and \\z as anchors",
47
- :line => value.line,
48
- :confidence => CONFIDENCE[:high]
49
- end
68
+ unless regex =~ /\A\/\\A.*\\(z|Z)\/(m|i|x|n|e|u|s|o)*\z/
69
+ warn :model => @current_model,
70
+ :warning_type => "Format Validation",
71
+ :message => "Insufficient validation for '#{get_name validator}' using #{regex}. Use \\A and \\z as anchors",
72
+ :line => value.line,
73
+ :confidence => CONFIDENCE[:high]
50
74
  end
51
75
  end
52
76
 
53
77
  #Get the name of the attribute being validated.
54
78
  def get_name validator
55
79
  name = validator[1]
80
+
56
81
  if sexp? name
57
- name[1]
82
+ name.value
58
83
  else
59
84
  name
60
85
  end
@@ -33,7 +33,7 @@ class Brakeman::CheckWithoutProtection < Brakeman::BaseCheck
33
33
  #All results should be Model.new(...) or Model.attributes=() calls
34
34
  def process_result res
35
35
  call = res[:call]
36
- last_arg = call.args.last
36
+ last_arg = call.last_arg
37
37
 
38
38
  if hash? last_arg and not call.original_line and not duplicate? res
39
39
 
@@ -50,8 +50,8 @@ module Brakeman::Options
50
50
  opts.separator ""
51
51
  opts.separator "Scanning options:"
52
52
 
53
- opts.on "-a", "--assume-routes", "Assume all controller methods are actions" do
54
- options[:assume_all_routes] = true
53
+ opts.on "-a", "--[no-]assume-routes", "Assume all controller methods are actions (default)" do |assume|
54
+ options[:assume_all_routes] = assume
55
55
  end
56
56
 
57
57
  opts.on "-e", "--escape-html", "Escape HTML by default" do
@@ -71,6 +71,10 @@ module Brakeman::Options
71
71
  options[:ignore_attr_protected] = true
72
72
  end
73
73
 
74
+ opts.on "--interprocedural", "Process method calls to known methods" do
75
+ options[:interprocedural] = true
76
+ end
77
+
74
78
  opts.on "--no-branching", "Disable flow sensitivity on conditionals" do
75
79
  options[:ignore_ifs] = true
76
80
  end
@@ -12,8 +12,9 @@ module Brakeman
12
12
  class Processor
13
13
  include Util
14
14
 
15
- def initialize options
16
- @tracker = Tracker.new self, options
15
+ def initialize(app_tree, options)
16
+ @app_tree = app_tree
17
+ @tracker = Tracker.new(@app_tree, self, options)
17
18
  end
18
19
 
19
20
  def tracked_events
@@ -38,7 +39,7 @@ module Brakeman
38
39
  #Process controller source. +file_name+ is used for reporting
39
40
  def process_controller src, file_name
40
41
  if contains_class? src
41
- ControllerProcessor.new(@tracker).process_controller src, file_name
42
+ ControllerProcessor.new(@app_tree, @tracker).process_controller src, file_name
42
43
  else
43
44
  LibraryProcessor.new(@tracker).process_library src, file_name
44
45
  end
@@ -47,13 +48,13 @@ module Brakeman
47
48
  #Process variable aliasing in controller source and save it in the
48
49
  #tracker.
49
50
  def process_controller_alias name, src, only_method = nil
50
- ControllerAliasProcessor.new(@tracker, only_method).process_controller name, src
51
+ ControllerAliasProcessor.new(@app_tree, @tracker, only_method).process_controller name, src
51
52
  end
52
53
 
53
54
  #Process a model source
54
55
  def process_model src, file_name
55
56
  result = ModelProcessor.new(@tracker).process_model src, file_name
56
- AliasProcessor.new(@tracker).process result
57
+ AliasProcessor.new(@tracker).process_all result if result
57
58
  end
58
59
 
59
60
  #Process either an ERB or HAML template
@@ -24,6 +24,8 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
24
24
  @exp_context = []
25
25
  @current_module = nil
26
26
  @tracker = tracker #set in subclass as necessary
27
+ @helper_method_cache = {}
28
+ @helper_method_info = Hash.new({})
27
29
  set_env_defaults
28
30
  end
29
31
 
@@ -70,11 +72,9 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
70
72
  @exp_context.push exp
71
73
 
72
74
  begin
73
- exp.each_with_index do |e, i|
74
- next if i == 0
75
-
75
+ exp.map! do |e|
76
76
  if sexp? e and not e.empty?
77
- exp[i] = process e
77
+ process e
78
78
  else
79
79
  e
80
80
  end
@@ -107,7 +107,6 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
107
107
 
108
108
  target = exp.target
109
109
  method = exp.method
110
- args = exp[3]
111
110
  first_arg = exp.first_arg
112
111
 
113
112
  #See if it is possible to simplify some basic cases
@@ -154,7 +153,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
154
153
  temp_exp = process_array_access target, exp.args
155
154
  exp = temp_exp if temp_exp
156
155
  elsif hash? target
157
- temp_exp = process_hash_access target, exp.args
156
+ temp_exp = process_hash_access target, first_arg
158
157
  exp = temp_exp if temp_exp
159
158
  end
160
159
  when :merge!, :update
@@ -204,7 +203,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
204
203
  def process_methdef exp
205
204
  env.scope do
206
205
  set_env_defaults
207
- process exp.body
206
+ exp.body = process_all! exp.body
208
207
  end
209
208
  exp
210
209
  end
@@ -213,7 +212,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
213
212
  def process_selfdef exp
214
213
  env.scope do
215
214
  set_env_defaults
216
- process exp.body
215
+ exp.body = process_all! exp.body
217
216
  end
218
217
  exp
219
218
  end
@@ -231,8 +230,10 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
231
230
 
232
231
  if @inside_if and val = env[local]
233
232
  #avoid setting to value it already is (e.g. "1 or 1")
234
- if val != exp.rhs and val[1] != exp.rhs and val[2] != exp.rhs
235
- env[local] = Sexp.new(:or, val, exp.rhs).line(exp.line || -2)
233
+ if val != exp.rhs
234
+ unless node_type?(val, :or) and (val.rhs == exp.rhs or val.lhs == exp.rhs)
235
+ env[local] = Sexp.new(:or, val, exp.rhs).line(exp.line || -2)
236
+ end
236
237
  end
237
238
  else
238
239
  env[local] = exp.rhs
@@ -300,21 +301,22 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
300
301
  tar_variable = exp.target
301
302
  target = exp.target = process(exp.target)
302
303
  method = exp.method
303
- args = exp.args
304
+ index_arg = exp.first_arg
305
+ value_arg = exp.second_arg
304
306
 
305
307
  if method == :[]=
306
- index = exp.first_arg = process(args.first)
307
- value = exp.second_arg = process(args.second)
308
- match = Sexp.new(:call, target, :[], Sexp.new(:arglist, index))
308
+ index = exp.first_arg = process(index_arg)
309
+ value = exp.second_arg = process(value_arg)
310
+ match = Sexp.new(:call, target, :[], index)
309
311
  env[match] = value
310
312
 
311
313
  if hash? target
312
314
  env[tar_variable] = hash_insert target.deep_clone, index, value
313
315
  end
314
316
  elsif method.to_s[-1,1] == "="
315
- value = exp.first_arg = process(args.first)
317
+ value = exp.first_arg = process(index_arg)
316
318
  #This is what we'll replace with the value
317
- match = Sexp.new(:call, target, method.to_s[0..-2].to_sym, Sexp.new(:arglist))
319
+ match = Sexp.new(:call, target, method.to_s[0..-2].to_sym)
318
320
 
319
321
  if @inside_if and val = env[match]
320
322
  if val != value
@@ -336,7 +338,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
336
338
  hash = hash.deep_clone
337
339
  hash_iterate args do |key, replacement|
338
340
  hash_insert hash, key, replacement
339
- match = Sexp.new(:call, hash, :[], Sexp.new(:arglist, key))
341
+ match = Sexp.new(:call, hash, :[], key)
340
342
  env[match] = replacement
341
343
  end
342
344
  hash
@@ -361,7 +363,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
361
363
  target = exp[1] = process(exp[1])
362
364
  index = exp[2][1] = process(exp[2][1])
363
365
  value = exp[4] = process(exp[4])
364
- match = Sexp.new(:call, target, :[], Sexp.new(:arglist, index))
366
+ match = Sexp.new(:call, target, :[], index)
365
367
 
366
368
  unless env[match]
367
369
  if request_value? target
@@ -383,7 +385,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
383
385
  value = exp[4] = process(exp[4])
384
386
  method = exp[2]
385
387
 
386
- match = Sexp.new(:call, target, method.to_s[0..-2].to_sym, Sexp.new(:arglist))
388
+ match = Sexp.new(:call, target, method.to_s[0..-2].to_sym)
387
389
 
388
390
  unless env[match]
389
391
  env[match] = value
@@ -392,8 +394,10 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
392
394
  exp
393
395
  end
394
396
 
397
+ #This is the right hand side value of a multiple assignment,
398
+ #like `x = y, z`
395
399
  def process_svalue exp
396
- exp[1]
400
+ exp.value
397
401
  end
398
402
 
399
403
  #Constant assignments like
@@ -423,9 +427,9 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
423
427
  if true? condition
424
428
  exps = [exp.then_clause]
425
429
  elsif false? condition
426
- exps = exp[3..-1]
430
+ exps = [exp.else_clause]
427
431
  else
428
- exps = exp[2..-1]
432
+ exps = [exp.then_clause, exp.else_clause]
429
433
  end
430
434
 
431
435
  was_inside = @inside_if
@@ -461,15 +465,9 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
461
465
  end
462
466
 
463
467
  #Process hash access by returning the value associated
464
- #with the given arguments.
465
- def process_hash_access target, args
466
- if args.length == 1
467
- index = args[0]
468
-
469
- hash_access(target, index)
470
- else
471
- nil
472
- end
468
+ #with the given argument.
469
+ def process_hash_access target, index
470
+ hash_access(target, index)
473
471
  end
474
472
 
475
473
  #Join two array literals into one.
@@ -482,8 +480,9 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
482
480
  #Join two string literals into one.
483
481
  def join_strings string1, string2
484
482
  result = Sexp.new(:str)
485
- result[1] = string1[1] + string2[1]
486
- if result[1].length > 50
483
+ result.value = string1.value + string2.value
484
+
485
+ if result.value.length > 50
487
486
  string1
488
487
  else
489
488
  result
@@ -492,18 +491,19 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
492
491
 
493
492
  #Returns a new SexpProcessor::Environment containing only instance variables.
494
493
  #This is useful, for example, when processing views.
495
- def only_ivars include_request_vars = false
494
+ def only_ivars include_request_vars = false, lenv = nil
495
+ lenv ||= env
496
496
  res = SexpProcessor::Environment.new
497
497
 
498
498
  if include_request_vars
499
- env.all.each do |k, v|
499
+ lenv.all.each do |k, v|
500
500
  #TODO Why would this have nil values?
501
501
  if (k.node_type == :ivar or request_value? k) and not v.nil?
502
502
  res[k] = v.dup
503
503
  end
504
504
  end
505
505
  else
506
- env.all.each do |k, v|
506
+ lenv.all.each do |k, v|
507
507
  #TODO Why would this have nil values?
508
508
  if k.node_type == :ivar and not v.nil?
509
509
  res[k] = v.dup
@@ -514,6 +514,117 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
514
514
  res
515
515
  end
516
516
 
517
+ def only_request_vars
518
+ res = SexpProcessor::Environment.new
519
+
520
+ env.all.each do |k, v|
521
+ if request_value? k and not v.nil?
522
+ res[k] = v.dup
523
+ end
524
+ end
525
+
526
+ res
527
+ end
528
+
529
+ def get_call_value call
530
+ method_name = call.method
531
+
532
+ #Look for helper methods and see if we can get a return value
533
+ if found_method = find_method(method_name, @current_class)
534
+ helper = found_method[:method]
535
+
536
+ if sexp? helper
537
+ value = process_helper_method helper, call.args
538
+ value.line(call.line)
539
+ return value
540
+ else
541
+ raise "Unexpected value for method: #{found_method}"
542
+ end
543
+ else
544
+ call
545
+ end
546
+ end
547
+
548
+ def process_helper_method method_exp, args
549
+ method_name = method_exp.method_name
550
+ Brakeman.debug "Processing method #{method_name}"
551
+
552
+ info = @helper_method_info[method_name]
553
+
554
+ #If method uses instance variables, then include those and request
555
+ #variables (params, etc) in the method environment. Otherwise,
556
+ #only include request variables.
557
+ if info[:uses_ivars]
558
+ meth_env = only_ivars(:include_request_vars)
559
+ else
560
+ meth_env = only_request_vars
561
+ end
562
+
563
+ #Add arguments to method environment
564
+ assign_args method_exp, args, meth_env
565
+
566
+
567
+ #Find return values if method does not depend on environment/args
568
+ values = @helper_method_cache[method_name]
569
+
570
+ unless values
571
+ #Serialize environment for cache key
572
+ meth_values = meth_env.instance_variable_get(:@env).to_a
573
+ meth_values.sort!
574
+ meth_values = meth_values.to_s
575
+
576
+ digest = Digest::SHA1.new.update(meth_values << method_name.to_s).to_s.to_sym
577
+
578
+ values = @helper_method_cache[digest]
579
+ end
580
+
581
+ if values
582
+ #Use values from cache
583
+ values[:ivar_values].each do |var, val|
584
+ env[var] = val
585
+ end
586
+
587
+ values[:return_value]
588
+ else
589
+ #Find return value for method
590
+ frv = Brakeman::FindReturnValue.new
591
+ value = frv.get_return_value(method_exp.body_list, meth_env)
592
+
593
+ ivars = {}
594
+
595
+ only_ivars(false, meth_env).all.each do |var, val|
596
+ env[var] = val
597
+ ivars[var] = val
598
+ end
599
+
600
+ if not frv.uses_ivars? and args.length == 0
601
+ #Store return value without ivars and args if they are not used
602
+ @helper_method_cache[method_exp.method_name] = { :return_value => value, :ivar_values => ivars }
603
+ else
604
+ @helper_method_cache[digest] = { :return_value => value, :ivar_values => ivars }
605
+ end
606
+
607
+ #Store information about method, just ivar usage for now
608
+ @helper_method_info[method_name] = { :uses_ivars => frv.uses_ivars? }
609
+
610
+ value
611
+ end
612
+ end
613
+
614
+ def assign_args method_exp, args, meth_env = SexpProcessor::Environment.new
615
+ formal_args = method_exp.formal_args
616
+
617
+ formal_args.each_with_index do |arg, index|
618
+ next if index == 0
619
+
620
+ if arg.is_a? Symbol and sexp? args[index - 1]
621
+ meth_env[Sexp.new(:lvar, arg)] = args[index - 1]
622
+ end
623
+ end
624
+
625
+ meth_env
626
+ end
627
+
517
628
  #Set line nunber for +exp+ and every Sexp it contains. Used when replacing
518
629
  #expressions, so warnings indicate the correct line.
519
630
  def set_line exp, line_number
@@ -530,8 +641,8 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
530
641
 
531
642
  #Finds the inner most call target which is not the target of a call to <<
532
643
  def find_push_target exp
533
- if call? exp and exp[2] == :<<
534
- find_push_target exp[1]
644
+ if call? exp and exp.method == :<<
645
+ find_push_target exp.target
535
646
  else
536
647
  exp
537
648
  end
@@ -544,4 +655,8 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
544
655
 
545
656
  false
546
657
  end
658
+
659
+ def find_method *args
660
+ nil
661
+ end
547
662
  end