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
@@ -31,7 +31,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
31
31
 
32
32
  CGI = Sexp.new(:const, :CGI)
33
33
 
34
- FORM_BUILDER = Sexp.new(:call, Sexp.new(:const, :FormBuilder), :new, Sexp.new(:arglist))
34
+ FORM_BUILDER = Sexp.new(:call, Sexp.new(:const, :FormBuilder), :new)
35
35
 
36
36
  #Run check
37
37
  def run_check
@@ -60,7 +60,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
60
60
 
61
61
  json_escape_on = false
62
62
  initializers = tracker.check_initializers :ActiveSupport, :escape_html_entities_in_json=
63
- initializers.each {|result| json_escape_on = true?(result[-1].first_arg) }
63
+ initializers.each {|result| json_escape_on = true?(result.call.first_arg) }
64
64
 
65
65
  if !json_escape_on or version_between? "0.0.0", "2.0.99"
66
66
  @known_dangerous << :to_json
@@ -115,7 +115,11 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
115
115
  :confidence => CONFIDENCE[:high]
116
116
 
117
117
  elsif not tracker.options[:ignore_model_output] and match = has_immediate_model?(out)
118
- method = match[2]
118
+ method = if call? match
119
+ match.method
120
+ else
121
+ nil
122
+ end
119
123
 
120
124
  unless IGNORE_MODEL_METHODS.include? method
121
125
  add_result out
@@ -227,7 +231,6 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
227
231
  end
228
232
 
229
233
  method = exp.method
230
- args = exp.arglist
231
234
 
232
235
  #Ignore safe items
233
236
  if (target.nil? and (@ignore_methods.include? method or method.to_s =~ IGNORE_LIKE)) or
@@ -241,14 +244,14 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
241
244
 
242
245
  #exp[0] = :ignore #should not be necessary
243
246
  @matched = false
244
- elsif sexp? target and model_name? target[1]
247
+ elsif sexp? target and model_name? target[1] #TODO: use method call?
245
248
  @matched = Match.new(:model, exp)
246
249
  elsif cookies? exp
247
250
  @matched = Match.new(:cookies, exp)
248
251
  elsif @inspect_arguments and params? exp
249
252
  @matched = Match.new(:params, exp)
250
253
  elsif @inspect_arguments
251
- process args
254
+ process_call_args exp
252
255
  end
253
256
  end
254
257
 
@@ -286,9 +289,8 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
286
289
 
287
290
  #Ignore condition in if Sexp
288
291
  def process_if exp
289
- exp[2..-1].each do |e|
290
- process e if sexp? e
291
- end
292
+ process exp.then_clause if sexp? exp.then_clause
293
+ process exp.else_clause if sexp? exp.else_clause
292
294
  exp
293
295
  end
294
296
 
@@ -20,7 +20,7 @@ class Brakeman::CheckEvaluation < Brakeman::BaseCheck
20
20
 
21
21
  #Warns if eval includes user input
22
22
  def process_result result
23
- if input = include_user_input?(result[:call][-1])
23
+ if input = include_user_input?(result[:call].arglist)
24
24
  warn :result => result,
25
25
  :warning_type => "Dangerous Eval",
26
26
  :message => "User input in eval",
@@ -30,12 +30,12 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
30
30
  #Processes results from Tracker#find_call.
31
31
  def process_result result
32
32
  call = result[:call]
33
-
34
- args = process call[3]
33
+ args = call.arglist
34
+ first_arg = call.first_arg
35
35
 
36
36
  case call.method
37
37
  when :system, :exec
38
- failure = include_user_input?(args[1]) || include_interp?(args[1])
38
+ failure = include_user_input?(first_arg) || include_interp?(first_arg)
39
39
  else
40
40
  failure = include_user_input?(args) || include_interp?(args)
41
41
  end
@@ -23,7 +23,7 @@ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
23
23
  @known_dangerous = []
24
24
  #Ideally, I think this should also check to see if people are setting
25
25
  #:escape => false
26
- methods = tracker.find_call :target => false, :method => :link_to
26
+ methods = tracker.find_call :target => false, :method => :link_to
27
27
 
28
28
  @models = tracker.models.keys
29
29
  @inspect_arguments = tracker.options[:check_arguments]
@@ -40,23 +40,24 @@ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
40
40
  #an ignored method call by the code above.
