brakeman 1.7.1 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/brakeman +3 -0
- data/lib/brakeman.rb +2 -0
- data/lib/brakeman/brakeman.rake +4 -3
- data/lib/brakeman/checks/base_check.rb +40 -37
- data/lib/brakeman/checks/check_basic_auth.rb +3 -3
- data/lib/brakeman/checks/check_content_tag.rb +179 -0
- data/lib/brakeman/checks/check_cross_site_scripting.rb +41 -17
- data/lib/brakeman/checks/check_execute.rb +1 -1
- data/lib/brakeman/checks/check_file_access.rb +2 -2
- data/lib/brakeman/checks/check_link_to.rb +9 -7
- 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 +6 -5
- data/lib/brakeman/checks/check_redirect.rb +18 -17
- data/lib/brakeman/checks/check_render.rb +3 -1
- data/lib/brakeman/checks/check_select_tag.rb +2 -2
- data/lib/brakeman/checks/check_select_vulnerability.rb +3 -3
- data/lib/brakeman/checks/check_send.rb +3 -3
- data/lib/brakeman/checks/check_session_settings.rb +5 -5
- data/lib/brakeman/checks/check_single_quotes.rb +8 -8
- data/lib/brakeman/checks/check_skip_before_filter.rb +2 -2
- data/lib/brakeman/checks/check_sql.rb +36 -39
- data/lib/brakeman/checks/check_validation_regex.rb +3 -3
- data/lib/brakeman/checks/check_without_protection.rb +2 -2
- data/lib/brakeman/format/style.css +15 -0
- data/lib/brakeman/options.rb +4 -0
- data/lib/brakeman/processor.rb +1 -1
- data/lib/brakeman/processors/alias_processor.rb +63 -61
- data/lib/brakeman/processors/base_processor.rb +31 -45
- data/lib/brakeman/processors/controller_alias_processor.rb +11 -9
- data/lib/brakeman/processors/controller_processor.rb +26 -25
- data/lib/brakeman/processors/erb_template_processor.rb +12 -12
- data/lib/brakeman/processors/erubis_template_processor.rb +19 -17
- data/lib/brakeman/processors/gem_processor.rb +5 -5
- data/lib/brakeman/processors/haml_template_processor.rb +16 -12
- data/lib/brakeman/processors/lib/find_all_calls.rb +11 -17
- data/lib/brakeman/processors/lib/find_call.rb +16 -23
- data/lib/brakeman/processors/lib/processor_helper.rb +11 -5
- data/lib/brakeman/processors/lib/rails2_config_processor.rb +21 -20
- data/lib/brakeman/processors/lib/rails2_route_processor.rb +38 -34
- data/lib/brakeman/processors/lib/rails3_config_processor.rb +17 -17
- data/lib/brakeman/processors/lib/rails3_route_processor.rb +42 -40
- data/lib/brakeman/processors/lib/render_helper.rb +6 -6
- data/lib/brakeman/processors/lib/route_helper.rb +1 -1
- data/lib/brakeman/processors/library_processor.rb +11 -11
- data/lib/brakeman/processors/model_processor.rb +18 -16
- data/lib/brakeman/processors/template_alias_processor.rb +36 -29
- data/lib/brakeman/processors/template_processor.rb +4 -4
- data/lib/brakeman/report.rb +23 -4
- data/lib/brakeman/templates/error_overview.html.erb +9 -1
- data/lib/brakeman/templates/view_warnings.html.erb +16 -3
- data/lib/brakeman/tracker.rb +3 -0
- data/lib/brakeman/util.rb +5 -1
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +1 -1
- data/lib/ruby_parser/bm_sexp.rb +302 -2
- metadata +6 -5
data/bin/brakeman
CHANGED
@@ -55,6 +55,9 @@ end
|
|
55
55
|
if options[:previous_results_json]
|
56
56
|
vulns = Brakeman.compare options.merge(:quiet => options[:quiet])
|
57
57
|
puts JSON.pretty_generate(vulns)
|
58
|
+
if options[:exit_on_warn] and (vulns[:new].count + vulns[:fixed].count > 0)
|
59
|
+
exit Brakeman::Warnings_Found_Exit_Code
|
60
|
+
end
|
58
61
|
else
|
59
62
|
#Run scan and output a report
|
60
63
|
tracker = Brakeman.run options.merge(:print_report => true, :quiet => options[:quiet])
|
data/lib/brakeman.rb
CHANGED
@@ -39,6 +39,7 @@ module Brakeman
|
|
39
39
|
# * :safe_methods - array of methods to consider safe
|
40
40
|
# * :skip_libs - do not process lib/ directory (default: false)
|
41
41
|
# * :skip_checks - checks not to run (run all if not specified)
|
42
|
+
# * :relative_path - show relative path of each file(default: false)
|
42
43
|
# * :summary_only - only output summary section of report
|
43
44
|
# (does not apply to tabs format)
|
44
45
|
#
|
@@ -119,6 +120,7 @@ module Brakeman
|
|
119
120
|
:ignore_model_output => false,
|
120
121
|
:message_limit => 100,
|
121
122
|
:parallel_checks => true,
|
123
|
+
:relative_path => false,
|
122
124
|
:quiet => true,
|
123
125
|
:report_progress => true,
|
124
126
|
:html_style => "#{File.expand_path(File.dirname(__FILE__))}/brakeman/format/style.css"
|
data/lib/brakeman/brakeman.rake
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
namespace :brakeman do
|
2
2
|
|
3
3
|
desc "Run Brakeman"
|
4
|
-
task :run, :
|
4
|
+
task :run, :output_files do |t, args|
|
5
5
|
require 'brakeman'
|
6
|
-
|
7
|
-
|
6
|
+
|
7
|
+
files = args[:output_files].split(' ') if args[:output_files]
|
8
|
+
Brakeman.run :app_path => ".", :output_files => files, :print_report => true
|
8
9
|
end
|
9
10
|
end
|
@@ -58,16 +58,18 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
58
58
|
|
59
59
|
#Process calls and check if they include user input
|
60
60
|
def process_call exp
|
61
|
-
process exp
|
62
|
-
|
61
|
+
process exp.target if sexp? exp.target
|
62
|
+
process_all exp.args
|
63
63
|
|
64
|
-
|
64
|
+
target = exp.target
|
65
|
+
|
66
|
+
if params? target
|
65
67
|
@has_user_input = Match.new(:params, exp)
|
66
|
-
elsif cookies?
|
68
|
+
elsif cookies? target
|
67
69
|
@has_user_input = Match.new(:cookies, exp)
|
68
|
-
elsif request_env?
|
70
|
+
elsif request_env? target
|
69
71
|
@has_user_input = Match.new(:request, exp)
|
70
|
-
elsif sexp?
|
72
|
+
elsif sexp? target and model_name? target[1]
|
71
73
|
@has_user_input = Match.new(:model, exp)
|
72
74
|
end
|
73
75
|
|
@@ -77,11 +79,11 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
77
79
|
def process_if exp
|
78
80
|
#This is to ignore user input in condition
|
79
81
|
current_user_input = @has_user_input
|
80
|
-
process exp
|
82
|
+
process exp.condition
|
81
83
|
@has_user_input = current_user_input
|
82
84
|
|
83
|
-
process exp
|
84
|
-
process exp
|
85
|
+
process exp.then_clause if sexp? exp.then_clause
|
86
|
+
process exp.else_clause if sexp? exp.else_clause
|
85
87
|
|
86
88
|
exp
|
87
89
|
end
|
@@ -258,11 +260,11 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
258
260
|
elsif cookies? exp
|
259
261
|
return Match.new(:cookies, exp)
|
260
262
|
elsif call? exp
|
261
|
-
if params? exp
|
263
|
+
if params? exp.target
|
262
264
|
return Match.new(:params, exp)
|
263
|
-
elsif cookies? exp
|
265
|
+
elsif cookies? exp.target
|
264
266
|
return Match.new(:cookies, exp)
|
265
|
-
elsif request_env? exp
|
267
|
+
elsif request_env? exp.target
|
266
268
|
return Match.new(:request, exp)
|
267
269
|
else
|
268
270
|
false
|
@@ -278,27 +280,25 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
278
280
|
end
|
279
281
|
false
|
280
282
|
when :string_eval
|
281
|
-
if sexp? exp
|
282
|
-
if exp
|
283
|
-
exp
|
284
|
-
|
285
|
-
|
286
|
-
return match if match
|
287
|
-
end
|
283
|
+
if sexp? exp.value
|
284
|
+
if exp.value.node_type == :rlist
|
285
|
+
exp.value.each_sexp do |e|
|
286
|
+
match = has_immediate_user_input?(e)
|
287
|
+
return match if match
|
288
288
|
end
|
289
289
|
false
|
290
290
|
else
|
291
|
-
has_immediate_user_input? exp
|
291
|
+
has_immediate_user_input? exp.value
|
292
292
|
end
|
293
293
|
end
|
294
294
|
when :format
|
295
|
-
has_immediate_user_input? exp
|
295
|
+
has_immediate_user_input? exp.value
|
296
296
|
when :if
|
297
|
-
(sexp? exp
|
298
|
-
(sexp? exp
|
297
|
+
(sexp? exp.then_clause and has_immediate_user_input? exp.then_clause) or
|
298
|
+
(sexp? exp.else_clause and has_immediate_user_input? exp.else_clause)
|
299
299
|
when :or
|
300
|
-
has_immediate_user_input? exp
|
301
|
-
has_immediate_user_input? exp
|
300
|
+
has_immediate_user_input? exp.lhs or
|
301
|
+
has_immediate_user_input? exp.rhs
|
302
302
|
else
|
303
303
|
false
|
304
304
|
end
|
@@ -311,12 +311,12 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
311
311
|
out = exp if out.nil?
|
312
312
|
|
313
313
|
if sexp? exp and exp.node_type == :output
|
314
|
-
exp = exp
|
314
|
+
exp = exp.value
|
315
315
|
end
|
316
316
|
|
317
317
|
if call? exp
|
318
|
-
target = exp
|
319
|
-
method = exp
|
318
|
+
target = exp.target
|
319
|
+
method = exp.method
|
320
320
|
|
321
321
|
if call? target and not method.to_s[-1,1] == "?"
|
322
322
|
has_immediate_model? target, out
|
@@ -335,23 +335,26 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
335
335
|
end
|
336
336
|
false
|
337
337
|
when :string_eval
|
338
|
-
if sexp? exp
|
339
|
-
if exp
|
340
|
-
exp
|
341
|
-
if
|
338
|
+
if sexp? exp.value
|
339
|
+
if exp.value.node_type == :rlist
|
340
|
+
exp.value.each_sexp do |e|
|
341
|
+
if match = has_immediate_model?(e, out)
|
342
342
|
return match
|
343
343
|
end
|
344
344
|
end
|
345
345
|
false
|
346
346
|
else
|
347
|
-
has_immediate_model? exp
|
347
|
+
has_immediate_model? exp.value, out
|
348
348
|
end
|
349
349
|
end
|
350
350
|
when :format
|
351
|
-
has_immediate_model? exp
|
351
|
+
has_immediate_model? exp.value, out
|
352
352
|
when :if
|
353
|
-
((sexp? exp
|
354
|
-
(sexp? exp
|
353
|
+
((sexp? exp.then_clause and has_immediate_model? exp.then_clause, out) or
|
354
|
+
(sexp? exp.else_clause and has_immediate_model? exp.else_clause, out))
|
355
|
+
when :or
|
356
|
+
has_immediate_model? exp.lhs or
|
357
|
+
has_immediate_model? exp.rhs
|
355
358
|
else
|
356
359
|
false
|
357
360
|
end
|
@@ -387,7 +390,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
387
390
|
|
388
391
|
case exp.node_type
|
389
392
|
when :output, :format
|
390
|
-
find_chain exp
|
393
|
+
find_chain exp.value, target
|
391
394
|
when :call
|
392
395
|
if exp == target or include_target? exp, target
|
393
396
|
return exp
|
@@ -33,10 +33,10 @@ class Brakeman::CheckBasicAuth < Brakeman::BaseCheck
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def get_password call
|
36
|
-
|
36
|
+
arg = call.first_arg
|
37
37
|
|
38
|
-
return false if
|
38
|
+
return false if arg.nil? or not hash? arg
|
39
39
|
|
40
|
-
hash_access(
|
40
|
+
hash_access(arg, :password)
|
41
41
|
end
|
42
42
|
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'brakeman/checks/check_cross_site_scripting'
|
2
|
+
|
3
|
+
#Checks for unescaped values in `content_tag`
|
4
|
+
#
|
5
|
+
# content_tag :tag, body
|
6
|
+
# ^-- Unescaped in Rails 2.x
|
7
|
+
#
|
8
|
+
# content_tag, :tag, body, attribute => value
|
9
|
+
# ^-- Unescaped in all versions
|
10
|
+
#
|
11
|
+
# content_tag, :tag, body, attribute => value
|
12
|
+
# ^
|
13
|
+
# |
|
14
|
+
# Escaped by default, can be explicitly escaped
|
15
|
+
# or not by passing in (true|false) as fourth argument
|
16
|
+
class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
|
17
|
+
Brakeman::Checks.add self
|
18
|
+
|
19
|
+
@description = "Checks for XSS in calls to content_tag"
|
20
|
+
|
21
|
+
def run_check
|
22
|
+
@ignore_methods = Set[:button_to, :check_box, :escapeHTML, :escape_once,
|
23
|
+
:field_field, :fields_for, :h, :hidden_field,
|
24
|
+
:hidden_field, :hidden_field_tag, :image_tag, :label,
|
25
|
+
:mail_to, :radio_button, :select,
|
26
|
+
:submit_tag, :text_area, :text_field,
|
27
|
+
:text_field_tag, :url_encode, :url_for,
|
28
|
+
:will_paginate].merge tracker.options[:safe_methods]
|
29
|
+
|
30
|
+
@known_dangerous = []
|
31
|
+
methods = tracker.find_call :target => false, :method => :content_tag
|
32
|
+
|
33
|
+
@models = tracker.models.keys
|
34
|
+
@inspect_arguments = tracker.options[:check_arguments]
|
35
|
+
|
36
|
+
Brakeman.debug "Checking for XSS in content_tag"
|
37
|
+
methods.each do |call|
|
38
|
+
process_result call
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def process_result result
|
43
|
+
return if duplicate? result
|
44
|
+
|
45
|
+
call = result[:call] = result[:call].dup
|
46
|
+
|
47
|
+
args = call.arglist
|
48
|
+
|
49
|
+
tag_name = args[1]
|
50
|
+
content = args[2]
|
51
|
+
attributes = args[3]
|
52
|
+
escape_attr = args[4]
|
53
|
+
|
54
|
+
@matched = false
|
55
|
+
|
56
|
+
#Silly, but still dangerous if someone uses user input in the tag type
|
57
|
+
check_argument result, tag_name
|
58
|
+
|
59
|
+
#Versions before 3.x do not escape body of tag, nor does the rails_xss gem
|
60
|
+
unless @matched or (tracker.options[:rails3] and not raw? content)
|
61
|
+
check_argument result, content
|
62
|
+
end
|
63
|
+
|
64
|
+
#Attribute keys are never escaped, so check them for user input
|
65
|
+
if not @matched and hash? attributes and not request_value? attributes
|
66
|
+
hash_iterate(attributes) do |k, v|
|
67
|
+
check_argument result, k
|
68
|
+
return if @matched
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
#By default, content_tag escapes attribute values passed in as a hash.
|
73
|
+
#But this behavior can be disabled. So only check attributes hash
|
74
|
+
#if they are explicitly not escaped.
|
75
|
+
if not @matched and attributes and false? escape_attr
|
76
|
+
if request_value? attributes or not hash? attributes
|
77
|
+
check_argument result, attributes
|
78
|
+
else #check hash values
|
79
|
+
hash_iterate(attributes) do |k, v|
|
80
|
+
check_argument result, v
|
81
|
+
return if @matched
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def check_argument result, exp
|
88
|
+
#Check contents of raw() calls directly
|
89
|
+
if call? exp and exp.method == :raw
|
90
|
+
arg = process exp.first_arg
|
91
|
+
else
|
92
|
+
arg = process exp
|
93
|
+
end
|
94
|
+
|
95
|
+
if input = has_immediate_user_input?(arg)
|
96
|
+
case input.type
|
97
|
+
when :params
|
98
|
+
message = "Unescaped parameter value in content_tag"
|
99
|
+
when :cookies
|
100
|
+
message = "Unescaped cookie value in content_tag"
|
101
|
+
else
|
102
|
+
message = "Unescaped user input value in content_tag"
|
103
|
+
end
|
104
|
+
|
105
|
+
add_result result
|
106
|
+
|
107
|
+
warn :result => result,
|
108
|
+
:warning_type => "Cross Site Scripting",
|
109
|
+
:message => message,
|
110
|
+
:user_input => input.match,
|
111
|
+
:confidence => CONFIDENCE[:high],
|
112
|
+
:link_path => "content_tag"
|
113
|
+
|
114
|
+
elsif not tracker.options[:ignore_model_output] and match = has_immediate_model?(arg)
|
115
|
+
method = match[2]
|
116
|
+
|
117
|
+
unless IGNORE_MODEL_METHODS.include? method
|
118
|
+
add_result result
|
119
|
+
|
120
|
+
if MODEL_METHODS.include? method or method.to_s =~ /^find_by/
|
121
|
+
confidence = CONFIDENCE[:high]
|
122
|
+
else
|
123
|
+
confidence = CONFIDENCE[:med]
|
124
|
+
end
|
125
|
+
|
126
|
+
warn :result => result,
|
127
|
+
:warning_type => "Cross Site Scripting",
|
128
|
+
:message => "Unescaped model attribute in content_tag",
|
129
|
+
:user_input => match,
|
130
|
+
:confidence => confidence,
|
131
|
+
:link_path => "content_tag"
|
132
|
+
end
|
133
|
+
|
134
|
+
elsif @matched
|
135
|
+
message = "Unescaped "
|
136
|
+
|
137
|
+
case @matched.type
|
138
|
+
when :model
|
139
|
+
return if tracker.options[:ignore_model_output]
|
140
|
+
message << "model attribute"
|
141
|
+
when :params
|
142
|
+
message << "parameter"
|
143
|
+
when :cookies
|
144
|
+
message << "cookie"
|
145
|
+
when :session
|
146
|
+
message << "session"
|
147
|
+
else
|
148
|
+
message << "user input"
|
149
|
+
end
|
150
|
+
|
151
|
+
message << " value in content_tag"
|
152
|
+
|
153
|
+
add_result result
|
154
|
+
|
155
|
+
warn :result => result,
|
156
|
+
:warning_type => "Cross Site Scripting",
|
157
|
+
:message => message,
|
158
|
+
:user_input => @matched.match,
|
159
|
+
:confidence => CONFIDENCE[:med],
|
160
|
+
:link_path => "content_tag"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def process_call exp
|
165
|
+
if @mark
|
166
|
+
actually_process_call exp
|
167
|
+
else
|
168
|
+
@mark = true
|
169
|
+
actually_process_call exp
|
170
|
+
@mark = false
|
171
|
+
end
|
172
|
+
|
173
|
+
exp
|
174
|
+
end
|
175
|
+
|
176
|
+
def raw? exp
|
177
|
+
call? exp and exp.method == :raw
|
178
|
+
end
|
179
|
+
end
|
@@ -34,7 +34,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
34
34
|
FORM_BUILDER = Sexp.new(:call, Sexp.new(:const, :FormBuilder), :new, Sexp.new(:arglist))
|
35
35
|
|
36
36
|
#Run check
|
37
|
-
def run_check
|
37
|
+
def run_check
|
38
38
|
@ignore_methods = Set[:button_to, :check_box, :content_tag, :escapeHTML, :escape_once,
|
39
39
|
:field_field, :fields_for, :h, :hidden_field,
|
40
40
|
:hidden_field, :hidden_field_tag, :image_tag, :label,
|
@@ -58,6 +58,16 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
58
58
|
@known_dangerous << :strip_tags
|
59
59
|
end
|
60
60
|
|
61
|
+
matches = tracker.check_initializers :ActiveSupport, :escape_html_entities_in_json=
|
62
|
+
json_escape_on = matches.detect {|result| true? result[-1].first_arg}
|
63
|
+
|
64
|
+
if !json_escape_on or version_between? "0.0.0", "2.0.99"
|
65
|
+
@known_dangerous << :to_json
|
66
|
+
Brakeman.debug("Automatic to_json escaping not enabled, consider to_json dangerous")
|
67
|
+
else
|
68
|
+
Brakeman.debug("Automatic to_json escaping is enabled.")
|
69
|
+
end
|
70
|
+
|
61
71
|
tracker.each_template do |name, template|
|
62
72
|
@current_template = template
|
63
73
|
template[:outputs].each do |out|
|
@@ -77,10 +87,10 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
77
87
|
def check_for_immediate_xss exp
|
78
88
|
return if duplicate? exp
|
79
89
|
|
80
|
-
if exp
|
81
|
-
out = exp
|
82
|
-
elsif exp
|
83
|
-
out = exp
|
90
|
+
if exp.node_type == :output
|
91
|
+
out = exp.value
|
92
|
+
elsif exp.node_type == :escaped_output and raw_call? exp
|
93
|
+
out = exp.value.first_arg
|
84
94
|
end
|
85
95
|
|
86
96
|
if input = has_immediate_user_input?(out)
|
@@ -115,12 +125,20 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
115
125
|
confidence = CONFIDENCE[:med]
|
116
126
|
end
|
117
127
|
|
128
|
+
message = "Unescaped model attribute"
|
129
|
+
link_path = "cross_site_scripting"
|
130
|
+
if node_type?(out, :call, :attrasgn) && out.method == :to_json
|
131
|
+
message += " in JSON hash"
|
132
|
+
link_path += "_to_json"
|
133
|
+
end
|
134
|
+
|
118
135
|
code = find_chain out, match
|
119
136
|
warn :template => @current_template,
|
120
137
|
:warning_type => "Cross Site Scripting",
|
121
|
-
:message =>
|
138
|
+
:message => message,
|
122
139
|
:code => code,
|
123
|
-
:confidence => confidence
|
140
|
+
:confidence => confidence,
|
141
|
+
:link_path => link_path
|
124
142
|
end
|
125
143
|
|
126
144
|
else
|
@@ -130,15 +148,15 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
130
148
|
|
131
149
|
#Process an output Sexp
|
132
150
|
def process_output exp
|
133
|
-
process exp
|
151
|
+
process exp.value.dup
|
134
152
|
end
|
135
153
|
|
136
154
|
#Look for calls to raw()
|
137
155
|
#Otherwise, ignore
|
138
156
|
def process_escaped_output exp
|
139
157
|
unless check_for_immediate_xss exp
|
140
|
-
if raw_call? exp
|
141
|
-
process exp
|
158
|
+
if raw_call? exp and not duplicate? exp
|
159
|
+
process exp.value.first_arg
|
142
160
|
end
|
143
161
|
end
|
144
162
|
exp
|
@@ -173,8 +191,13 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
173
191
|
if message and not duplicate? exp
|
174
192
|
add_result exp
|
175
193
|
|
176
|
-
|
194
|
+
link_path = "cross_site_scripting"
|
195
|
+
if @known_dangerous.include? exp.method
|
177
196
|
confidence = CONFIDENCE[:high]
|
197
|
+
if exp.method == :to_json
|
198
|
+
message += " in JSON hash"
|
199
|
+
link_path += "_to_json"
|
200
|
+
end
|
178
201
|
else
|
179
202
|
confidence = CONFIDENCE[:low]
|
180
203
|
end
|
@@ -184,7 +207,8 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
184
207
|
:message => message,
|
185
208
|
:code => exp,
|
186
209
|
:user_input => @matched.match,
|
187
|
-
:confidence => confidence
|
210
|
+
:confidence => confidence,
|
211
|
+
:link_path => link_path
|
188
212
|
end
|
189
213
|
end
|
190
214
|
|
@@ -196,13 +220,13 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
196
220
|
|
197
221
|
def actually_process_call exp
|
198
222
|
return if @matched
|
199
|
-
target = exp
|
223
|
+
target = exp.target
|
200
224
|
if sexp? target
|
201
225
|
target = process target
|
202
226
|
end
|
203
227
|
|
204
|
-
method = exp
|
205
|
-
args = exp
|
228
|
+
method = exp.method
|
229
|
+
args = exp.arglist
|
206
230
|
|
207
231
|
#Ignore safe items
|
208
232
|
if (target.nil? and (@ignore_methods.include? method or method.to_s =~ IGNORE_LIKE)) or
|
@@ -215,7 +239,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
215
239
|
|
216
240
|
#exp[0] = :ignore #should not be necessary
|
217
241
|
@matched = false
|
218
|
-
elsif sexp?
|
242
|
+
elsif sexp? target and model_name? target[1]
|
219
243
|
@matched = Match.new(:model, exp)
|
220
244
|
elsif cookies? exp
|
221
245
|
@matched = Match.new(:cookies, exp)
|
@@ -267,6 +291,6 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
267
291
|
end
|
268
292
|
|
269
293
|
def raw_call? exp
|
270
|
-
exp
|
294
|
+
exp.value.node_type == :call and exp.value.method == :raw
|
271
295
|
end
|
272
296
|
end
|