brakeman 1.2.0 → 1.2.1
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 +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
|
-
|