41
41
  call = result[:call] = result[:call].dup
42
42
 
43
- args = call.args
43
+ first_arg = call.first_arg
44
+ second_arg = call.second_arg
44
45
 
45
46
  @matched = false
46
47
 
47
48
  #Skip if no arguments(?) or first argument is a hash
48
- return if args.first.nil? or hash? args.first
49
+ return if first_arg.nil? or hash? first_arg
49
50
 
50
51
  if version_between? "2.0.0", "2.2.99"
51
- check_argument result, args.first
52
+ check_argument result, first_arg
52
53
 
53
- if args.second and not hash? args.second
54
- check_argument result, args.second
54
+ if second_arg and not hash? second_arg
55
+ check_argument result, second_arg
55
56
  end
56
- elsif args.second
57
+ elsif second_arg
57
58
  #Only check first argument if there is a second argument
58
59
  #in Rails 2.3.x
59
- check_argument result, args.first
60
+ check_argument result, first_arg
60
61
  end
61
62
  end
62
63
 
@@ -75,14 +76,14 @@ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
75
76
 
76
77
  add_result result
77
78
  warn :result => result,
78
- :warning_type => "Cross Site Scripting",
79
+ :warning_type => "Cross Site Scripting",
79
80
  :message => message,
80
81
  :user_input => input.match,
81
82
  :confidence => CONFIDENCE[:high],
82
83
  :link_path => "link_to"
83
84
 
84
85
  elsif not tracker.options[:ignore_model_output] and match = has_immediate_model?(arg)
85
- method = match[2]
86
+ method = match.method
86
87
 
87
88
  unless IGNORE_MODEL_METHODS.include? method
88
89
  add_result result
@@ -94,7 +95,7 @@ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
94
95
  end
95
96
 
96
97
  warn :result => result,
97
- :warning_type => "Cross Site Scripting",
98
+ :warning_type => "Cross Site Scripting",
98
99
  :message => "Unescaped model attribute in link_to",
99
100
  :user_input => match,
100
101
  :confidence => confidence,
@@ -111,8 +112,8 @@ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
111
112
  if message
112
113
  add_result result
113
114
 
114
- warn :result => result,
115
- :warning_type => "Cross Site Scripting",
115
+ warn :result => result,
116
+ :warning_type => "Cross Site Scripting",
116
117
  :message => message,
117
118
  :user_input => @matched.match,
118
119
  :confidence => CONFIDENCE[:med],
@@ -137,6 +138,7 @@ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
137
138
 
138
139
  #Bare records create links to the model resource,
139
140
  #not a string that could have injection
141
+ #TODO: Needs test? I think this is broken?
140
142
  if model_name? target and context == [:call, :arglist]
141
143
  return exp
142
144
  end
@@ -34,7 +34,7 @@ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
34
34
  #an ignored method call by the code above.
35
35
  call = result[:call] = result[:call].dup
36
36
  @matched = false
37
- url_arg = process call.args.second
37
+ url_arg = process call.second_arg
38
38
 
39
39
  #Ignore situations where the href is an interpolated string
40
40
  #with something before the user input
@@ -34,7 +34,7 @@ class Brakeman::CheckMailTo < Brakeman::BaseCheck
34
34
  Brakeman.debug "Checking calls to mail_to for javascript encoding"
35
35
 
36
36
  tracker.find_call(:target => false, :method => :mail_to).each do |result|
37
- result[:call].arglist.each do |arg|
37
+ result[:call].each_arg do |arg|
38
38
  if hash? arg
39
39
  if option = hash_access(arg, :encode)
40
40
  return result if symbol? option and option.value == :javascript
@@ -78,13 +78,14 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
78
78
 
79
79
  #Want to ignore calls to Model.new that have no arguments
80
80
  def check_call call
81
- args = process_all call.args
81
+ process_call_args call
82
+ first_arg = call.first_arg
82
83
 
83
- if args.empty? #empty new()
84
+ if first_arg.nil? #empty new()
84
85
  false
85
- elsif hash? args.first and not include_user_input? args.first
86
+ elsif hash? first_arg and not include_user_input? first_arg
86
87
  false
87
- elsif all_literals? args
88
+ elsif all_literal_args? call
88
89
  false
89
90
  else
90
91
  true
@@ -93,17 +94,30 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
93
94
 
94
95
  LITERALS = Set[:lit, :true, :false, :nil, :string]
