brakeman 1.9.5 → 2.0.0.pre2
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.
- checksums.yaml +4 -4
- data/CHANGES +27 -0
- data/README.md +5 -2
- data/bin/brakeman +20 -15
- data/lib/brakeman.rb +106 -80
- data/lib/brakeman/app_tree.rb +22 -11
- data/lib/brakeman/call_index.rb +4 -4
- data/lib/brakeman/checks/base_check.rb +33 -5
- data/lib/brakeman/checks/check_basic_auth.rb +2 -1
- data/lib/brakeman/checks/check_content_tag.rb +8 -29
- data/lib/brakeman/checks/check_cross_site_scripting.rb +10 -19
- data/lib/brakeman/checks/check_deserialize.rb +57 -0
- data/lib/brakeman/checks/check_execute.rb +3 -11
- data/lib/brakeman/checks/check_file_access.rb +1 -14
- data/lib/brakeman/checks/check_forgery_setting.rb +5 -4
- data/lib/brakeman/checks/check_link_to.rb +4 -15
- data/lib/brakeman/checks/check_link_to_href.rb +1 -8
- data/lib/brakeman/checks/check_mass_assignment.rb +6 -2
- data/lib/brakeman/checks/check_model_attributes.rb +1 -0
- data/lib/brakeman/checks/check_model_serialize.rb +2 -1
- data/lib/brakeman/checks/check_render.rb +2 -15
- data/lib/brakeman/checks/check_select_tag.rb +1 -1
- data/lib/brakeman/checks/check_select_vulnerability.rb +2 -2
- data/lib/brakeman/checks/check_send.rb +3 -0
- data/lib/brakeman/checks/check_session_settings.rb +2 -3
- data/lib/brakeman/checks/check_skip_before_filter.rb +5 -2
- data/lib/brakeman/checks/check_sql.rb +59 -50
- data/lib/brakeman/checks/check_symbol_dos.rb +5 -14
- data/lib/brakeman/checks/check_unsafe_reflection.rb +2 -15
- data/lib/brakeman/options.rb +14 -9
- data/lib/brakeman/processors/controller_alias_processor.rb +4 -10
- data/lib/brakeman/processors/controller_processor.rb +53 -14
- data/lib/brakeman/processors/lib/find_all_calls.rb +40 -40
- data/lib/brakeman/processors/lib/processor_helper.rb +5 -1
- data/lib/brakeman/processors/lib/rails3_config_processor.rb +8 -0
- data/lib/brakeman/processors/output_processor.rb +23 -1
- data/lib/brakeman/report.rb +28 -14
- data/lib/brakeman/scanner.rb +5 -3
- data/lib/brakeman/tracker.rb +7 -7
- data/lib/brakeman/util.rb +5 -3
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +12 -9
- data/lib/ruby_parser/bm_sexp.rb +5 -1
- data/lib/tasks/brakeman.rake +10 -0
- metadata +11 -9
- data/lib/brakeman/checks/check_yaml_load.rb +0 -55
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA512:
|
3
|
-
|
4
|
-
|
3
|
+
data.tar.gz: 0fa96dca9b41558e7db8c55a2ec2a2e4dc95fc79afba243d0e656fe0c120fbe5b8c71c6c2216a4d27036efc5a57db9cd9661d2a2952e6b92f4c98777a4e26173
|
4
|
+
metadata.gz: 6ed79f61f202f946c7c417f2945ae57ebba267a4e4f46e45eb07fd0eddebe947046d907ff18775bb942073ec3ea00a2a8a9ccaf9b1b31e66d2afa8d62a95166b
|
5
5
|
SHA1:
|
6
|
-
|
7
|
-
|
6
|
+
data.tar.gz: ca68abc07bbc2bafc9af02bcabab84d4756447b7
|
7
|
+
metadata.gz: fad7234ee850e69edbe9bacf2783605edbcf7b64
|
data/CHANGES
CHANGED
@@ -1,3 +1,30 @@
|
|
1
|
+
# 2.0.0
|
2
|
+
|
3
|
+
* Add `--only-files` option to specify files/paths to scan (Ian Ehlert)
|
4
|
+
* Add Marshal/CSV deserialization check
|
5
|
+
* Combine deserialization checks into single check
|
6
|
+
* Avoid duplicate "Dangerous Send" and "Unsafe Reflection" warnings
|
7
|
+
* Avoid duplicate results for Symbol DoS check
|
8
|
+
* Medium confidence for mass assignment to attr_protected models
|
9
|
+
* Remove "timestamp" key from JSON reports
|
10
|
+
* Remove deprecated config file locations
|
11
|
+
* Only treat classes with names containing `Controller` like controllers
|
12
|
+
* Better handling of classes nested inside controllers
|
13
|
+
* Better handling of controller classes nested in classes/modules
|
14
|
+
* Handle `->` lambdas with no arguments
|
15
|
+
* Handle explicit block argument destructuring
|
16
|
+
* Skip Rails config options that are real objects
|
17
|
+
* Detect Rails 3 JSON escape config option
|
18
|
+
* Much better tracking of warning file names
|
19
|
+
* Fix errors when using `--separate-models` (Noah Davis)
|
20
|
+
* Fix fingerprint generation to actually use the file path
|
21
|
+
* Fix text report console output in JRuby
|
22
|
+
* Fix false positives on `Model#id`
|
23
|
+
* Fix false positives on `params.to_json`
|
24
|
+
* Fix model path guesses to use "models/" instead of "controllers/"
|
25
|
+
* Clean up SQL CVE warning messages
|
26
|
+
* Use exceptions instead of abort in brakeman lib
|
27
|
+
|
1
28
|
# 1.9.5
|
2
29
|
|
3
30
|
* Add check for unsafe symbol creation
|
data/README.md
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|

