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.
- data/README.md +3 -27
- data/lib/brakeman.rb +36 -38
- data/lib/brakeman/app_tree.rb +90 -0
- data/lib/brakeman/call_index.rb +5 -38
- data/lib/brakeman/checks.rb +11 -11
- data/lib/brakeman/checks/base_check.rb +53 -29
- data/lib/brakeman/checks/check_cross_site_scripting.rb +11 -9
- data/lib/brakeman/checks/check_evaluation.rb +1 -1
- data/lib/brakeman/checks/check_execute.rb +3 -3
- data/lib/brakeman/checks/check_link_to.rb +15 -13
- data/lib/brakeman/checks/check_link_to_href.rb +1 -1
- data/lib/brakeman/checks/check_mail_to.rb +1 -1
- data/lib/brakeman/checks/check_mass_assignment.rb +27 -13
- data/lib/brakeman/checks/check_redirect.rb +4 -4
- data/lib/brakeman/checks/check_select_tag.rb +1 -1
- data/lib/brakeman/checks/check_select_vulnerability.rb +1 -1
- data/lib/brakeman/checks/check_send.rb +2 -2
- data/lib/brakeman/checks/check_session_settings.rb +12 -5
- data/lib/brakeman/checks/check_single_quotes.rb +3 -3
- data/lib/brakeman/checks/check_skip_before_filter.rb +4 -3
- data/lib/brakeman/checks/check_sql.rb +30 -30
- data/lib/brakeman/checks/check_translate_bug.rb +11 -10
- data/lib/brakeman/checks/check_validation_regex.rb +36 -11
- data/lib/brakeman/checks/check_without_protection.rb +1 -1
- data/lib/brakeman/options.rb +6 -2
- data/lib/brakeman/processor.rb +6 -5
- data/lib/brakeman/processors/alias_processor.rb +153 -38
- data/lib/brakeman/processors/base_processor.rb +16 -21
- data/lib/brakeman/processors/controller_alias_processor.rb +24 -11
- data/lib/brakeman/processors/controller_processor.rb +25 -25
- data/lib/brakeman/processors/erb_template_processor.rb +6 -7
- data/lib/brakeman/processors/erubis_template_processor.rb +2 -3
- data/lib/brakeman/processors/gem_processor.rb +5 -4
- data/lib/brakeman/processors/haml_template_processor.rb +4 -6
- data/lib/brakeman/processors/lib/find_all_calls.rb +3 -3
- data/lib/brakeman/processors/lib/find_call.rb +2 -2
- data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
- data/lib/brakeman/processors/lib/processor_helper.rb +24 -2
- data/lib/brakeman/processors/lib/rails2_config_processor.rb +13 -14
- data/lib/brakeman/processors/lib/rails2_route_processor.rb +9 -4
- data/lib/brakeman/processors/lib/rails3_config_processor.rb +8 -8
- data/lib/brakeman/processors/lib/rails3_route_processor.rb +23 -21
- data/lib/brakeman/processors/lib/render_helper.rb +2 -2
- data/lib/brakeman/processors/library_processor.rb +2 -2
- data/lib/brakeman/processors/model_processor.rb +16 -12
- data/lib/brakeman/processors/output_processor.rb +2 -1
- data/lib/brakeman/processors/template_alias_processor.rb +12 -8
- data/lib/brakeman/report.rb +28 -14
- data/lib/brakeman/rescanner.rb +5 -5
- data/lib/brakeman/scanner.rb +56 -94
- data/lib/brakeman/templates/header.html.erb +7 -2
- data/lib/brakeman/tracker.rb +14 -4
- data/lib/brakeman/util.rb +38 -17
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +14 -6
- data/lib/ruby_parser/bm_sexp.rb +157 -57
- data/lib/ruby_parser/bm_sexp_processor.rb +1 -2
- metadata +26 -25
- data/lib/ruby_parser/ruby18_parser.rb +0 -5544
- data/lib/ruby_parser/ruby19_parser.rb +0 -5756
- data/lib/ruby_parser/ruby_lexer.rb +0 -1349
- data/lib/ruby_parser/ruby_parser.rb +0 -5
- 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
|
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
|
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
|
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
|
-
|
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
|
290
|
-
|
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]
|
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
|
-
|
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?(
|
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
|
-
|
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
|
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,
|
52
|
+
check_argument result, first_arg
|
52
53
|
|
53
|
-
if
|
54
|
-
check_argument result,
|
54
|
+
if second_arg and not hash? second_arg
|
55
|
+
check_argument result, second_arg
|
55
56
|
end
|
56
|
-
elsif
|
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,
|
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
|
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.
|
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].
|
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
|
-
|
81
|
+
process_call_args call
|
82
|
+
first_arg = call.first_arg
|
82
83
|
|
83
|
-
if
|
84
|
+
if first_arg.nil? #empty new()
|
84
85
|
false
|
85
|
-
elsif hash?
|
86
|
+
elsif hash? first_arg and not include_user_input? first_arg
|
86
87
|
false
|
87
|
-
elsif
|
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
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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
|
-
|
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
|
77
|
-
return Match.new(immediate, arg
|
78
|
-
elsif 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
|
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].
|
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].
|
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
|
-
|
19
|
+
process_call_args result[:call]
|
20
20
|
target = process result[:call].target
|
21
21
|
|
22
|
-
if input = has_immediate_user_input?(
|
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
|
-
|
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
|
45
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
38
|
+
first_arg = filter.first_arg
|
39
|
+
last_arg = filter.last_arg
|
39
40
|
|
40
|
-
if symbol?
|
41
|
-
if hash_access(
|
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 =
|
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 =
|
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
|
179
|
+
check_find_arguments call.second_arg
|
181
180
|
when :exists?
|
182
|
-
check_find_arguments
|
181
|
+
check_find_arguments call.first_arg
|
183
182
|
when :named_scope, :scope
|
184
|
-
check_scope_arguments call
|
183
|
+
check_scope_arguments call
|
185
184
|
when :find_by_sql, :count_by_sql
|
186
|
-
check_by_sql_arguments
|
185
|
+
check_by_sql_arguments call.first_arg
|
187
186
|
when :calculate
|
188
|
-
check_find_arguments
|
187
|
+
check_find_arguments call.third_arg
|
189
188
|
when :last, :first, :all
|
190
|
-
check_find_arguments
|
189
|
+
check_find_arguments call.first_arg
|
191
190
|
when :average, :count, :maximum, :minimum, :sum
|
192
|
-
if
|
193
|
-
unsafe_sql?(
|
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
|
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
|
201
|
+
check_joins_arguments call.first_arg
|
203
202
|
when :from, :select
|
204
|
-
unsafe_sql?
|
203
|
+
unsafe_sql? call.first_arg
|
205
204
|
when :lock
|
206
|
-
check_lock_arguments
|
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
|
230
|
-
if include_user_input?
|
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
|
263
|
-
|
261
|
+
def check_scope_arguments call
|
262
|
+
scope_arg = call.second_arg #first arg is name of scope
|
264
263
|
|
265
|
-
if node_type?
|
266
|
-
unsafe_sql?
|
264
|
+
if node_type? scope_arg, :iter
|
265
|
+
unsafe_sql? scope_arg.block
|
267
266
|
else
|
268
|
-
unsafe_sql?
|
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?
|
276
|
+
if arg.length > 2 and node_type? first_arg, :string_interp, :dstr
|
277
277
|
# Model.where("blah = ?", blah)
|
278
|
-
return check_string_interp
|
278
|
+
return check_string_interp first_arg
|
279
279
|
else
|
280
|
-
arg =
|
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
|
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
|
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?
|
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
|