95
96
 
96
- def all_literals? args
97
- args.all? do |arg|
98
- if sexp? arg
99
- if arg.node_type == :hash
100
- all_literals? arg
101
- else
102
- LITERALS.include? arg.node_type
103
- end
97
+ def all_literal_args? exp
98
+ if call? exp
99
+ exp.each_arg do |arg|
100
+ return false unless literal? arg
101
+ end
102
+
103
+ true
104
+ else
105
+ exp.all? do |arg|
106
+ literal? arg
107
+ end
108
+ end
109
+
110
+ end
111
+
112
+ def literal? exp
113
+ if sexp? exp
114
+ if exp.node_type == :hash
115
+ all_literal_args? exp
104
116
  else
105
- true
117
+ LITERALS.include? exp.node_type
106
118
  end
119
+ else
120
+ true
107
121
  end
108
122
  end
109
123
  end
@@ -73,12 +73,12 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
73
73
  elsif call? arg
74
74
  if request_value? arg
75
75
  return Match.new(immediate, arg)
76
- elsif request_value? arg[1]
77
- return Match.new(immediate, arg[1])
78
- elsif arg[2] == :url_for and include_user_input? arg
76
+ elsif request_value? arg.target
77
+ return Match.new(immediate, arg.target)
78
+ elsif arg.method == :url_for and include_user_input? arg
79
79
  return Match.new(immediate, arg)
80
80
  #Ignore helpers like some_model_url?
81
- elsif arg[2].to_s =~ /_(url|path)\z/
81
+ elsif arg.method.to_s =~ /_(url|path)\z/
82
82
  return false
83
83
  end
84
84
  elsif request_value? arg
@@ -38,7 +38,7 @@ class Brakeman::CheckSelectTag < Brakeman::BaseCheck
38
38
  add_result result
39
39
 
40
40
  #Only concerned if user input is supplied for :prompt option
41
- last_arg = result[:call].arglist.last
41
+ last_arg = result[:call].last_arg
42
42
 
43
43
  if hash? last_arg
44
44
  prompt_option = hash_access last_arg, :prompt
@@ -35,7 +35,7 @@ class Brakeman::CheckSelectVulnerability < Brakeman::BaseCheck
35
35
  def process_result result
36
36
  return if duplicate? result
37
37
 
38
- third_arg = result[:call].args[2]
38
+ third_arg = result[:call].third_arg
39
39
 
40
40
  #Check for user input in options parameter
41
41
  if sexp? third_arg and include_user_input? third_arg
@@ -16,10 +16,10 @@ class Brakeman::CheckSend < Brakeman::BaseCheck
16
16
  end
17
17
 
18
18
  def process_result result
19
- args = process_all result[:call].args
19
+ process_call_args result[:call]
20
20
  target = process result[:call].target
21
21
 
22
- if input = has_immediate_user_input?(args.first)
22
+ if input = has_immediate_user_input?(result[:call].first_arg)
23
23
  warn :result => result,
24
24
  :warning_type => "Dangerous Send",
25
25
  :message => "User controlled method execution",
@@ -9,10 +9,10 @@ class Brakeman::CheckSessionSettings < Brakeman::BaseCheck
9
9
  def initialize *args
10
10
  super
11
11
 
12
- if tracker.options[:rails3]
13
- @session_settings = Sexp.new(:call, Sexp.new(:colon2, Sexp.new(:const, :Rails3), :Application), :config, Sexp.new(:arglist))
14
- else
12
+ unless tracker.options[:rails3]
15
13
  @session_settings = Sexp.new(:colon2, Sexp.new(:const, :ActionController), :Base)
14
+ else
15
+ @session_settings = nil
16
16
  end
17
17
  end
18
18
 
@@ -41,8 +41,8 @@ class Brakeman::CheckSessionSettings < Brakeman::BaseCheck
41
41
  #Looks for Rails3::Application.config.session_store :cookie_store, { ... }
42
42
  #in Rails 3.x apps
43
43
  def process_call exp
44
- if tracker.options[:rails3] and exp.target == @session_settings and exp.method == :session_store
45
- check_for_issues exp.args.second, "#{tracker.options[:app_path]}/config/initializers/session_store.rb"
44
+ if tracker.options[:rails3] and settings_target?(exp.target) and exp.method == :session_store
45
+ check_for_issues exp.second_arg, "#{tracker.options[:app_path]}/config/initializers/session_store.rb"
46
46
  end