|
2
2
|
|
3
|
-
[](https://travis-ci.org/presidentbeef/brakeman)
|
5
|
+
[](https://codeclimate.com/github/presidentbeef/brakeman)
|
4
7
|
|
5
8
|
# Brakeman
|
6
9
|
|
7
10
|
Brakeman is a static analysis tool which checks Ruby on Rails applications for security vulnerabilities.
|
8
11
|
|
9
12
|
It targets Rails versions 2.x and 3.x.
|
10
|
-
|
13
|
+
|
11
14
|
There is also a [plugin available](http://brakemanscanner.org/docs/jenkins/) for Jenkins/Hudson.
|
12
15
|
|
13
16
|
For even more continuous testing, try the [Guard plugin](https://github.com/oreoshake/guard-brakeman).
|
data/bin/brakeman
CHANGED
@@ -52,22 +52,27 @@ trap("INT") do
|
|
52
52
|
exit!
|
53
53
|
end
|
54
54
|
|
55
|
-
if options[:
|
56
|
-
|
57
|
-
puts MultiJson.dump(vulns, :pretty => true)
|
58
|
-
|
59
|
-
if options[:exit_on_warn] and (vulns[:new].count + vulns[:fixed].count > 0)
|
60
|
-
exit Brakeman::Warnings_Found_Exit_Code
|
61
|
-
end
|
62
|
-
else
|
63
|
-
#Run scan and output a report
|
64
|
-
tracker = Brakeman.run options.merge(:print_report => true, :quiet => options[:quiet])
|
65
|
-
|
66
|
-
#Return error code if --exit-on-warn is used and warnings were found
|
67
|
-
if options[:exit_on_warn] and not tracker.checks.all_warnings.empty?
|
68
|
-
exit Brakeman::Warnings_Found_Exit_Code
|
69
|
-
end
|
55
|
+
if options[:quiet].nil?
|
56
|
+
options[:quiet] = :command_line
|
70
57
|
end
|
71
58
|
|
59
|
+
begin
|
60
|
+
if options[:previous_results_json]
|
61
|
+
vulns = Brakeman.compare options.merge(:quiet => options[:quiet])
|
62
|
+
puts MultiJson.dump(vulns, :pretty => true)
|
72
63
|
|
64
|
+
if options[:exit_on_warn] and (vulns[:new].count + vulns[:fixed].count > 0)
|
65
|
+
exit Brakeman::Warnings_Found_Exit_Code
|
66
|
+
end
|
67
|
+
else
|
68
|
+
#Run scan and output a report
|
69
|
+
tracker = Brakeman.run options.merge(:print_report => true, :quiet => options[:quiet])
|
73
70
|
|
71
|
+
#Return error code if --exit-on-warn is used and warnings were found
|
72
|
+
if options[:exit_on_warn] and not tracker.checks.all_warnings.empty?
|
73
|
+
exit Brakeman::Warnings_Found_Exit_Code
|
74
|
+
end
|
75
|
+
end
|
76
|
+
rescue Brakeman::Scanner::NoApplication => e
|
77
|
+
$stderr.puts e.message
|
78
|
+
end
|
data/lib/brakeman.rb
CHANGED
@@ -40,7 +40,7 @@ module Brakeman
|
|
40
40
|
# * :safe_methods - array of methods to consider safe
|
41
41
|
# * :skip_libs - do not process lib/ directory (default: false)
|
42
42
|
# * :skip_checks - checks not to run (run all if not specified)
|
43
|
-
# * :
|
43
|
+
# * :absolute_paths - show absolute path of each file (default: false)
|
44
44
|
# * :summary_only - only output summary section of report
|
45
45
|
# (does not apply to tabs format)
|
46
46
|
#
|
@@ -63,56 +63,51 @@ module Brakeman
|
|
63
63
|
options = { :app_path => options }
|
64
64
|
end
|
65
65
|
|
66
|
-
options[:
|
67
|
-
|
68
|
-
|
66
|
+
if options[:quiet] == :command_line
|
67
|
+
command_line = true
|
68
|
+
options.delete :quiet
|
69
|
+
end
|
69
70
|
|
70
|
-
options =
|
71
|
+
options = default_options.merge(load_options(options[:config_file], options[:quiet])).merge(options)
|
71
72
|
|
72
|
-
|
73
|
+
if options[:quiet].nil? and not command_line
|
74
|
+
options[:quiet] = true
|
75
|
+
end
|
73
76
|
|
74
|
-
options =
|
77
|
+
options[:app_path] = File.expand_path(options[:app_path])
|
75
78
|
options[:output_formats] = get_output_formats options
|
76
79
|
|
77
80
|
options
|
78
81
|
end
|
79
82
|
|
80
|
-
DEPRECATED_CONFIG_FILES = [
|
81
|
-
File.expand_path("./config.yaml"),
|
82
|
-
File.expand_path("~/.brakeman/config.yaml"),
|
83
|
-
File.expand_path("/etc/brakeman/config.yaml"),
|
84
|
-
"#{File.expand_path(File.dirname(__FILE__))}/../lib/config.yaml"
|
85
|
-
]
|
86
|
-
|
87
83
|
CONFIG_FILES = [
|
88
84
|
File.expand_path("./config/brakeman.yml"),
|
89
85
|
File.expand_path("~/.brakeman/config.yml"),
|
90
|
-
File.expand_path("/etc/brakeman/config.yml")
|
86
|
+
File.expand_path("/etc/brakeman/config.yml")
|
91
87
|
]
|
92
88
|
|
93
89
|
#Load options from YAML file
|
94
|
-
def self.load_options custom_location
|
90
|
+
def self.load_options custom_location, quiet
|
95
91
|
#Load configuration file
|
96
92
|
if config = config_file(custom_location)
|
97
93
|
options = YAML.load_file config
|
98
94
|
options.each { |k, v| options[k] = Set.new v if v.is_a? Array }
|
99
|
-
|
95
|
+
|
96
|
+
# notify if options[:quiet] and quiet is nil||false
|
97
|
+
notify "[Notice] Using configuration in #{config}" unless (options[:quiet] || quiet)
|
100
98
|
options
|
101
99
|
else
|
102
100
|
{}
|
103
101
|
end
|
104
102
|
end
|
105
103
|
|
106
|
-
def self.config_file
|
107
|
-
|
108
|
-
|
109
|
-
end
|
110
|
-
supported_locations = [File.expand_path(custom_location || "")] + DEPRECATED_CONFIG_FILES + CONFIG_FILES
|
111
|
-
supported_locations.detect{|f| File.file?(f) }
|
104
|
+
def self.config_file custom_location = nil
|
105
|
+
supported_locations = [File.expand_path(custom_location || "")] + CONFIG_FILES
|
106
|
+
supported_locations.detect {|f| File.file?(f) }
|
112
107
|
end
|
113
108
|
|
114
109
|
#Default set of options
|
115
|
-
def self.
|
110
|
+
def self.default_options
|
116
111
|
{ :assume_all_routes => true,
|
117
112
|
:skip_checks => Set.new,
|
118
113
|
:check_arguments => true,
|
@@ -126,7 +121,6 @@ module Brakeman
|
|
126
121
|
:message_limit => 100,
|
127
122
|
:parallel_checks => true,
|
128
123
|
:relative_path => false,
|
129
|
-
:quiet => true,
|
130
124
|
:report_progress => true,
|
131
125
|
:html_style => "#{File.expand_path(File.dirname(__FILE__))}/brakeman/format/style.css"
|
132
126
|
}
|
@@ -140,61 +134,80 @@ module Brakeman
|
|
140
134
|
raise ArgumentError, "Cannot specify output format if multiple output files specified"
|
141
135
|
end
|
142
136
|
if options[:output_format]
|
143
|
-
[
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
]
|
137
|
+
get_formats_from_output_format options[:output_format]
|
138
|
+
elsif options[:output_files]
|
139
|
+
get_formats_from_output_files options[:output_files]
|
140
|
+
else
|
141
|
+
return [:to_s]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.get_formats_from_output_format output_format
|
146
|
+
case output_format
|
147
|
+
when :html, :to_html
|
148
|
+
[:to_html]
|
149
|
+
when :csv, :to_csv
|
150
|
+
[:to_csv]
|
151
|
+
when :pdf, :to_pdf
|
152
|
+
[:to_pdf]
|
153
|
+
when :tabs, :to_tabs
|
154
|
+
[:to_tabs]
|
155
|
+
when :json, :to_json
|
156
|
+
[:to_json]
|
159
157
|
else
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
158
|
+
[:to_s]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
private_class_method :get_formats_from_output_format
|
162
|
+
|
163
|
+
def self.get_formats_from_output_files output_files
|
164
|
+
output_files.map do |output_file|
|
165
|
+
case output_file
|
166
|
+
when /\.html$/i
|
167
|
+
:to_html
|
168
|
+
when /\.csv$/i
|
169
|
+
:to_csv
|
170
|
+
when /\.pdf$/i
|
171
|
+
:to_pdf
|
172
|
+
when /\.tabs$/i
|
173
|
+
:to_tabs
|
174
|
+
when /\.json$/i
|
175
|
+
:to_json
|
176
|
+
else
|
177
|
+
:to_s
|
176
178
|
end
|
177
179
|
end
|
178
180
|
end
|
181
|
+
private_class_method :get_formats_from_output_files
|
179
182
|
|
180
183
|
#Output list of checks (for `-k` option)
|
181
184
|
def self.list_checks
|
182
185
|
require 'brakeman/scanner'
|
186
|
+
format_length = 30
|
187
|
+
|
183
188
|
$stderr.puts "Available Checks:"
|
184
|
-
$stderr.puts "-" *
|
185
|
-
|
186
|
-
|
187
|
-
|
189
|
+
$stderr.puts "-" * format_length
|
190
|
+
Checks.checks.each do |check|
|
191
|
+
$stderr.printf("%-#{format_length}s%s\n", check.name, check.description)
|
192
|
+
end
|
188
193
|
end
|
189
194
|
|
190
195
|
#Installs Rake task for running Brakeman,
|
191
196
|
#which basically means copying `lib/brakeman/brakeman.rake` to
|
192
197
|
#`lib/tasks/brakeman.rake` in the current Rails application.
|
193
|
-
def self.install_rake_task
|
194
|
-
if
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
+
def self.install_rake_task install_path = nil
|
199
|
+
if install_path
|
200
|
+
rake_path = File.join(install_path, "Rakefile")
|
201
|
+
task_path = File.join(install_path, "lib", "tasks", "brakeman.rake")
|
202
|
+
else
|
203
|
+
rake_path = "Rakefile"
|
204
|
+
task_path = File.join("lib", "tasks", "brakeman.rake")
|
205
|
+
end
|
206
|
+
|
207
|
+
if not File.exists? rake_path
|
208
|
+
raise RakeInstallError, "No Rakefile detected"
|
209
|
+
elsif File.exists? task_path
|
210
|
+
raise RakeInstallError, "Task already exists"
|
198
211
|
end
|
199
212
|
|
200
213
|
require 'fileutils'
|
@@ -206,13 +219,13 @@ module Brakeman
|
|
206
219
|
|
207
220
|
path = File.expand_path(File.dirname(__FILE__))
|
208
221
|
|
209
|
-
FileUtils.cp "#{path}/brakeman/brakeman.rake",
|
222
|
+
FileUtils.cp "#{path}/brakeman/brakeman.rake", task_path
|
210
223
|
|
211
|
-
if File.exists?
|
212
|
-
notify "Task created in
|
224
|
+
if File.exists? task_path
|
225
|
+
notify "Task created in #{task_path}"
|
213
226
|
notify "Usage: rake brakeman:run[output_file]"
|
214
227
|
else
|
215
|
-
|
228
|
+
raise RakeInstallError, "Could not create task"
|
216
229
|
end
|
217
230
|
end
|
218
231
|
|
@@ -251,7 +264,7 @@ module Brakeman
|
|
251
264
|
begin
|
252
265
|
require 'brakeman/scanner'
|
253
266
|
rescue LoadError
|
254
|
-
|
267
|
+
raise NoBrakemanError, "Cannot find lib/ directory."
|
255
268
|
end
|
256
269
|
|
257
270
|
#Start scanning
|
@@ -270,22 +283,32 @@ module Brakeman
|
|
270
283
|
if options[:output_files]
|
271
284
|
notify "Generating report..."
|
272
285
|
|
273
|
-
options[:output_files]
|
274
|
-
File.open output_file, "w" do |f|
|
275
|
-
f.write tracker.report.send(options[:output_formats][idx])
|
276
|
-
end
|
277
|
-
notify "Report saved in '#{output_file}'"
|
278
|
-
end
|
286
|
+
write_report_to_files tracker, options[:output_files]
|
279
287
|
elsif options[:print_report]
|
280
288
|
notify "Generating report..."
|
281
289
|
|
282
|
-
options[:output_formats]
|
283
|
-
puts tracker.report.send(output_format)
|
284
|
-
end
|
290
|
+
write_report_to_formats tracker, options[:output_formats]
|
285
291
|
end
|
286
292
|
|
287
293
|
tracker
|
288
294
|
end
|
295
|
+
|
296
|
+
def self.write_report_to_files tracker, output_files
|
297
|
+
output_files.each_with_index do |output_file, idx|
|
298
|
+
File.open output_file, "w" do |f|
|
299
|
+
f.write tracker.report.format(output_file)
|
300
|
+
end
|
301
|
+
notify "Report saved in '#{output_file}'"
|
302
|
+
end
|
303
|
+
end
|
304
|
+
private_class_method :write_report_to_files
|
305
|
+
|
306
|
+
def self.write_report_to_formats tracker, output_formats
|
307
|
+
output_formats.each do |output_format|
|
308
|
+
puts tracker.report.format(output_format)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
private_class_method :write_report_to_formats
|
289
312
|
|
290
313
|
#Rescan a subset of files in a Rails application.
|
291
314
|
#
|
@@ -336,4 +359,7 @@ module Brakeman
|
|
336
359
|
|
337
360
|
Brakeman::Differ.new(new_results, previous_results).diff
|
338
361
|
end
|
362
|
+
|
363
|
+
class RakeInstallError < RuntimeError; end
|
364
|
+
class NoBrakemanError < RuntimeError; end
|
339
365
|
end
|
data/lib/brakeman/app_tree.rb
CHANGED
@@ -8,17 +8,20 @@ module Brakeman
|
|
8
8
|
root = options[:app_path]
|
9
9
|
|
10
10
|
# Convert files into Regexp for matching
|
11
|
+
init_options = {}
|
11
12
|
if options[:skip_files]
|
12
|
-
|
13
|
-
new(root, Regexp.new(list))
|
14
|
-
else
|
15
|
-
new(root)
|
13
|
+
init_options[:skip_files] = Regexp.new("(?:" << options[:skip_files].map { |f| Regexp.escape f }.join("|") << ")$")
|
16
14
|
end
|
15
|
+
if options[:only_files]
|
16
|
+
init_options[:only_files] = Regexp.new("(?:" << options[:only_files].map { |f| Regexp.escape f }.join("|") << ")")
|
17
|
+
end
|
18
|
+
new(root, init_options)
|
17
19
|
end
|
18
20
|
|
19
|
-
def initialize(root,
|
21
|
+
def initialize(root, init_options = {})
|
20
22
|
@root = root
|
21
|
-
@skip_files = skip_files
|
23
|
+
@skip_files = init_options[:skip_files]
|
24
|
+
@only_files = init_options[:only_files]
|
22
25
|
end
|
23
26
|
|
24
27
|
def expand_path(path)
|
@@ -76,14 +79,22 @@ module Brakeman
|
|
76
79
|
def find_paths(directory, extensions = "*.rb")
|
77
80
|
pattern = @root + "/#{directory}/**/#{extensions}"
|
78
81
|
|
79
|
-
Dir.glob(pattern).sort
|
80
|
-
|
81
|
-
|
82
|
+
select_files(Dir.glob(pattern).sort)
|
83
|
+
end
|
84
|
+
|
85
|
+
def select_files(paths)
|
86
|
+
paths = select_only_files(paths)
|
87
|
+
reject_skipped_files(paths)
|
88
|
+
end
|
89
|
+
|
90
|
+
def select_only_files(paths)
|
91
|
+
return paths unless @only_files
|
92
|
+
paths.select { |f| @only_files.match f }
|
82
93
|
end
|
83
94
|
|
84
95
|
def reject_skipped_files(paths)
|
85
|
-
return unless @skip_files
|
86
|
-
paths.reject
|
96
|
+
return paths unless @skip_files
|
97
|
+
paths.reject { |f| @skip_files.match f }
|
87
98
|
end
|
88
99
|
|
89
100
|
end
|