brakeman 1.2.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +8 -2
- data/lib/brakeman.rb +57 -19
- data/lib/brakeman/call_index.rb +1 -1
- data/lib/brakeman/checks.rb +4 -4
- data/lib/brakeman/checks/base_check.rb +0 -5
- data/lib/brakeman/checks/check_cross_site_scripting.rb +15 -6
- data/lib/brakeman/checks/check_default_routes.rb +1 -1
- data/lib/brakeman/checks/check_evaluation.rb +2 -2
- data/lib/brakeman/checks/check_execute.rb +3 -3
- data/lib/brakeman/checks/check_file_access.rb +4 -4
- data/lib/brakeman/checks/check_mail_to.rb +1 -1
- data/lib/brakeman/checks/check_mass_assignment.rb +2 -2
- data/lib/brakeman/checks/check_quote_table_name.rb +1 -1
- data/lib/brakeman/checks/check_redirect.rb +2 -2
- data/lib/brakeman/checks/check_send_file.rb +1 -1
- data/lib/brakeman/checks/check_sql.rb +5 -5
- data/lib/brakeman/checks/check_strip_tags.rb +1 -1
- data/lib/brakeman/checks/check_translate_bug.rb +2 -2
- data/lib/brakeman/checks/check_without_protection.rb +2 -2
- data/lib/brakeman/processors/controller_alias_processor.rb +2 -2
- data/lib/brakeman/processors/controller_processor.rb +2 -2
- data/lib/brakeman/processors/lib/rails2_config_processor.rb +1 -1
- data/lib/brakeman/processors/lib/render_helper.rb +7 -4
- data/lib/brakeman/processors/model_processor.rb +3 -1
- data/lib/brakeman/processors/output_processor.rb +1 -1
- data/lib/brakeman/report.rb +1 -1
- data/lib/brakeman/rescanner.rb +9 -1
- data/lib/brakeman/scanner.rb +19 -19
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +11 -0
- metadata +74 -109
data/README.md
CHANGED
@@ -6,9 +6,15 @@ It targets Rails versions 2.x and 3.x.
|
|
6
6
|
|
7
7
|
There is also a [plugin available](http://brakemanscanner.org/docs/jenkins/) for Jenkins/Hudson.
|
8
8
|
|
9
|
-
|
9
|
+
For even more continuous testing, try the [Guard plugin](https://github.com/oreoshake/guard-brakeman).
|
10
10
|
|
11
|
-
|
11
|
+
# Homepage/News
|
12
|
+
|
13
|
+
Website: http://brakemanscanner.org/
|
14
|
+
|
15
|
+
Twitter: http://twitter.com/brakemanscanner
|
16
|
+
|
17
|
+
Mailing list: brakeman@librelist.com
|
12
18
|
|
13
19
|
# Installation
|
14
20
|
|
data/lib/brakeman.rb
CHANGED
@@ -8,6 +8,9 @@ module Brakeman
|
|
8
8
|
#option is set
|
9
9
|
Warnings_Found_Exit_Code = 3
|
10
10
|
|
11
|
+
@debug = false
|
12
|
+
@quiet = false
|
13
|
+
|
11
14
|
#Run Brakeman scan. Returns Tracker object.
|
12
15
|
#
|
13
16
|
#Options:
|
@@ -42,14 +45,15 @@ module Brakeman
|
|
42
45
|
def self.run options
|
43
46
|
options = set_options options
|
44
47
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
48
|
+
@quiet = !!options[:quiet]
|
49
|
+
@debug = !!options[:debug]
|
50
|
+
|
51
|
+
options[:report_progress] = !@quiet
|
49
52
|
|
50
53
|
scan options
|
51
54
|
end
|
52
55
|
|
56
|
+
#Sets up options for run, checks given application path
|
53
57
|
def self.set_options options
|
54
58
|
if options.is_a? String
|
55
59
|
options = { :app_path => options }
|
@@ -67,12 +71,13 @@ module Brakeman
|
|
67
71
|
|
68
72
|
if File.exist? app_path + "/script/rails"
|
69
73
|
options[:rails3] = true
|
70
|
-
|
74
|
+
notify "[Notice] Detected Rails 3 application"
|
71
75
|
end
|
72
76
|
|
73
77
|
options
|
74
78
|
end
|
75
79
|
|
80
|
+
#Load options from YAML file
|
76
81
|
def self.load_options config_file
|
77
82
|
config_file ||= ""
|
78
83
|
|
@@ -84,7 +89,7 @@ module Brakeman
|
|
84
89
|
"#{File.expand_path(File.dirname(__FILE__))}/../lib/config.yaml"].each do |f|
|
85
90
|
|
86
91
|
if File.exist? f and not File.directory? f
|
87
|
-
|
92
|
+
notify "[Notice] Using configuration in #{f}"
|
88
93
|
options = YAML.load_file f
|
89
94
|
options.each do |k,v|
|
90
95
|
if v.is_a? Array
|
@@ -99,6 +104,7 @@ module Brakeman
|
|
99
104
|
return {}
|
100
105
|
end
|
101
106
|
|
107
|
+
#Default set of options
|
102
108
|
def self.get_defaults
|
103
109
|
{ :skip_checks => Set.new,
|
104
110
|
:check_arguments => true,
|
@@ -116,6 +122,8 @@ module Brakeman
|
|
116
122
|
}
|
117
123
|
end
|
118
124
|
|
125
|
+
#Determine output format based on options[:output_format]
|
126
|
+
#or options[:output_file]
|
119
127
|
def self.get_output_format options
|
120
128
|
#Set output format
|
121
129
|
if options[:output_format]
|
@@ -147,6 +155,7 @@ module Brakeman
|
|
147
155
|
end
|
148
156
|
end
|
149
157
|
|
158
|
+
#Output list of checks (for `-k` option)
|
150
159
|
def self.list_checks
|
151
160
|
require 'brakeman/scanner'
|
152
161
|
$stderr.puts "Available Checks:"
|
@@ -154,6 +163,9 @@ module Brakeman
|
|
154
163
|
$stderr.puts Checks.checks.map { |c| c.to_s.match(/^Brakeman::(.*)$/)[1] }.sort.join "\n"
|
155
164
|
end
|
156
165
|
|
166
|
+
#Installs Rake task for running Brakeman,
|
167
|
+
#which basically means copying `lib/brakeman/brakeman.rake` to
|
168
|
+
#`lib/tasks/brakeman.rake` in the current Rails application.
|
157
169
|
def self.install_rake_task
|
158
170
|
if not File.exists? "Rakefile"
|
159
171
|
abort "No Rakefile detected"
|
@@ -164,7 +176,7 @@ module Brakeman
|
|
164
176
|
require 'fileutils'
|
165
177
|
|
166
178
|
if not File.exists? "lib/tasks"
|
167
|
-
|
179
|
+
notify "Creating lib/tasks"
|
168
180
|
FileUtils.mkdir_p "lib/tasks"
|
169
181
|
end
|
170
182
|
|
@@ -173,13 +185,14 @@ module Brakeman
|
|
173
185
|
FileUtils.cp "#{path}/brakeman/brakeman.rake", "lib/tasks/brakeman.rake"
|
174
186
|
|
175
187
|
if File.exists? "lib/tasks/brakeman.rake"
|
176
|
-
|
177
|
-
|
188
|
+
notify "Task created in lib/tasks/brakeman.rake"
|
189
|
+
notify "Usage: rake brakeman:run[output_file]"
|
178
190
|
else
|
179
|
-
|
191
|
+
notify "Could not create task"
|
180
192
|
end
|
181
193
|
end
|
182
194
|
|
195
|
+
#Output configuration to YAML
|
183
196
|
def self.dump_config options
|
184
197
|
if options[:create_config].is_a? String
|
185
198
|
file = options[:create_config]
|
@@ -206,9 +219,10 @@ module Brakeman
|
|
206
219
|
exit
|
207
220
|
end
|
208
221
|
|
222
|
+
#Run a scan. Generally called from Brakeman.run instead of directly.
|
209
223
|
def self.scan options
|
210
224
|
#Load scanner
|
211
|
-
|
225
|
+
notify "Loading scanner..."
|
212
226
|
|
213
227
|
begin
|
214
228
|
require 'brakeman/scanner'
|
@@ -219,27 +233,27 @@ module Brakeman
|
|
219
233
|
#Start scanning
|
220
234
|
scanner = Scanner.new options
|
221
235
|
|
222
|
-
|
236
|
+
notify "[Notice] Using Ruby #{RUBY_VERSION}. Please make sure this matches the one used to run your Rails application."
|
223
237
|
|
224
|
-
|
238
|
+
notify "Processing application in #{options[:app_path]}"
|
225
239
|
tracker = scanner.process
|
226
240
|
|
227
241
|
if options[:parallel_checks]
|
228
|
-
|
242
|
+
notify "Running checks in parallel..."
|
229
243
|
else
|
230
|
-
|
244
|
+
notify "Runnning checks..."
|
231
245
|
end
|
232
246
|
tracker.run_checks
|
233
247
|
|
234
248
|
if options[:output_file]
|
235
|
-
|
249
|
+
notify "Generating report..."
|
236
250
|
|
237
251
|
File.open options[:output_file], "w" do |f|
|
238
252
|
f.puts tracker.report.send(options[:output_format])
|
239
253
|
end
|
240
|
-
|
254
|
+
notify "Report saved in '#{options[:output_file]}'"
|
241
255
|
elsif options[:print_report]
|
242
|
-
|
256
|
+
notify "Generating report..."
|
243
257
|
|
244
258
|
puts tracker.report.send(options[:output_format])
|
245
259
|
end
|
@@ -256,9 +270,33 @@ module Brakeman
|
|
256
270
|
tracker
|
257
271
|
end
|
258
272
|
|
259
|
-
|
273
|
+
#Rescan a subset of files in a Rails application.
|
274
|
+
#
|
275
|
+
#A full scan must have been run already to use this method.
|
276
|
+
#The returned Tracker object from Brakeman.run is used as a starting point
|
277
|
+
#for the rescan.
|
278
|
+
#
|
279
|
+
#Options may be given as a hash with the same values as Brakeman.run.
|
280
|
+
#Note that these options will be merged into the Tracker.
|
281
|
+
#
|
282
|
+
#This method returns a RescanReport object with information about the scan.
|
283
|
+
#However, the Tracker object will also be modified as the scan is run.
|
284
|
+
def self.rescan tracker, files, options = {}
|
260
285
|
require 'brakeman/rescanner'
|
261
286
|
|
287
|
+
tracker.options.merge! options
|
288
|
+
|
289
|
+
@quiet = !!tracker.options[:quiet]
|
290
|
+
@debug = !!tracker.options[:debug]
|
291
|
+
|
262
292
|
Rescanner.new(tracker.options, tracker.processor, files).recheck
|
263
293
|
end
|
294
|
+
|
295
|
+
def self.notify message
|
296
|
+
$stderr.puts message unless @quiet
|
297
|
+
end
|
298
|
+
|
299
|
+
def self.debug message
|
300
|
+
$stderr.puts message if @debug
|
301
|
+
end
|
264
302
|
end
|
data/lib/brakeman/call_index.rb
CHANGED
@@ -55,7 +55,7 @@ class Brakeman::CallIndex
|
|
55
55
|
elsif method
|
56
56
|
calls = calls_by_method method
|
57
57
|
else
|
58
|
-
|
58
|
+
notify "Invalid arguments to CallCache#find_calls: #{options.inspect}"
|
59
59
|
end
|
60
60
|
|
61
61
|
return [] if calls.nil?
|
data/lib/brakeman/checks.rb
CHANGED
@@ -89,7 +89,7 @@ class Brakeman::Checks
|
|
89
89
|
unless tracker.options[:skip_checks].include? check_name or
|
90
90
|
(tracker.options[:run_checks] and not tracker.options[:run_checks].include? check_name)
|
91
91
|
|
92
|
-
|
92
|
+
Brakeman.notify " - #{check_name}"
|
93
93
|
|
94
94
|
check = c.new(tracker)
|
95
95
|
check.run_check
|
@@ -120,7 +120,7 @@ class Brakeman::Checks
|
|
120
120
|
unless tracker.options[:skip_checks].include? check_name or
|
121
121
|
(tracker.options[:run_checks] and not tracker.options[:run_checks].include? check_name)
|
122
122
|
|
123
|
-
|
123
|
+
Brakeman.notify " - #{check_name}"
|
124
124
|
|
125
125
|
threads << Thread.new do
|
126
126
|
begin
|
@@ -128,7 +128,7 @@ class Brakeman::Checks
|
|
128
128
|
check.run_check
|
129
129
|
check.warnings
|
130
130
|
rescue Exception => e
|
131
|
-
|
131
|
+
Brakeman.notify "[#{check_name}] #{e}"
|
132
132
|
[]
|
133
133
|
end
|
134
134
|
end
|
@@ -141,7 +141,7 @@ class Brakeman::Checks
|
|
141
141
|
|
142
142
|
threads.each { |t| t.join }
|
143
143
|
|
144
|
-
|
144
|
+
Brakeman.notify "Checks finished, collecting results..."
|
145
145
|
|
146
146
|
#Collect results
|
147
147
|
threads.each do |thread|
|
@@ -20,7 +20,6 @@ class Brakeman::BaseCheck < SexpProcessor
|
|
20
20
|
@tracker = tracker
|
21
21
|
@string_interp = false
|
22
22
|
@current_set = nil
|
23
|
-
@debug_mode = tracker.options[:debug]
|
24
23
|
@current_template = @current_module = @current_class = @current_method = nil
|
25
24
|
self.strict = false
|
26
25
|
self.auto_shift_type = false
|
@@ -397,8 +396,4 @@ class Brakeman::BaseCheck < SexpProcessor
|
|
397
396
|
"config/environment.rb"
|
398
397
|
end
|
399
398
|
end
|
400
|
-
|
401
|
-
def debug_info msg
|
402
|
-
Kernel.warn msg if @debug_mode
|
403
|
-
end
|
404
399
|
end
|
@@ -44,9 +44,11 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
44
44
|
@models = tracker.models.keys
|
45
45
|
@inspect_arguments = tracker.options[:check_arguments]
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
if version_between?("2.0.0", "2.9.9") and not tracker.config[:escape_html]
|
48
|
+
link_to_check = Brakeman::CheckLinkTo.new(tracker)
|
49
|
+
link_to_check.run_check
|
50
|
+
warnings.concat link_to_check.warnings unless link_to_check.warnings.empty?
|
51
|
+
end
|
50
52
|
|
51
53
|
@known_dangerous = Set.new([:truncate, :concat])
|
52
54
|
|
@@ -59,10 +61,10 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
59
61
|
tracker.each_template do |name, template|
|
60
62
|
@current_template = template
|
61
63
|
template[:outputs].each do |out|
|
62
|
-
|
64
|
+
Brakeman.debug "Checking #{name} for direct XSS"
|
63
65
|
|
64
66
|
unless check_for_immediate_xss out
|
65
|
-
|
67
|
+
Brakeman.debug "Checking #{name} for indirect XSS"
|
66
68
|
|
67
69
|
@matched = false
|
68
70
|
@mark = false
|
@@ -266,7 +268,14 @@ end
|
|
266
268
|
#This _only_ checks calls to link_to
|
267
269
|
class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
|
268
270
|
def run_check
|
269
|
-
@ignore_methods = [
|
271
|
+
@ignore_methods = Set.new([:button_to, :check_box, :escapeHTML, :escape_once,
|
272
|
+
:field_field, :fields_for, :h, :hidden_field,
|
273
|
+
:hidden_field, :hidden_field_tag, :image_tag, :label,
|
274
|
+
:mail_to, :radio_button, :select,
|
275
|
+
:submit_tag, :text_area, :text_field,
|
276
|
+
:text_field_tag, :url_encode, :url_for,
|
277
|
+
:will_paginate] ).merge tracker.options[:safe_methods]
|
278
|
+
|
270
279
|
@known_dangerous = []
|
271
280
|
#Ideally, I think this should also check to see if people are setting
|
272
281
|
#:escape => false
|
@@ -15,7 +15,7 @@ class Brakeman::CheckDefaultRoutes < Brakeman::BaseCheck
|
|
15
15
|
:confidence => CONFIDENCE[:high],
|
16
16
|
:file => "#{tracker.options[:app_path]}/config/routes.rb"
|
17
17
|
else #Report each controller separately
|
18
|
-
|
18
|
+
Brakeman.debug "Checking each controller for default routes"
|
19
19
|
|
20
20
|
tracker.routes.each do |name, actions|
|
21
21
|
if actions.is_a? Array and actions[0] == :allow_all_actions
|
@@ -7,10 +7,10 @@ class Brakeman::CheckEvaluation < Brakeman::BaseCheck
|
|
7
7
|
|
8
8
|
#Process calls
|
9
9
|
def run_check
|
10
|
-
|
10
|
+
Brakeman.debug "Finding eval-like calls"
|
11
11
|
calls = tracker.find_call :method => [:eval, :instance_eval, :class_eval, :module_eval]
|
12
12
|
|
13
|
-
|
13
|
+
Brakeman.debug "Processing eval-like calls"
|
14
14
|
calls.each do |call|
|
15
15
|
process_result call
|
16
16
|
end
|
@@ -13,13 +13,13 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
13
13
|
|
14
14
|
#Check models, controllers, and views for command injection.
|
15
15
|
def run_check
|
16
|
-
|
16
|
+
Brakeman.debug "Finding system calls using ``"
|
17
17
|
check_for_backticks tracker
|
18
18
|
|
19
|
-
|
19
|
+
Brakeman.debug "Finding other system calls"
|
20
20
|
calls = tracker.find_call :targets => [:IO, :Open3, :Kernel, nil], :methods => [:exec, :popen, :popen3, :syscall, :system]
|
21
21
|
|
22
|
-
|
22
|
+
Brakeman.debug "Processing system calls"
|
23
23
|
calls.each do |result|
|
24
24
|
process_result result
|
25
25
|
end
|
@@ -6,16 +6,16 @@ class Brakeman::CheckFileAccess < Brakeman::BaseCheck
|
|
6
6
|
Brakeman::Checks.add self
|
7
7
|
|
8
8
|
def run_check
|
9
|
-
|
9
|
+
Brakeman.debug "Finding possible file access"
|
10
10
|
methods = tracker.find_call :targets => [:Dir, :File, :IO, :Kernel, :"Net::FTP", :"Net::HTTP", :PStore, :Pathname, :Shell, :YAML], :methods => [:[], :chdir, :chroot, :delete, :entries, :foreach, :glob, :install, :lchmod, :lchown, :link, :load, :load_file, :makedirs, :move, :new, :open, :read, :read_lines, :rename, :rmdir, :safe_unlink, :symlink, :syscopy, :sysopen, :truncate, :unlink]
|
11
11
|
|
12
|
-
|
12
|
+
Brakeman.debug "Finding calls to load()"
|
13
13
|
methods.concat tracker.find_call :target => false, :method => :load
|
14
14
|
|
15
|
-
|
15
|
+
Brakeman.debug "Finding calls using FileUtils"
|
16
16
|
methods.concat tracker.find_call :target => :FileUtils
|
17
17
|
|
18
|
-
|
18
|
+
Brakeman.debug "Processing found calls"
|
19
19
|
methods.each do |call|
|
20
20
|
process_result call
|
21
21
|
end
|
@@ -28,7 +28,7 @@ class Brakeman::CheckMailTo < Brakeman::BaseCheck
|
|
28
28
|
#Check for javascript encoding of mail_to address
|
29
29
|
# mail_to email, name, :encode => :javascript
|
30
30
|
def mail_to_javascript?
|
31
|
-
|
31
|
+
Brakeman.debug "Checking calls to mail_to for javascript encoding"
|
32
32
|
|
33
33
|
tracker.find_call(:target => false, :method => :mail_to).each do |result|
|
34
34
|
call = result[:call]
|
@@ -21,7 +21,7 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
|
|
21
21
|
|
22
22
|
@results = Set.new
|
23
23
|
|
24
|
-
|
24
|
+
Brakeman.debug "Finding possible mass assignment calls on #{models.length} models"
|
25
25
|
calls = tracker.find_call :chained => true, :targets => models, :methods => [:new,
|
26
26
|
:attributes=,
|
27
27
|
:update_attribute,
|
@@ -30,7 +30,7 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
|
|
30
30
|
:create,
|
31
31
|
:create!]
|
32
32
|
|
33
|
-
|
33
|
+
Brakeman.debug "Processing possible mass assignment calls"
|
34
34
|
calls.each do |result|
|
35
35
|
process_result result
|
36
36
|
end
|
@@ -29,7 +29,7 @@ class Brakeman::CheckQuoteTableName < Brakeman::BaseCheck
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def uses_quote_table_name?
|
32
|
-
|
32
|
+
Brakeman.debug "Finding calls to quote_table_name()"
|
33
33
|
|
34
34
|
not tracker.find_call(:target => false, :method => :quote_table_name).empty?
|
35
35
|
end
|
@@ -9,7 +9,7 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
|
|
9
9
|
Brakeman::Checks.add self
|
10
10
|
|
11
11
|
def run_check
|
12
|
-
|
12
|
+
Brakeman.debug "Finding calls to redirect_to()"
|
13
13
|
|
14
14
|
@tracker.find_call(:target => false, :method => :redirect_to).each do |res|
|
15
15
|
process_result res
|
@@ -42,7 +42,7 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
|
|
42
42
|
#which can be used to enable/disable reporting output of method calls which use
|
43
43
|
#user input as arguments.
|
44
44
|
def include_user_input? call
|
45
|
-
|
45
|
+
Brakeman.debug "Checking if call includes user input"
|
46
46
|
|
47
47
|
if tracker.options[:ignore_redirect_to_model] and call? call[3][1] and
|
48
48
|
call[3][1][2] == :new and call[3][1][1]
|
@@ -6,7 +6,7 @@ class Brakeman::CheckSendFile < Brakeman::CheckFileAccess
|
|
6
6
|
Brakeman::Checks.add self
|
7
7
|
|
8
8
|
def run_check
|
9
|
-
|
9
|
+
Brakeman.debug "Finding all calls to send_file()"
|
10
10
|
|
11
11
|
methods = tracker.find_call :target => false, :method => :send_file
|
12
12
|
|
@@ -14,7 +14,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
14
14
|
def run_check
|
15
15
|
@rails_version = tracker.config[:rails_version]
|
16
16
|
|
17
|
-
|
17
|
+
Brakeman.debug "Finding possible SQL calls on models"
|
18
18
|
if tracker.options[:rails3]
|
19
19
|
calls = tracker.find_call :targets => tracker.models.keys,
|
20
20
|
:methods => /^(find.*|first|last|all|where|order|group|having)$/,
|
@@ -25,16 +25,16 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
25
25
|
:chained => true
|
26
26
|
end
|
27
27
|
|
28
|
-
|
28
|
+
Brakeman.debug "Finding possible SQL calls with no target"
|
29
29
|
calls.concat tracker.find_call(:target => nil, :method => /^(find.*|last|first|all|count|sum|average|minumum|maximum|count_by_sql)$/)
|
30
30
|
|
31
|
-
|
31
|
+
Brakeman.debug "Finding possible SQL calls using constantized()"
|
32
32
|
calls.concat tracker.find_call(:method => /^(find.*|last|first|all|count|sum|average|minumum|maximum|count_by_sql)$/).select { |result| constantize_call? result }
|
33
33
|
|
34
|
-
|
34
|
+
Brakeman.debug "Finding calls to named_scope or scope"
|
35
35
|
calls.concat find_scope_calls
|
36
36
|
|
37
|
-
|
37
|
+
Brakeman.debug "Processing possible SQL calls"
|
38
38
|
calls.each do |c|
|
39
39
|
process_result c
|
40
40
|
end
|
@@ -23,7 +23,7 @@ class Brakeman::CheckStripTags < Brakeman::BaseCheck
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def uses_strip_tags?
|
26
|
-
|
26
|
+
Brakeman.debug "Finding calls to strip_tags()"
|
27
27
|
|
28
28
|
not tracker.find_call(:target => false, :method => :strip_tags).empty?
|
29
29
|
end
|
@@ -6,7 +6,7 @@ class Brakeman::CheckTranslateBug < Brakeman::BaseCheck
|
|
6
6
|
Brakeman::Checks.add self
|
7
7
|
|
8
8
|
def run_check
|
9
|
-
if (version_between?('2.3.0', '2.3.99') and tracker.
|
9
|
+
if (version_between?('2.3.0', '2.3.99') and tracker.config[:escape_html]) or
|
10
10
|
version_between?('3.0.0', '3.0.10') or
|
11
11
|
version_between?('3.1.0', '3.1.1')
|
12
12
|
|
@@ -34,7 +34,7 @@ class Brakeman::CheckTranslateBug < Brakeman::BaseCheck
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def uses_translate?
|
37
|
-
|
37
|
+
Brakeman.debug "Finding calls to translate() or t()"
|
38
38
|
|
39
39
|
not tracker.find_call(:target => nil, :methods => [:t, :translate]).empty?
|
40
40
|
end
|
@@ -23,7 +23,7 @@ class Brakeman::CheckWithoutProtection < Brakeman::BaseCheck
|
|
23
23
|
|
24
24
|
@results = Set.new
|
25
25
|
|
26
|
-
|
26
|
+
Brakeman.debug "Finding all mass assignments"
|
27
27
|
calls = tracker.find_call :targets => models, :methods => [:new,
|
28
28
|
:attributes=,
|
29
29
|
:update_attribute,
|
@@ -32,7 +32,7 @@ class Brakeman::CheckWithoutProtection < Brakeman::BaseCheck
|
|
32
32
|
:create,
|
33
33
|
:create!]
|
34
34
|
|
35
|
-
|
35
|
+
Brakeman.debug "Processing all mass assignments"
|
36
36
|
calls.each do |result|
|
37
37
|
process_result result
|
38
38
|
end
|
@@ -87,7 +87,7 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
|
|
87
87
|
method = find_method name, @current_class
|
88
88
|
|
89
89
|
if method.nil?
|
90
|
-
|
90
|
+
Brakeman.debug "[Notice] Could not find filter #{name}"
|
91
91
|
return
|
92
92
|
end
|
93
93
|
|
@@ -207,7 +207,7 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
|
|
207
207
|
when :lit, :str
|
208
208
|
filter[option] = value[1]
|
209
209
|
else
|
210
|
-
|
210
|
+
Brakeman.debug "[Notice] Unknown before_filter value: #{option} => #{value}"
|
211
211
|
end
|
212
212
|
else
|
213
213
|
filter[:all] = true
|
@@ -22,7 +22,7 @@ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
|
|
22
22
|
#s(:class, NAME, PARENT, s(:scope ...))
|
23
23
|
def process_class exp
|
24
24
|
if @controller
|
25
|
-
|
25
|
+
Brakeman.debug "[Notice] Skipping inner class: #{class_name exp[1]}"
|
26
26
|
return ignore
|
27
27
|
end
|
28
28
|
|
@@ -83,7 +83,7 @@ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
|
|
83
83
|
unless Dir.glob("#{@tracker.options[:app_path]}/app/views/layouts/#{name}.html.{erb,haml}").empty?
|
84
84
|
@controller[:layout] = "layouts/#{name}"
|
85
85
|
else
|
86
|
-
|
86
|
+
Brakeman.debug "[Notice] Layout not found: #{name}"
|
87
87
|
end
|
88
88
|
elsif sexp? args[-1] and (args[-1][0] == :nil or args[-1][0] == :false)
|
89
89
|
#layout :false or layout nil
|
@@ -37,7 +37,7 @@ class Brakeman::Rails2ConfigProcessor < Brakeman::BaseProcessor
|
|
37
37
|
target = process target if sexp? target
|
38
38
|
|
39
39
|
if exp[2] == :gem and exp[3][1][1] == "erubis"
|
40
|
-
|
40
|
+
Brakeman.notify "[Notice] Using Erubis for ERB templates"
|
41
41
|
@tracker.config[:erubis] = true
|
42
42
|
end
|
43
43
|
|
@@ -21,10 +21,13 @@ module Brakeman::RenderHelper
|
|
21
21
|
|
22
22
|
#Processes layout
|
23
23
|
def process_layout name = nil
|
24
|
-
|
25
|
-
|
24
|
+
if name.nil? and defined? layout_name
|
25
|
+
name = layout_name
|
26
|
+
end
|
27
|
+
|
28
|
+
return unless name
|
26
29
|
|
27
|
-
process_template
|
30
|
+
process_template name, nil
|
28
31
|
end
|
29
32
|
|
30
33
|
#Determines file name for partial and then processes it
|
@@ -50,7 +53,7 @@ module Brakeman::RenderHelper
|
|
50
53
|
name = name.to_s.gsub(/^\//, "")
|
51
54
|
template = @tracker.templates[name.to_sym]
|
52
55
|
unless template
|
53
|
-
|
56
|
+
Brakeman.debug "[Notice] No such template: #{name}"
|
54
57
|
return
|
55
58
|
end
|
56
59
|
|
@@ -19,7 +19,7 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
|
|
19
19
|
#s(:class, NAME, PARENT, s(:scope ...))
|
20
20
|
def process_class exp
|
21
21
|
if @model
|
22
|
-
|
22
|
+
Brakeman.debug "[Notice] Skipping inner class: #{class_name exp[1]}"
|
23
23
|
ignore
|
24
24
|
else
|
25
25
|
@model = { :name => class_name(exp[1]),
|
@@ -56,6 +56,8 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
|
|
56
56
|
case method
|
57
57
|
when :private, :protected, :public
|
58
58
|
@visibility = method
|
59
|
+
when :attr_accessible
|
60
|
+
@model[:attr_accessible] ||= []
|
59
61
|
else
|
60
62
|
#??
|
61
63
|
end
|
@@ -19,7 +19,7 @@ class Brakeman::OutputProcessor < Ruby2Ruby
|
|
19
19
|
begin
|
20
20
|
super exp if sexp? exp and not exp.empty?
|
21
21
|
rescue Exception => e
|
22
|
-
|
22
|
+
Brakeman.debug "While formatting #{exp}: #{e}\n#{e.backtrace.join("\n")}"
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
data/lib/brakeman/report.rb
CHANGED
data/lib/brakeman/rescanner.rb
CHANGED
@@ -45,7 +45,7 @@ class Brakeman::Rescanner < Brakeman::Scanner
|
|
45
45
|
|
46
46
|
SCAN_ORDER.each do |type|
|
47
47
|
paths_by_type[type].each do |path|
|
48
|
-
|
48
|
+
Brakeman.debug "Rescanning #{path} as #{type}"
|
49
49
|
|
50
50
|
if rescan_file path, type
|
51
51
|
@changes = true
|
@@ -244,4 +244,12 @@ class Brakeman::RescanReport
|
|
244
244
|
def diff
|
245
245
|
@diff ||= @new_results.diff(@old_results)
|
246
246
|
end
|
247
|
+
|
248
|
+
def to_s
|
249
|
+
<<-OUTPUT
|
250
|
+
Total warnings: #{all_warnings.length}
|
251
|
+
Fixed warnings: #{fixed_warnings.length}
|
252
|
+
New warnings: #{new_warnings.length}
|
253
|
+
OUTPUT
|
254
|
+
end
|
247
255
|
end
|
data/lib/brakeman/scanner.rb
CHANGED
@@ -51,23 +51,23 @@ class Brakeman::Scanner
|
|
51
51
|
|
52
52
|
#Process everything in the Rails application
|
53
53
|
def process
|
54
|
-
|
54
|
+
Brakeman.notify "Processing configuration..."
|
55
55
|
process_config
|
56
|
-
|
56
|
+
Brakeman.notify "Processing gems..."
|
57
57
|
process_gems
|
58
|
-
|
58
|
+
Brakeman.notify "Processing initializers..."
|
59
59
|
process_initializers
|
60
|
-
|
60
|
+
Brakeman.notify "Processing libs..."
|
61
61
|
process_libs
|
62
|
-
|
62
|
+
Brakeman.notify "Processing routes... "
|
63
63
|
process_routes
|
64
|
-
|
64
|
+
Brakeman.notify "Processing templates... "
|
65
65
|
process_templates
|
66
|
-
|
66
|
+
Brakeman.notify "Processing models... "
|
67
67
|
process_models
|
68
|
-
|
68
|
+
Brakeman.notify "Processing controllers... "
|
69
69
|
process_controllers
|
70
|
-
|
70
|
+
Brakeman.notify "Indexing call sites... "
|
71
71
|
index_call_sites
|
72
72
|
tracker
|
73
73
|
end
|
@@ -89,7 +89,7 @@ class Brakeman::Scanner
|
|
89
89
|
(File.exists? "#@path/Gemfile" and File.read("#@path/Gemfile").include? "rails_xss")
|
90
90
|
|
91
91
|
tracker.config[:escape_html] = true
|
92
|
-
|
92
|
+
Brakeman.notify "[Notice] Escaping HTML by default"
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
@@ -99,7 +99,7 @@ class Brakeman::Scanner
|
|
99
99
|
end
|
100
100
|
|
101
101
|
rescue Exception => e
|
102
|
-
|
102
|
+
Brakeman.notify "[Notice] Error while processing config/#{file}"
|
103
103
|
tracker.error e.exception(e.message + "\nwhile processing Gemfile"), e.backtrace
|
104
104
|
end
|
105
105
|
|
@@ -115,7 +115,7 @@ class Brakeman::Scanner
|
|
115
115
|
end
|
116
116
|
end
|
117
117
|
rescue Exception => e
|
118
|
-
|
118
|
+
Brakeman.notify "[Notice] Error while processing Gemfile."
|
119
119
|
tracker.error e.exception(e.message + "\nWhile processing Gemfile"), e.backtrace
|
120
120
|
end
|
121
121
|
|
@@ -144,7 +144,7 @@ class Brakeman::Scanner
|
|
144
144
|
#Adds parsed information to tracker.libs.
|
145
145
|
def process_libs
|
146
146
|
if options[:skip_libs]
|
147
|
-
|
147
|
+
Brakeman.notify '[Skipping]'
|
148
148
|
return
|
149
149
|
end
|
150
150
|
|
@@ -153,7 +153,7 @@ class Brakeman::Scanner
|
|
153
153
|
current = 0
|
154
154
|
|
155
155
|
lib_files.each do |f|
|
156
|
-
|
156
|
+
Brakeman.debug "Processing #{f}"
|
157
157
|
if @report_progress
|
158
158
|
$stderr.print " #{current}/#{total} files processed\r"
|
159
159
|
current += 1
|
@@ -183,11 +183,11 @@ class Brakeman::Scanner
|
|
183
183
|
@processor.process_routes parse_ruby(File.read("#@path/config/routes.rb"))
|
184
184
|
rescue Exception => e
|
185
185
|
tracker.error e.exception(e.message + "\nWhile processing routes.rb"), e.backtrace
|
186
|
-
|
186
|
+
Brakeman.notify "[Notice] Error while processing routes - assuming all public controller methods are actions."
|
187
187
|
options[:assume_all_routes] = true
|
188
188
|
end
|
189
189
|
else
|
190
|
-
|
190
|
+
Brakeman.notify "[Notice] No route information found"
|
191
191
|
end
|
192
192
|
end
|
193
193
|
|
@@ -200,7 +200,7 @@ class Brakeman::Scanner
|
|
200
200
|
current = 0
|
201
201
|
|
202
202
|
controller_files.each do |f|
|
203
|
-
|
203
|
+
Brakeman.debug "Processing #{f}"
|
204
204
|
if @report_progress
|
205
205
|
$stderr.print " #{current}/#{total} files processed\r"
|
206
206
|
current += 1
|
@@ -212,7 +212,7 @@ class Brakeman::Scanner
|
|
212
212
|
current = 0
|
213
213
|
total = tracker.controllers.length
|
214
214
|
|
215
|
-
|
215
|
+
Brakeman.notify "Processing data flow in controllers..."
|
216
216
|
|
217
217
|
tracker.controllers.each do |name, controller|
|
218
218
|
if @report_progress
|
@@ -258,7 +258,7 @@ class Brakeman::Scanner
|
|
258
258
|
total = tracker.templates.length
|
259
259
|
count = 0
|
260
260
|
|
261
|
-
|
261
|
+
Brakeman.notify "Processing data flow in templates..."
|
262
262
|
|
263
263
|
tracker.templates.keys.dup.each do |name|
|
264
264
|
if @report_progress
|
data/lib/brakeman/version.rb
CHANGED
data/lib/brakeman/warning.rb
CHANGED
@@ -5,6 +5,8 @@ class Brakeman::Warning
|
|
5
5
|
|
6
6
|
attr_accessor :code, :context, :file, :message
|
7
7
|
|
8
|
+
TEXT_CONFIDENCE = [ "High", "Medium", "Weak" ]
|
9
|
+
|
8
10
|
#+options[:result]+ can be a result from Tracker#find_call. Otherwise, it can be +nil+.
|
9
11
|
def initialize options = {}
|
10
12
|
@view_name = nil
|
@@ -111,4 +113,13 @@ class Brakeman::Warning
|
|
111
113
|
|
112
114
|
@row
|
113
115
|
end
|
116
|
+
|
117
|
+
def to_s
|
118
|
+
output = "(#{TEXT_CONFIDENCE[self.confidence]}) #{self.warning_type} - #{self.message}"
|
119
|
+
output << " near line #{self.line}" if self.line
|
120
|
+
output << " in #{self.file}" if self.file
|
121
|
+
output << ": #{self.format_code}" if self.code
|
122
|
+
|
123
|
+
output
|
124
|
+
end
|
114
125
|
end
|
metadata
CHANGED
@@ -1,127 +1,101 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: brakeman
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 1
|
7
|
-
- 2
|
8
|
-
- 0
|
9
|
-
version: 1.2.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.1
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Justin Collins
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2012-01-20 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
21
15
|
name: activesupport
|
22
|
-
|
23
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: &76221240 !ruby/object:Gem::Requirement
|
24
17
|
none: false
|
25
|
-
requirements:
|
26
|
-
- -
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
|
29
|
-
- 0
|
30
|
-
version: "0"
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
31
22
|
type: :runtime
|
32
|
-
version_requirements: *id001
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: i18n
|
35
23
|
prerelease: false
|
36
|
-
|
24
|
+
version_requirements: *76221240
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: i18n
|
27
|
+
requirement: &76220920 !ruby/object:Gem::Requirement
|
37
28
|
none: false
|
38
|
-
requirements:
|
39
|
-
- -
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
|
42
|
-
- 0
|
43
|
-
version: "0"
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
44
33
|
type: :runtime
|
45
|
-
version_requirements: *id002
|
46
|
-
- !ruby/object:Gem::Dependency
|
47
|
-
name: ruby2ruby
|
48
34
|
prerelease: false
|
49
|
-
|
35
|
+
version_requirements: *76220920
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: ruby2ruby
|
38
|
+
requirement: &76220320 !ruby/object:Gem::Requirement
|
50
39
|
none: false
|
51
|
-
requirements:
|
40
|
+
requirements:
|
52
41
|
- - ~>
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
|
55
|
-
- 1
|
56
|
-
- 2
|
57
|
-
version: "1.2"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '1.2'
|
58
44
|
type: :runtime
|
59
|
-
version_requirements: *id003
|
60
|
-
- !ruby/object:Gem::Dependency
|
61
|
-
name: ruport
|
62
45
|
prerelease: false
|
63
|
-
|
46
|
+
version_requirements: *76220320
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: ruport
|
49
|
+
requirement: &76219720 !ruby/object:Gem::Requirement
|
64
50
|
none: false
|
65
|
-
requirements:
|
51
|
+
requirements:
|
66
52
|
- - ~>
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
|
69
|
-
- 1
|
70
|
-
- 6
|
71
|
-
version: "1.6"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.6'
|
72
55
|
type: :runtime
|
73
|
-
version_requirements: *id004
|
74
|
-
- !ruby/object:Gem::Dependency
|
75
|
-
name: erubis
|
76
56
|
prerelease: false
|
77
|
-
|
57
|
+
version_requirements: *76219720
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: erubis
|
60
|
+
requirement: &76943790 !ruby/object:Gem::Requirement
|
78
61
|
none: false
|
79
|
-
requirements:
|
62
|
+
requirements:
|
80
63
|
- - ~>
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
|
83
|
-
- 2
|
84
|
-
- 6
|
85
|
-
version: "2.6"
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '2.6'
|
86
66
|
type: :runtime
|
87
|
-
version_requirements: *id005
|
88
|
-
- !ruby/object:Gem::Dependency
|
89
|
-
name: haml
|
90
67
|
prerelease: false
|
91
|
-
|
68
|
+
version_requirements: *76943790
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: haml
|
71
|
+
requirement: &76943560 !ruby/object:Gem::Requirement
|
92
72
|
none: false
|
93
|
-
requirements:
|
73
|
+
requirements:
|
94
74
|
- - ~>
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
|
97
|
-
- 3
|
98
|
-
- 0
|
99
|
-
version: "3.0"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '3.0'
|
100
77
|
type: :runtime
|
101
|
-
version_requirements: *id006
|
102
|
-
- !ruby/object:Gem::Dependency
|
103
|
-
name: sass
|
104
78
|
prerelease: false
|
105
|
-
|
79
|
+
version_requirements: *76943560
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: sass
|
82
|
+
requirement: &76943330 !ruby/object:Gem::Requirement
|
106
83
|
none: false
|
107
|
-
requirements:
|
84
|
+
requirements:
|
108
85
|
- - ~>
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
|
111
|
-
- 3
|
112
|
-
- 0
|
113
|
-
version: "3.0"
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '3.0'
|
114
88
|
type: :runtime
|
115
|
-
|
116
|
-
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *76943330
|
91
|
+
description: Brakeman detects security vulnerabilities in Ruby on Rails applications
|
92
|
+
via static analysis.
|
117
93
|
email:
|
118
|
-
executables:
|
94
|
+
executables:
|
119
95
|
- brakeman
|
120
96
|
extensions: []
|
121
|
-
|
122
97
|
extra_rdoc_files: []
|
123
|
-
|
124
|
-
files:
|
98
|
+
files:
|
125
99
|
- bin/brakeman
|
126
100
|
- WARNING_TYPES
|
127
101
|
- FEATURES
|
@@ -194,37 +168,28 @@ files:
|
|
194
168
|
- lib/brakeman/processor.rb
|
195
169
|
- lib/brakeman.rb
|
196
170
|
- lib/brakeman/format/style.css
|
197
|
-
has_rdoc: true
|
198
171
|
homepage: http://brakemanscanner.org
|
199
172
|
licenses: []
|
200
|
-
|
201
173
|
post_install_message:
|
202
174
|
rdoc_options: []
|
203
|
-
|
204
|
-
require_paths:
|
175
|
+
require_paths:
|
205
176
|
- lib
|
206
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
177
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
207
178
|
none: false
|
208
|
-
requirements:
|
209
|
-
- -
|
210
|
-
- !ruby/object:Gem::Version
|
211
|
-
|
212
|
-
|
213
|
-
version: "0"
|
214
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
179
|
+
requirements:
|
180
|
+
- - ! '>='
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: '0'
|
183
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
215
184
|
none: false
|
216
|
-
requirements:
|
217
|
-
- -
|
218
|
-
- !ruby/object:Gem::Version
|
219
|
-
|
220
|
-
- 0
|
221
|
-
version: "0"
|
185
|
+
requirements:
|
186
|
+
- - ! '>='
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: '0'
|
222
189
|
requirements: []
|
223
|
-
|
224
190
|
rubyforge_project:
|
225
|
-
rubygems_version: 1.
|
191
|
+
rubygems_version: 1.8.10
|
226
192
|
signing_key:
|
227
193
|
specification_version: 3
|
228
194
|
summary: Security vulnerability scanner for Ruby on Rails.
|
229
195
|
test_files: []
|
230
|
-
|