47
47
 
48
48
  exp
@@ -50,6 +50,13 @@ class Brakeman::CheckSessionSettings < Brakeman::BaseCheck
50
50
 
51
51
  private
52
52
 
53
+ def settings_target? exp
54
+ call? exp and
55
+ exp.method == :config and
56
+ node_type? exp.target, :colon2 and
57
+ exp.target.rhs == :Application
58
+ end
59
+
53
60
  def check_for_issues settings, file
54
61
  if settings and hash? settings
55
62
  if value = hash_access(settings, :session_http_only)
@@ -52,7 +52,7 @@ class Brakeman::CheckSingleQuotes < Brakeman::BaseCheck
52
52
  def process_class exp
53
53
  if exp.class_name == :ERB
54
54
  @inside_erb = true
55
- process exp.body
55
+ process_all exp.body
56
56
  @inside_erb = false
57
57
  end
58
58
 
@@ -65,7 +65,7 @@ class Brakeman::CheckSingleQuotes < Brakeman::BaseCheck
65
65
  def process_module exp
66
66
  if @inside_erb and exp.module_name == :Util
67
67
  @inside_util = true
68
- process exp.body
68
+ process_all exp.body
69
69
  @inside_util = false
70
70
  end
71
71
 
@@ -78,7 +78,7 @@ class Brakeman::CheckSingleQuotes < Brakeman::BaseCheck
78
78
  def process_defn exp
79
79
  if @inside_util and exp.method_name == :html_escape
80
80
  @inside_html_escape = true
81
- process exp.body
81
+ process_all exp.body
82
82
  @inside_html_escape = false
83
83
  end
84
84
 
@@ -35,10 +35,11 @@ class Brakeman::CheckSkipBeforeFilter < Brakeman::BaseCheck
35
35
  def skip_verify_except? filter
36
36
  return false unless call? filter
37
37
 
38
- args = filter.args
38
+ first_arg = filter.first_arg
39
+ last_arg = filter.last_arg
39
40
 
40
- if symbol? args.first and args.first.value == :verify_authenticity_token and hash? args.last
41
- if hash_access(args.last, :except)
41
+ if symbol? first_arg and first_arg.value == :verify_authenticity_token and hash? last_arg
42
+ if hash_access(last_arg, :except)
42
43
  return true
43
44
  end
44
45
  end
@@ -61,7 +61,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
61
61
  active_record_models.each do |name, model|
62
62
  if model[:options][:named_scope]
63
63
  model[:options][:named_scope].each do |args|
64
- call = Sexp.new(:call, nil, :named_scope, args).line(args.line)
64
+ call = make_call(nil, :named_scope, args).line(args.line)
65
65
  scope_calls << { :call => call, :location => [:class, name ], :method => :named_scope }
66
66
  end
67
67
  end
@@ -80,7 +80,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
80
80
  call = second_arg
81
81
  scope_calls << { :call => call, :location => [:class, name ], :method => call.method }
82
82
  else
83
- call = Sexp.new(:call, nil, :scope, args).line(args.line)
83
+ call = make_call(nil, :scope, args).line(args.line)
84
84
  scope_calls << { :call => call, :location => [:class, name ], :method => :scope }
85
85
  end
86
86
  end
@@ -173,37 +173,36 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
173
173
 
174
174
  call = result[:call]
175
175
  method = call.method
176
- args = call.args
177
176
 
178
177
  dangerous_value = case method
179
178
  when :find
180
- check_find_arguments args.second
179
+ check_find_arguments call.second_arg
181
180
  when :exists?
182
- check_find_arguments args.first
181
+ check_find_arguments call.first_arg
183
182
  when :named_scope, :scope
184
- check_scope_arguments call.arglist
183
+ check_scope_arguments call
185
184
  when :find_by_sql, :count_by_sql
186
- check_by_sql_arguments args.first
185
+ check_by_sql_arguments call.first_arg
187
186
  when :calculate
188
- check_find_arguments args[2]
187
+ check_find_arguments call.third_arg
189
188
  when :last, :first, :all
190
- check_find_arguments args.first
189
+ check_find_arguments call.first_arg
191
190
  when :average, :count, :maximum, :minimum, :sum
