brakeman 1.7.1 → 1.8.0
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/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
|