brakeman 1.5.2 → 1.5.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +4 -0
- data/lib/brakeman.rb +50 -38
- data/lib/brakeman/brakeman.rake +9 -0
- data/lib/brakeman/checks/check_evaluation.rb +2 -2
- data/lib/brakeman/checks/check_send.rb +38 -0
- data/lib/brakeman/options.rb +4 -3
- data/lib/brakeman/parsers/rails2_erubis.rb +4 -0
- data/lib/brakeman/parsers/rails2_xss_plugin_erubis.rb +46 -0
- data/lib/brakeman/parsers/rails3_erubis.rb +60 -0
- data/lib/brakeman/processor.rb +2 -2
- data/lib/brakeman/processors/alias_processor.rb +17 -4
- data/lib/brakeman/processors/base_processor.rb +21 -14
- data/lib/brakeman/processors/controller_alias_processor.rb +14 -2
- data/lib/brakeman/processors/controller_processor.rb +7 -1
- data/lib/brakeman/processors/erb_template_processor.rb +1 -1
- data/lib/brakeman/processors/erubis_template_processor.rb +1 -1
- data/lib/brakeman/processors/haml_template_processor.rb +1 -1
- data/lib/brakeman/processors/lib/processor_helper.rb +13 -3
- data/lib/brakeman/processors/lib/render_helper.rb +9 -4
- data/lib/brakeman/processors/template_alias_processor.rb +8 -3
- data/lib/brakeman/rescanner.rb +2 -0
- data/lib/brakeman/scanner.rb +15 -128
- data/lib/brakeman/util.rb +24 -0
- data/lib/brakeman/version.rb +1 -1
- metadata +9 -4
data/README.md
CHANGED
@@ -41,6 +41,10 @@ To specify an output file for the results:
|
|
41
41
|
|
42
42
|
The output format is determined by the file extension or by using the `-f` option. Current options are: `text`, `html`, `tabs`, `json` and `csv`.
|
43
43
|
|
44
|
+
Multiple output files can be specified:
|
45
|
+
|
46
|
+
brakeman -o output.html -o output.json
|
47
|
+
|
44
48
|
To suppress informational warnings and just output the report:
|
45
49
|
|
46
50
|
brakeman -q
|
data/lib/brakeman.rb
CHANGED
@@ -27,8 +27,8 @@ module Brakeman
|
|
27
27
|
# * :ignore_model_output - consider models safe (default: false)
|
28
28
|
# * :message_limit - limit length of messages
|
29
29
|
# * :min_confidence - minimum confidence (0-2, 0 is highest)
|
30
|
-
# * :
|
31
|
-
# * :
|
30
|
+
# * :output_files - files for output
|
31
|
+
# * :output_formats - formats for output (:to_s, :to_tabs, :to_csv, :to_html)
|
32
32
|
# * :parallel_checks - run checks in parallel (default: true)
|
33
33
|
# * :print_report - if no output file specified, print to stdout (default: false)
|
34
34
|
# * :quiet - suppress most messages (default: true)
|
@@ -65,7 +65,7 @@ module Brakeman
|
|
65
65
|
|
66
66
|
options = load_options(options[:config_file]).merge! options
|
67
67
|
options = get_defaults.merge! options
|
68
|
-
options[:
|
68
|
+
options[:output_formats] = get_output_formats options
|
69
69
|
|
70
70
|
app_path = options[:app_path]
|
71
71
|
|
@@ -124,39 +124,47 @@ module Brakeman
|
|
124
124
|
}
|
125
125
|
end
|
126
126
|
|
127
|
-
#Determine output
|
128
|
-
#or options[:
|
129
|
-
def self.
|
127
|
+
#Determine output formats based on options[:output_formats]
|
128
|
+
#or options[:output_files]
|
129
|
+
def self.get_output_formats options
|
130
130
|
#Set output format
|
131
|
+
if options[:output_format] && options[:output_files] && options[:output_files].size > 1
|
132
|
+
raise ArgumentError, "Cannot specify output format if multiple output files specified"
|
133
|
+
end
|
131
134
|
if options[:output_format]
|
132
|
-
|
133
|
-
|
134
|
-
:to_html
|
135
|
-
|
136
|
-
:to_csv
|
137
|
-
|
138
|
-
:to_pdf
|
139
|
-
|
140
|
-
:to_tabs
|
141
|
-
|
142
|
-
:to_json
|
143
|
-
|
144
|
-
|
145
|
-
|
135
|
+
[
|
136
|
+
case options[:output_format]
|
137
|
+
when :html, :to_html
|
138
|
+
:to_html
|
139
|
+
when :csv, :to_csv
|
140
|
+
:to_csv
|
141
|
+
when :pdf, :to_pdf
|
142
|
+
:to_pdf
|
143
|
+
when :tabs, :to_tabs
|
144
|
+
:to_tabs
|
145
|
+
when :json, :to_json
|
146
|
+
:to_json
|
147
|
+
else
|
148
|
+
:to_s
|
149
|
+
end
|
150
|
+
]
|
146
151
|
else
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
152
|
+
return [:to_s] unless options[:output_files]
|
153
|
+
options[:output_files].map do |output_file|
|
154
|
+
case output_file
|
155
|
+
when /\.html$/i
|
156
|
+
:to_html
|
157
|
+
when /\.csv$/i
|
158
|
+
:to_csv
|
159
|
+
when /\.pdf$/i
|
160
|
+
:to_pdf
|
161
|
+
when /\.tabs$/i
|
162
|
+
:to_tabs
|
163
|
+
when /\.json$/i
|
164
|
+
:to_json
|
165
|
+
else
|
166
|
+
:to_s
|
167
|
+
end
|
160
168
|
end
|
161
169
|
end
|
162
170
|
end
|
@@ -253,17 +261,21 @@ module Brakeman
|
|
253
261
|
end
|
254
262
|
tracker.run_checks
|
255
263
|
|
256
|
-
if options[:
|
264
|
+
if options[:output_files]
|
257
265
|
notify "Generating report..."
|
258
266
|
|
259
|
-
|
260
|
-
|
267
|
+
options[:output_files].each_with_index do |output_file, idx|
|
268
|
+
File.open output_file, "w" do |f|
|
269
|
+
f.write tracker.report.send(options[:output_formats][idx])
|
270
|
+
end
|
271
|
+
notify "Report saved in '#{output_file}'"
|
261
272
|
end
|
262
|
-
notify "Report saved in '#{options[:output_file]}'"
|
263
273
|
elsif options[:print_report]
|
264
274
|
notify "Generating report..."
|
265
275
|
|
266
|
-
|
276
|
+
options[:output_formats].each do |output_format|
|
277
|
+
puts tracker.report.send(output_format)
|
278
|
+
end
|
267
279
|
end
|
268
280
|
|
269
281
|
tracker
|
@@ -18,9 +18,9 @@ class Brakeman::CheckEvaluation < Brakeman::BaseCheck
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
#Warns if
|
21
|
+
#Warns if eval includes user input
|
22
22
|
def process_result result
|
23
|
-
if include_user_input? result[:call]
|
23
|
+
if include_user_input? result[:call][-1]
|
24
24
|
warn :result => result,
|
25
25
|
:warning_type => "Dangerous Eval",
|
26
26
|
:message => "User input in eval",
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'brakeman/checks/base_check'
|
2
|
+
|
3
|
+
#Checks if user supplied data is passed to send
|
4
|
+
class Brakeman::CheckSend < Brakeman::BaseCheck
|
5
|
+
Brakeman::Checks.add self
|
6
|
+
|
7
|
+
@description = "Check for unsafe use of Object#send"
|
8
|
+
|
9
|
+
def run_check
|
10
|
+
Brakeman.debug("Finding instances of #send")
|
11
|
+
calls = tracker.find_call :method => :send
|
12
|
+
|
13
|
+
calls.each do |call|
|
14
|
+
process_result call
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def process_result result
|
19
|
+
args = process result[:call][3]
|
20
|
+
target = process result[:call][1]
|
21
|
+
|
22
|
+
if has_immediate_user_input? args[1]
|
23
|
+
warn :result => result,
|
24
|
+
:warning_type => "Dangerous Send",
|
25
|
+
:message => "User controlled method execution",
|
26
|
+
:code => result[:call],
|
27
|
+
:confidence => CONFIDENCE[:high]
|
28
|
+
end
|
29
|
+
|
30
|
+
if has_immediate_user_input?(target)
|
31
|
+
warn :result => result,
|
32
|
+
:warning_type => "Dangerous Send",
|
33
|
+
:message => "User defined target of method invocation",
|
34
|
+
:code => result[:call],
|
35
|
+
:confidence => CONFIDENCE[:med]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/brakeman/options.rb
CHANGED
@@ -130,7 +130,7 @@ module Brakeman::Options
|
|
130
130
|
opts.on "-f",
|
131
131
|
"--format TYPE",
|
132
132
|
[:pdf, :text, :html, :csv, :tabs, :json],
|
133
|
-
"Specify output
|
133
|
+
"Specify output formats. Default is text" do |type|
|
134
134
|
|
135
135
|
type = "s" if type == :text
|
136
136
|
options[:output_format] = ("to_" << type.to_s).to_sym
|
@@ -152,8 +152,9 @@ module Brakeman::Options
|
|
152
152
|
options[:message_limit] = limit.to_i
|
153
153
|
end
|
154
154
|
|
155
|
-
opts.on "-o", "--output FILE", "Specify
|
156
|
-
options[:
|
155
|
+
opts.on "-o", "--output FILE", "Specify files for output. Defaults to stdout. Multiple '-o's allowed" do |file|
|
156
|
+
options[:output_files] ||= []
|
157
|
+
options[:output_files].push(file)
|
157
158
|
end
|
158
159
|
|
159
160
|
opts.on "--separate-models", "Warn on each model without attr_accessible" do
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#This is from the rails_xss plugin for Rails 2
|
2
|
+
class Brakeman::Rails2XSSPluginErubis < ::Erubis::Eruby
|
3
|
+
def add_preamble(src)
|
4
|
+
#src << "@output_buffer = ActiveSupport::SafeBuffer.new;"
|
5
|
+
end
|
6
|
+
|
7
|
+
#This is different from rails_xss - fixes some line number issues
|
8
|
+
def add_text(src, text)
|
9
|
+
if text == "\n"
|
10
|
+
src << "\n"
|
11
|
+
elsif text.include? "\n"
|
12
|
+
lines = text.split("\n")
|
13
|
+
if text.match(/\n\z/)
|
14
|
+
lines.each do |line|
|
15
|
+
src << "@output_buffer.safe_concat('" << escape_text(line) << "');\n"
|
16
|
+
end
|
17
|
+
else
|
18
|
+
lines[0..-2].each do |line|
|
19
|
+
src << "@output_buffer.safe_concat('" << escape_text(line) << "');\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
src << "@output_buffer.safe_concat('" << escape_text(lines.last) << "');"
|
23
|
+
end
|
24
|
+
else
|
25
|
+
src << "@output_buffer.safe_concat('" << escape_text(text) << "');"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
30
|
+
|
31
|
+
def add_expr_literal(src, code)
|
32
|
+
if code =~ BLOCK_EXPR
|
33
|
+
src << "@output_buffer.safe_concat((" << $1 << ").to_s);"
|
34
|
+
else
|
35
|
+
src << '@output_buffer << ((' << code << ').to_s);'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_expr_escaped(src, code)
|
40
|
+
src << '@output_buffer << ' << escaped_expr(code) << ';'
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_postamble(src)
|
44
|
+
#src << '@output_buffer.to_s'
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#This is from Rails 3 version of the Erubis handler
|
2
|
+
class Brakeman::Rails3Erubis < ::Erubis::Eruby
|
3
|
+
|
4
|
+
def add_preamble(src)
|
5
|
+
# src << "_buf = ActionView::SafeBuffer.new;\n"
|
6
|
+
end
|
7
|
+
|
8
|
+
#This is different from Rails 3 - fixes some line number issues
|
9
|
+
def add_text(src, text)
|
10
|
+
if text == "\n"
|
11
|
+
src << "\n"
|
12
|
+
elsif text.include? "\n"
|
13
|
+
lines = text.split("\n")
|
14
|
+
if text.match(/\n\z/)
|
15
|
+
lines.each do |line|
|
16
|
+
src << "@output_buffer << ('" << escape_text(line) << "'.html_safe!);\n"
|
17
|
+
end
|
18
|
+
else
|
19
|
+
lines[0..-2].each do |line|
|
20
|
+
src << "@output_buffer << ('" << escape_text(line) << "'.html_safe!);\n"
|
21
|
+
end
|
22
|
+
|
23
|
+
src << "@output_buffer << ('" << escape_text(lines.last) << "'.html_safe!);"
|
24
|
+
end
|
25
|
+
else
|
26
|
+
src << "@output_buffer << ('" << escape_text(text) << "'.html_safe!);"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
31
|
+
|
32
|
+
def add_expr_literal(src, code)
|
33
|
+
if code =~ BLOCK_EXPR
|
34
|
+
src << '@output_buffer.append= ' << code
|
35
|
+
else
|
36
|
+
src << '@output_buffer.append= (' << code << ');'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_stmt(src, code)
|
41
|
+
if code =~ BLOCK_EXPR
|
42
|
+
src << '@output_buffer.append_if_string= ' << code
|
43
|
+
else
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def add_expr_escaped(src, code)
|
49
|
+
if code =~ BLOCK_EXPR
|
50
|
+
src << "@output_buffer.safe_append= " << code
|
51
|
+
else
|
52
|
+
src << "@output_buffer.safe_concat(" << code << ");"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
#Add code to output buffer.
|
57
|
+
def add_postamble(src)
|
58
|
+
# src << '_buf.to_s'
|
59
|
+
end
|
60
|
+
end
|
data/lib/brakeman/processor.rb
CHANGED
@@ -40,8 +40,8 @@ module Brakeman
|
|
40
40
|
|
41
41
|
#Process variable aliasing in controller source and save it in the
|
42
42
|
#tracker.
|
43
|
-
def process_controller_alias src, only_method = nil
|
44
|
-
ControllerAliasProcessor.new(@tracker, only_method).
|
43
|
+
def process_controller_alias name, src, only_method = nil
|
44
|
+
ControllerAliasProcessor.new(@tracker, only_method).process_controller name, src
|
45
45
|
end
|
46
46
|
|
47
47
|
#Process a model source
|
@@ -492,12 +492,25 @@ class Brakeman::AliasProcessor < SexpProcessor
|
|
492
492
|
|
493
493
|
#Returns a new SexpProcessor::Environment containing only instance variables.
|
494
494
|
#This is useful, for example, when processing views.
|
495
|
-
def only_ivars
|
495
|
+
def only_ivars include_request_vars = false
|
496
496
|
res = SexpProcessor::Environment.new
|
497
|
-
|
498
|
-
|
499
|
-
|
497
|
+
|
498
|
+
if include_request_vars
|
499
|
+
env.all.each do |k, v|
|
500
|
+
#TODO Why would this have nil values?
|
501
|
+
if (k.node_type == :ivar or request_value? k) and not v.nil?
|
502
|
+
res[k] = v.dup
|
503
|
+
end
|
504
|
+
end
|
505
|
+
else
|
506
|
+
env.all.each do |k, v|
|
507
|
+
#TODO Why would this have nil values?
|
508
|
+
if k.node_type == :ivar and not v.nil?
|
509
|
+
res[k] = v.dup
|
510
|
+
end
|
511
|
+
end
|
500
512
|
end
|
513
|
+
|
501
514
|
res
|
502
515
|
end
|
503
516
|
|
@@ -32,14 +32,6 @@ class Brakeman::BaseProcessor < SexpProcessor
|
|
32
32
|
exp
|
33
33
|
end
|
34
34
|
|
35
|
-
def process_module exp
|
36
|
-
current_module = @current_module
|
37
|
-
@current_module = class_name exp[1]
|
38
|
-
process exp[2]
|
39
|
-
@current_module = current_module
|
40
|
-
exp
|
41
|
-
end
|
42
|
-
|
43
35
|
#Process a new scope. Removes expressions that are set to nil.
|
44
36
|
def process_scope exp
|
45
37
|
exp = exp.dup
|
@@ -210,9 +202,14 @@ class Brakeman::BaseProcessor < SexpProcessor
|
|
210
202
|
exp
|
211
203
|
end
|
212
204
|
|
205
|
+
#Convenience method for `make_render exp, true`
|
206
|
+
def make_render_in_view exp
|
207
|
+
make_render exp, true
|
208
|
+
end
|
209
|
+
|
213
210
|
#Generates :render node from call to render.
|
214
|
-
def make_render exp
|
215
|
-
render_type, value, rest = find_render_type exp[3]
|
211
|
+
def make_render exp, in_view = false
|
212
|
+
render_type, value, rest = find_render_type exp[3], in_view
|
216
213
|
rest = process rest
|
217
214
|
result = Sexp.new(:render, render_type, value, rest)
|
218
215
|
result.line(exp.line)
|
@@ -222,9 +219,11 @@ class Brakeman::BaseProcessor < SexpProcessor
|
|
222
219
|
#Determines the type of a call to render.
|
223
220
|
#
|
224
221
|
#Possible types are:
|
225
|
-
#:action, :default :file, :inline, :js, :json, :nothing, :partial,
|
222
|
+
#:action, :default, :file, :inline, :js, :json, :nothing, :partial,
|
226
223
|
#:template, :text, :update, :xml
|
227
|
-
|
224
|
+
#
|
225
|
+
#And also :layout for inside templates
|
226
|
+
def find_render_type args, in_view = false
|
228
227
|
rest = Sexp.new(:hash)
|
229
228
|
type = nil
|
230
229
|
value = nil
|
@@ -252,10 +251,18 @@ class Brakeman::BaseProcessor < SexpProcessor
|
|
252
251
|
value = args[1]
|
253
252
|
end
|
254
253
|
|
254
|
+
types_in_hash = Set[:action, :file, :inline, :js, :json, :nothing, :partial, :text, :update, :xml]
|
255
|
+
|
256
|
+
#render :layout => "blah" means something else when in a template
|
257
|
+
if in_view
|
258
|
+
types_in_hash << :layout
|
259
|
+
end
|
260
|
+
|
261
|
+
#Look for "type" of render in options hash
|
262
|
+
#For example, render :file => "blah"
|
255
263
|
if hash? args[-1]
|
256
264
|
hash_iterate(args[-1]) do |key, val|
|
257
|
-
|
258
|
-
when :action, :file, :inline, :js, :json, :nothing, :partial, :text, :update, :xml
|
265
|
+
if types_in_hash.include? key[1]
|
259
266
|
type = key[1]
|
260
267
|
value = val
|
261
268
|
else
|
@@ -17,11 +17,23 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
|
|
17
17
|
@current_class = @current_module = @current_method = nil
|
18
18
|
end
|
19
19
|
|
20
|
+
def process_controller name, src
|
21
|
+
if not node_type? src, :class
|
22
|
+
Brakeman.debug "#{name} is not a class, it's a #{src.node_type}"
|
23
|
+
return
|
24
|
+
else
|
25
|
+
@current_class = name
|
26
|
+
process_default src
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
20
30
|
#Processes a class which is probably a controller.
|
31
|
+
#(This method should be retired - only classes should ever be processed
|
32
|
+
# and @current_module will never be set, leading to inaccurate class names)
|
21
33
|
def process_class exp
|
22
34
|
@current_class = class_name(exp[1])
|
23
35
|
if @current_module
|
24
|
-
@current_class = (
|
36
|
+
@current_class = ("#@current_module::#@current_class").to_sym
|
25
37
|
end
|
26
38
|
|
27
39
|
process_default exp
|
@@ -101,7 +113,7 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
|
|
101
113
|
processor = Brakeman::AliasProcessor.new @tracker
|
102
114
|
processor.process_safely(method[3])
|
103
115
|
|
104
|
-
ivars = processor.only_ivars.all
|
116
|
+
ivars = processor.only_ivars(:include_request_vars).all
|
105
117
|
|
106
118
|
@tracker.filter_cache[[filter[:controller], name]] = ivars
|
107
119
|
|
@@ -130,7 +130,13 @@ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
|
|
130
130
|
name = exp[2]
|
131
131
|
|
132
132
|
if exp[1].node_type == :self
|
133
|
-
|
133
|
+
if @controller
|
134
|
+
target = @controller[:name]
|
135
|
+
elsif @current_module
|
136
|
+
target = @current_module
|
137
|
+
else
|
138
|
+
target = nil
|
139
|
+
end
|
134
140
|
else
|
135
141
|
target = class_name exp[1]
|
136
142
|
end
|
@@ -44,7 +44,7 @@ class Brakeman::ErbTemplateProcessor < Brakeman::TemplateProcessor
|
|
44
44
|
end
|
45
45
|
elsif target == nil and method == :render
|
46
46
|
exp[3] = process(exp[3])
|
47
|
-
|
47
|
+
make_render_in_view exp
|
48
48
|
else
|
49
49
|
args = exp[3] = process(exp[3])
|
50
50
|
call = Sexp.new :call, target, method, args
|
@@ -41,7 +41,7 @@ class Brakeman::ErubisTemplateProcessor < Brakeman::TemplateProcessor
|
|
41
41
|
end
|
42
42
|
elsif target == nil and method == :render
|
43
43
|
exp[3] = process exp[3]
|
44
|
-
|
44
|
+
make_render_in_view exp
|
45
45
|
else
|
46
46
|
args = exp[3] = process(exp[3])
|
47
47
|
call = Sexp.new :call, target, method, args
|
@@ -92,7 +92,7 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
|
|
92
92
|
elsif target == nil and method == :render
|
93
93
|
#Process call to render()
|
94
94
|
exp[3] = process exp[3]
|
95
|
-
|
95
|
+
make_render_in_view exp
|
96
96
|
else
|
97
97
|
args = process exp[3]
|
98
98
|
call = Sexp.new :call, target, method, args
|
@@ -3,9 +3,19 @@ module Brakeman::ProcessorHelper
|
|
3
3
|
|
4
4
|
#Sets the current module.
|
5
5
|
def process_module exp
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
module_name = class_name(exp[1]).to_s
|
7
|
+
prev_module = @current_module
|
8
|
+
|
9
|
+
if prev_module
|
10
|
+
@current_module = "#{prev_module}::#{module_name}"
|
11
|
+
else
|
12
|
+
@current_module = module_name
|
13
|
+
end
|
14
|
+
|
15
|
+
process exp[2]
|
16
|
+
|
17
|
+
@current_module = prev_module
|
18
|
+
|
9
19
|
exp
|
10
20
|
end
|
11
21
|
|
@@ -11,8 +11,13 @@ module Brakeman::RenderHelper
|
|
11
11
|
when :action
|
12
12
|
process_action exp[2][1], exp[3]
|
13
13
|
when :default
|
14
|
-
|
15
|
-
|
14
|
+
begin
|
15
|
+
process_template template_name, exp[3]
|
16
|
+
rescue ArgumentError => e
|
17
|
+
Brakeman.debug "Problem processing render: #{exp}"
|
18
|
+
raise e
|
19
|
+
end
|
20
|
+
when :partial, :layout
|
16
21
|
process_partial exp[2], exp[3]
|
17
22
|
when :nothing
|
18
23
|
end
|
@@ -58,7 +63,7 @@ module Brakeman::RenderHelper
|
|
58
63
|
return
|
59
64
|
end
|
60
65
|
|
61
|
-
template_env = only_ivars
|
66
|
+
template_env = only_ivars(:include_request_vars)
|
62
67
|
|
63
68
|
#Hash the environment and the source of the template to avoid
|
64
69
|
#pointlessly processing templates, which can become prohibitively
|
@@ -117,7 +122,7 @@ module Brakeman::RenderHelper
|
|
117
122
|
#Run source through AliasProcessor with instance variables from the
|
118
123
|
#current environment.
|
119
124
|
#TODO: Add in :locals => { ... } to environment
|
120
|
-
src = Brakeman::TemplateAliasProcessor.new(@tracker, template).process_safely(template[:src], template_env)
|
125
|
+
src = Brakeman::TemplateAliasProcessor.new(@tracker, template, called_from).process_safely(template[:src], template_env)
|
121
126
|
|
122
127
|
#Run alias-processed src through the template processor to pull out
|
123
128
|
#information and outputs.
|
@@ -9,14 +9,19 @@ class Brakeman::TemplateAliasProcessor < Brakeman::AliasProcessor
|
|
9
9
|
|
10
10
|
FORM_METHODS = Set[:form_for, :remote_form_for, :form_remote_for]
|
11
11
|
|
12
|
-
def initialize tracker, template
|
13
|
-
super
|
14
|
-
@tracker = tracker
|
12
|
+
def initialize tracker, template, called_from = nil
|
13
|
+
super tracker
|
15
14
|
@template = template
|
15
|
+
@called_from = called_from
|
16
16
|
end
|
17
17
|
|
18
18
|
#Process template
|
19
19
|
def process_template name, args
|
20
|
+
if @called_from and @called_from.match(/Template:#{Regexp.escape name}$/)
|
21
|
+
Brakeman.debug "Skipping circular render from #{@template[:name]} to #{name}"
|
22
|
+
return
|
23
|
+
end
|
24
|
+
|
20
25
|
super name, args, "Template:#{@template[:name]}"
|
21
26
|
end
|
22
27
|
|
data/lib/brakeman/rescanner.rb
CHANGED
data/lib/brakeman/scanner.rb
CHANGED
@@ -13,26 +13,21 @@ begin
|
|
13
13
|
require 'erb'
|
14
14
|
require 'erubis'
|
15
15
|
require 'brakeman/processor'
|
16
|
+
require 'brakeman/parsers/rails2_erubis'
|
17
|
+
require 'brakeman/parsers/rails2_xss_plugin_erubis'
|
18
|
+
require 'brakeman/parsers/rails3_erubis'
|
16
19
|
rescue LoadError => e
|
17
20
|
$stderr.puts e.message
|
18
21
|
$stderr.puts "Please install the appropriate dependency."
|
19
22
|
exit
|
20
23
|
end
|
21
24
|
|
22
|
-
#Erubis processor which ignores any output which is plain text.
|
23
|
-
class Brakeman::ScannerErubis < Erubis::Eruby
|
24
|
-
include Erubis::NoTextEnhancer
|
25
|
-
end
|
26
|
-
|
27
|
-
class Brakeman::ErubisEscape < Brakeman::ScannerErubis
|
28
|
-
include Erubis::EscapeEnhancer
|
29
|
-
end
|
30
|
-
|
31
25
|
#Scans the Rails application.
|
32
26
|
class Brakeman::Scanner
|
33
27
|
attr_reader :options
|
34
28
|
|
35
29
|
RUBY_1_9 = !!(RUBY_VERSION =~ /^1\.9/)
|
30
|
+
KNOWN_TEMPLATE_EXTENSIONS = /.*\.(erb|haml|rhtml)$/
|
36
31
|
|
37
32
|
#Pass in path to the root of the Rails application
|
38
33
|
def initialize options, processor = nil
|
@@ -71,15 +66,15 @@ class Brakeman::Scanner
|
|
71
66
|
process_initializers
|
72
67
|
Brakeman.notify "Processing libs..."
|
73
68
|
process_libs
|
74
|
-
Brakeman.notify "Processing routes...
|
69
|
+
Brakeman.notify "Processing routes... "
|
75
70
|
process_routes
|
76
|
-
Brakeman.notify "Processing templates...
|
71
|
+
Brakeman.notify "Processing templates... "
|
77
72
|
process_templates
|
78
|
-
Brakeman.notify "Processing models...
|
73
|
+
Brakeman.notify "Processing models... "
|
79
74
|
process_models
|
80
|
-
Brakeman.notify "Processing controllers...
|
75
|
+
Brakeman.notify "Processing controllers... "
|
81
76
|
process_controllers
|
82
|
-
Brakeman.notify "Indexing call sites...
|
77
|
+
Brakeman.notify "Indexing call sites... "
|
83
78
|
index_call_sites
|
84
79
|
tracker
|
85
80
|
end
|
@@ -215,7 +210,7 @@ class Brakeman::Scanner
|
|
215
210
|
controller_files = Dir.glob(@app_path + "/controllers/**/*.rb").sort
|
216
211
|
controller_files.reject! { |f| @skip_files.match f } if @skip_files
|
217
212
|
|
218
|
-
total = controller_files.length
|
213
|
+
total = controller_files.length
|
219
214
|
current = 0
|
220
215
|
|
221
216
|
controller_files.each do |f|
|
@@ -240,7 +235,7 @@ class Brakeman::Scanner
|
|
240
235
|
current += 1
|
241
236
|
end
|
242
237
|
|
243
|
-
@processor.process_controller_alias controller[:src]
|
238
|
+
@processor.process_controller_alias name, controller[:src]
|
244
239
|
end
|
245
240
|
|
246
241
|
#No longer need these processed filter methods
|
@@ -298,7 +293,7 @@ class Brakeman::Scanner
|
|
298
293
|
end
|
299
294
|
|
300
295
|
def process_template path
|
301
|
-
type = path.match(
|
296
|
+
type = path.match(KNOWN_TEMPLATE_EXTENSIONS)[1].to_sym
|
302
297
|
type = :erb if type == :rhtml
|
303
298
|
name = template_path_to_name path
|
304
299
|
text = File.read path
|
@@ -308,9 +303,9 @@ class Brakeman::Scanner
|
|
308
303
|
if tracker.config[:escape_html]
|
309
304
|
type = :erubis
|
310
305
|
if options[:rails3]
|
311
|
-
src = Brakeman::
|
306
|
+
src = Brakeman::Rails3Erubis.new(text).src
|
312
307
|
else
|
313
|
-
src = Brakeman::
|
308
|
+
src = Brakeman::Rails2XSSPluginErubis.new(text).src
|
314
309
|
end
|
315
310
|
elsif tracker.config[:erubis]
|
316
311
|
type = :erubis
|
@@ -353,7 +348,7 @@ class Brakeman::Scanner
|
|
353
348
|
#
|
354
349
|
#Adds the processed models to tracker.models
|
355
350
|
def process_models
|
356
|
-
model_files = Dir.glob(@app_path + "/models
|
351
|
+
model_files = Dir.glob(@app_path + "/models/**/*.rb").sort
|
357
352
|
model_files.reject! { |f| @skip_files.match f } if @skip_files
|
358
353
|
|
359
354
|
total = model_files.length
|
@@ -389,111 +384,3 @@ class Brakeman::Scanner
|
|
389
384
|
@ruby_parser.new.parse input
|
390
385
|
end
|
391
386
|
end
|
392
|
-
|
393
|
-
#This is from Rails 3 version of the Erubis handler
|
394
|
-
class Brakeman::Rails3XSSErubis < ::Erubis::Eruby
|
395
|
-
|
396
|
-
def add_preamble(src)
|
397
|
-
# src << "_buf = ActionView::SafeBuffer.new;\n"
|
398
|
-
end
|
399
|
-
|
400
|
-
#This is different from Rails 3 - fixes some line number issues
|
401
|
-
def add_text(src, text)
|
402
|
-
if text == "\n"
|
403
|
-
src << "\n"
|
404
|
-
elsif text.include? "\n"
|
405
|
-
lines = text.split("\n")
|
406
|
-
if text.match(/\n\z/)
|
407
|
-
lines.each do |line|
|
408
|
-
src << "@output_buffer << ('" << escape_text(line) << "'.html_safe!);\n"
|
409
|
-
end
|
410
|
-
else
|
411
|
-
lines[0..-2].each do |line|
|
412
|
-
src << "@output_buffer << ('" << escape_text(line) << "'.html_safe!);\n"
|
413
|
-
end
|
414
|
-
|
415
|
-
src << "@output_buffer << ('" << escape_text(lines.last) << "'.html_safe!);"
|
416
|
-
end
|
417
|
-
else
|
418
|
-
src << "@output_buffer << ('" << escape_text(text) << "'.html_safe!);"
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
423
|
-
|
424
|
-
def add_expr_literal(src, code)
|
425
|
-
if code =~ BLOCK_EXPR
|
426
|
-
src << '@output_buffer.append= ' << code
|
427
|
-
else
|
428
|
-
src << '@output_buffer.append= (' << code << ');'
|
429
|
-
end
|
430
|
-
end
|
431
|
-
|
432
|
-
def add_stmt(src, code)
|
433
|
-
if code =~ BLOCK_EXPR
|
434
|
-
src << '@output_buffer.append_if_string= ' << code
|
435
|
-
else
|
436
|
-
super
|
437
|
-
end
|
438
|
-
end
|
439
|
-
|
440
|
-
def add_expr_escaped(src, code)
|
441
|
-
if code =~ BLOCK_EXPR
|
442
|
-
src << "@output_buffer.safe_append= " << code
|
443
|
-
else
|
444
|
-
src << "@output_buffer.safe_concat(" << code << ");"
|
445
|
-
end
|
446
|
-
end
|
447
|
-
|
448
|
-
#Add code to output buffer.
|
449
|
-
def add_postamble(src)
|
450
|
-
# src << '_buf.to_s'
|
451
|
-
end
|
452
|
-
end
|
453
|
-
|
454
|
-
#This is from the rails_xss plugin for Rails 2
|
455
|
-
class Brakeman::Rails2XSSErubis < ::Erubis::Eruby
|
456
|
-
def add_preamble(src)
|
457
|
-
#src << "@output_buffer = ActiveSupport::SafeBuffer.new;"
|
458
|
-
end
|
459
|
-
|
460
|
-
#This is different from rails_xss - fixes some line number issues
|
461
|
-
def add_text(src, text)
|
462
|
-
if text == "\n"
|
463
|
-
src << "\n"
|
464
|
-
elsif text.include? "\n"
|
465
|
-
lines = text.split("\n")
|
466
|
-
if text.match(/\n\z/)
|
467
|
-
lines.each do |line|
|
468
|
-
src << "@output_buffer.safe_concat('" << escape_text(line) << "');\n"
|
469
|
-
end
|
470
|
-
else
|
471
|
-
lines[0..-2].each do |line|
|
472
|
-
src << "@output_buffer.safe_concat('" << escape_text(line) << "');\n"
|
473
|
-
end
|
474
|
-
|
475
|
-
src << "@output_buffer.safe_concat('" << escape_text(lines.last) << "');"
|
476
|
-
end
|
477
|
-
else
|
478
|
-
src << "@output_buffer.safe_concat('" << escape_text(text) << "');"
|
479
|
-
end
|
480
|
-
end
|
481
|
-
|
482
|
-
BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
483
|
-
|
484
|
-
def add_expr_literal(src, code)
|
485
|
-
if code =~ BLOCK_EXPR
|
486
|
-
src << "@output_buffer.safe_concat((" << $1 << ").to_s);"
|
487
|
-
else
|
488
|
-
src << '@output_buffer << ((' << code << ').to_s);'
|
489
|
-
end
|
490
|
-
end
|
491
|
-
|
492
|
-
def add_expr_escaped(src, code)
|
493
|
-
src << '@output_buffer << ' << escaped_expr(code) << ';'
|
494
|
-
end
|
495
|
-
|
496
|
-
def add_postamble(src)
|
497
|
-
#src << '@output_buffer.to_s'
|
498
|
-
end
|
499
|
-
end
|
data/lib/brakeman/util.rb
CHANGED
@@ -80,6 +80,23 @@ module Brakeman::Util
|
|
80
80
|
hash
|
81
81
|
end
|
82
82
|
|
83
|
+
#Get value from hash using key.
|
84
|
+
#
|
85
|
+
#If _key_ is a Symbol, it will be converted to a Sexp(:lit, key).
|
86
|
+
def hash_access hash, key
|
87
|
+
if key.is_a? Symbol
|
88
|
+
key = Sexp.new(:lit, key)
|
89
|
+
end
|
90
|
+
|
91
|
+
hash_iterate hash do |k, v|
|
92
|
+
if k == key
|
93
|
+
return v
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
nil
|
98
|
+
end
|
99
|
+
|
83
100
|
#Adds params, session, and cookies to environment
|
84
101
|
#so they can be replaced by their respective Sexps.
|
85
102
|
def set_env_defaults
|
@@ -187,6 +204,13 @@ module Brakeman::Util
|
|
187
204
|
call? exp and (exp == REQUEST_ENV or exp[1] == REQUEST_ENV)
|
188
205
|
end
|
189
206
|
|
207
|
+
#Check if exp is params, cookies, or request_env
|
208
|
+
def request_value? exp
|
209
|
+
params? exp or
|
210
|
+
cookies? exp or
|
211
|
+
request_env? exp
|
212
|
+
end
|
213
|
+
|
190
214
|
#Check if _exp_ is a Sexp.
|
191
215
|
def sexp? exp
|
192
216
|
exp.is_a? Sexp
|
data/lib/brakeman/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brakeman
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 5
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 5
|
9
|
-
-
|
10
|
-
version: 1.5.
|
9
|
+
- 3
|
10
|
+
version: 1.5.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Justin Collins
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-04-10 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: activesupport
|
@@ -133,6 +133,7 @@ files:
|
|
133
133
|
- WARNING_TYPES
|
134
134
|
- FEATURES
|
135
135
|
- README.md
|
136
|
+
- lib/brakeman/brakeman.rake
|
136
137
|
- lib/ruby_parser/ruby18_parser.rb
|
137
138
|
- lib/ruby_parser/ruby_parser_extras.rb
|
138
139
|
- lib/ruby_parser/bm_sexp.rb
|
@@ -193,12 +194,16 @@ files:
|
|
193
194
|
- lib/brakeman/checks/check_file_access.rb
|
194
195
|
- lib/brakeman/checks/check_response_splitting.rb
|
195
196
|
- lib/brakeman/checks/check_basic_auth.rb
|
197
|
+
- lib/brakeman/checks/check_send.rb
|
196
198
|
- lib/brakeman/checks/check_redirect.rb
|
197
199
|
- lib/brakeman/checks/check_forgery_setting.rb
|
198
200
|
- lib/brakeman/checks/check_render.rb
|
199
201
|
- lib/brakeman/tracker.rb
|
200
202
|
- lib/brakeman/util.rb
|
201
203
|
- lib/brakeman/report.rb
|
204
|
+
- lib/brakeman/parsers/rails3_erubis.rb
|
205
|
+
- lib/brakeman/parsers/rails2_xss_plugin_erubis.rb
|
206
|
+
- lib/brakeman/parsers/rails2_erubis.rb
|
202
207
|
- lib/brakeman/version.rb
|
203
208
|
- lib/brakeman/call_index.rb
|
204
209
|
- lib/brakeman/options.rb
|