brakeman 1.8.3 → 1.9.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.
- 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
|