192
- if args.length > 2
193
- unsafe_sql?(args.first) or check_find_arguments(args.last)
191
+ if call.length > 5
192
+ unsafe_sql?(call.first_arg) or check_find_arguments(call.last_arg)
194
193
  else
195
- check_find_arguments args.last
194
+ check_find_arguments call.last_arg
196
195
  end
197
196
  when :where, :having
198
197
  check_query_arguments call.arglist
199
198
  when :order, :group, :reorder
200
199
  check_order_arguments call.arglist
201
200
  when :joins
202
- check_joins_arguments args.first
201
+ check_joins_arguments call.first_arg
203
202
  when :from, :select
204
- unsafe_sql? args.first
203
+ unsafe_sql? call.first_arg
205
204
  when :lock
206
- check_lock_arguments args.first
205
+ check_lock_arguments call.first_arg
207
206
  else
208
207
  Brakeman.debug "Unhandled SQL method: #{method}"
209
208
  end
@@ -226,8 +225,8 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
226
225
  :confidence => confidence
227
226
  end
228
227
 
229
- if check_for_limit_or_offset_vulnerability args[-1]
230
- if include_user_input? args[-1]
228
+ if check_for_limit_or_offset_vulnerability call.last_arg
229
+ if include_user_input? call.last_arg
231
230
  confidence = CONFIDENCE[:high]
232
231
  else
233
232
  confidence = CONFIDENCE[:low]
@@ -259,25 +258,26 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
259
258
  unsafe_sql? arg
260
259
  end
261
260
 
262
- def check_scope_arguments args
263
- return unless node_type? args, :arglist
261
+ def check_scope_arguments call
262
+ scope_arg = call.second_arg #first arg is name of scope
264
263
 
265
- if node_type? args[2], :iter
266
- unsafe_sql? args[2][-1]
264
+ if node_type? scope_arg, :iter
265
+ unsafe_sql? scope_arg.block
267
266
  else
268
- unsafe_sql? args[2]
267
+ unsafe_sql? scope_arg
269
268
  end
270
269
  end
271
270
 
272
271
  def check_query_arguments arg
273
272
  return unless sexp? arg
273
+ first_arg = arg[1]
274
274
 
275
275
  if node_type? arg, :arglist
276
- if arg.length > 2 and node_type? arg[1], :string_interp, :dstr
276
+ if arg.length > 2 and node_type? first_arg, :string_interp, :dstr
277
277
  # Model.where("blah = ?", blah)
278
- return check_string_interp arg[1]
278
+ return check_string_interp first_arg
279
279
  else
280
- arg = arg[1]
280
+ arg = first_arg
281
281
  end
282
282
  end
283
283
 
@@ -319,7 +319,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
319
319
  def check_by_sql_arguments arg
320
320
  return unless sexp? arg
321
321
 
322
- #This is kind of necessary, because unsafe_sql? will handle an array
322
+ #This is kind of unnecessary, because unsafe_sql? will handle an array
323
323
  #correctly, but might be better to be explicit.
324
324
  if array? arg
325
325
  unsafe_sql? arg[1]
@@ -457,7 +457,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
457
457
  def check_hash_values exp
458
458
  hash_iterate(exp) do |key, value|
459
459
  if symbol? key
460
- unsafe = case key[1]
460
+ unsafe = case key.value
461
461
  when :conditions, :having, :select
462
462
  check_query_arguments value
463
463
  when :order, :group
@@ -486,9 +486,8 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
486
486
 
487
487
  target = exp.target
488
488
  method = exp.method
489
- args = exp.args
490
489
 
491
- if string? target or string? args.first
490
+ if string? target or string? exp.first_arg
492
491
  if STRING_METHODS.include? method
493
492
  return exp
494
493
  end
@@ -500,7 +499,8 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
500
499
  IGNORE_METHODS_IN_SQL = Set[:id, :merge_conditions, :table_name, :to_i, :to_f,
501
500
  :sanitize_sql, :sanitize_sql_array, :sanitize_sql_for_assignment,
502
501
  :sanitize_sql_for_conditions, :sanitize_sql_hash,
503
- :sanitize_sql_hash_for_assignment, :sanitize_sql_hash_for_conditions]
502
+ :sanitize_sql_hash_for_assignment, :sanitize_sql_hash_for_conditions,
503
+ :to_sql]
504
504
 
505
505
  def safe_value? exp
506
506
  return true unless sexp? exp