brakeman 1.5.2 → 1.5.3
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 +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
|