brakeman 2.1.0 → 2.1.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/CHANGES +11 -0
- data/README.md +1 -1
- data/bin/brakeman +1 -1
- data/lib/brakeman.rb +6 -6
- data/lib/brakeman/checks/base_check.rb +5 -23
- data/lib/brakeman/checks/check_content_tag.rb +2 -4
- data/lib/brakeman/checks/check_cross_site_scripting.rb +21 -3
- data/lib/brakeman/checks/check_link_to.rb +1 -1
- data/lib/brakeman/checks/check_model_attr_accessible.rb +31 -25
- data/lib/brakeman/parsers/rails2_erubis.rb +1 -1
- data/lib/brakeman/parsers/rails2_xss_plugin_erubis.rb +1 -1
- data/lib/brakeman/parsers/rails3_erubis.rb +1 -1
- data/lib/brakeman/processors/lib/rails3_route_processor.rb +7 -4
- data/lib/brakeman/processors/model_processor.rb +3 -0
- data/lib/brakeman/report/ignore/interactive.rb +1 -1
- data/lib/brakeman/report/report_csv.rb +1 -1
- data/lib/brakeman/report/report_json.rb +1 -1
- data/lib/brakeman/report/report_table.rb +1 -1
- data/lib/brakeman/report/report_tabs.rb +2 -2
- data/lib/brakeman/rescanner.rb +4 -4
- data/lib/brakeman/scanner.rb +3 -3
- data/lib/brakeman/tracker.rb +10 -0
- data/lib/brakeman/util.rb +2 -2
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning_codes.rb +2 -1
- metadata +4 -4
data/CHANGES
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
# 2.1.1
|
2
|
+
|
3
|
+
* New warning code for dangerous attributes in attr_accessible
|
4
|
+
* Do not warn on attr_accessible using roles
|
5
|
+
* More accurate results for model attribute warnings
|
6
|
+
* Use exit code zero with `-z` if all warnings ignored
|
7
|
+
* Respect ignored warnings in rescans
|
8
|
+
* Ignore dynamic controller names in routes
|
9
|
+
* Fix infinite loop when run as rake task (Matthew Shanley)
|
10
|
+
* Respect ignored warnings in tabs format reports
|
11
|
+
|
1
12
|
# 2.1.0
|
2
13
|
|
3
14
|
* Support non-native line endings in Gemfile.lock (Paul Deardorff)
|
data/README.md
CHANGED
@@ -13,7 +13,7 @@ It works with Rails 2.x, 3.x, and 4.x.
|
|
13
13
|
|
14
14
|
There is also a [plugin available](http://brakemanscanner.org/docs/jenkins/) for Jenkins/Hudson.
|
15
15
|
|
16
|
-
For even more continuous testing, try the [Guard plugin](https://github.com/
|
16
|
+
For even more continuous testing, try the [Guard plugin](https://github.com/guard/guard-brakeman).
|
17
17
|
|
18
18
|
# Homepage/News
|
19
19
|
|
data/bin/brakeman
CHANGED
@@ -78,7 +78,7 @@ begin
|
|
78
78
|
tracker = Brakeman.run options.merge(:print_report => true, :quiet => options[:quiet])
|
79
79
|
|
80
80
|
#Return error code if --exit-on-warn is used and warnings were found
|
81
|
-
if options[:exit_on_warn] and not tracker.
|
81
|
+
if options[:exit_on_warn] and not tracker.filtered_warnings.empty?
|
82
82
|
exit Brakeman::Warnings_Found_Exit_Code
|
83
83
|
end
|
84
84
|
end
|
data/lib/brakeman.rb
CHANGED
@@ -153,7 +153,7 @@ module Brakeman
|
|
153
153
|
end
|
154
154
|
end
|
155
155
|
end
|
156
|
-
|
156
|
+
|
157
157
|
def self.get_formats_from_output_format output_format
|
158
158
|
case output_format
|
159
159
|
when :html, :to_html
|
@@ -171,7 +171,7 @@ module Brakeman
|
|
171
171
|
end
|
172
172
|
end
|
173
173
|
private_class_method :get_formats_from_output_format
|
174
|
-
|
174
|
+
|
175
175
|
def self.get_formats_from_output_files output_files
|
176
176
|
output_files.map do |output_file|
|
177
177
|
case output_file
|
@@ -196,7 +196,7 @@ module Brakeman
|
|
196
196
|
def self.list_checks
|
197
197
|
require 'brakeman/scanner'
|
198
198
|
format_length = 30
|
199
|
-
|
199
|
+
|
200
200
|
$stderr.puts "Available Checks:"
|
201
201
|
$stderr.puts "-" * format_length
|
202
202
|
Checks.checks.each do |check|
|
@@ -307,7 +307,7 @@ module Brakeman
|
|
307
307
|
|
308
308
|
tracker
|
309
309
|
end
|
310
|
-
|
310
|
+
|
311
311
|
def self.write_report_to_files tracker, output_files
|
312
312
|
output_files.each_with_index do |output_file, idx|
|
313
313
|
File.open output_file, "w" do |f|
|
@@ -317,7 +317,7 @@ module Brakeman
|
|
317
317
|
end
|
318
318
|
end
|
319
319
|
private_class_method :write_report_to_files
|
320
|
-
|
320
|
+
|
321
321
|
def self.write_report_to_formats tracker, output_formats
|
322
322
|
output_formats.each do |output_format|
|
323
323
|
puts tracker.report.format(output_format)
|
@@ -375,7 +375,7 @@ module Brakeman
|
|
375
375
|
Brakeman::Differ.new(new_results, previous_results).diff
|
376
376
|
end
|
377
377
|
|
378
|
-
def self.
|
378
|
+
def self.load_brakeman_dependency name
|
379
379
|
return if @loaded_dependencies.include? name
|
380
380
|
|
381
381
|
begin
|
@@ -364,7 +364,11 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
364
364
|
if @safe_input_attributes.include? method
|
365
365
|
false
|
366
366
|
elsif call? target and not method.to_s[-1,1] == "?"
|
367
|
-
has_immediate_model?
|
367
|
+
if res = has_immediate_model?(target, out)
|
368
|
+
exp
|
369
|
+
else
|
370
|
+
false
|
371
|
+
end
|
368
372
|
elsif model_name? target
|
369
373
|
exp
|
370
374
|
else
|
@@ -429,28 +433,6 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
429
433
|
end
|
430
434
|
end
|
431
435
|
|
432
|
-
#Finds entire method call chain where +target+ is a target in the chain
|
433
|
-
def find_chain exp, target
|
434
|
-
return unless sexp? exp
|
435
|
-
|
436
|
-
case exp.node_type
|
437
|
-
when :output, :format
|
438
|
-
find_chain exp.value, target
|
439
|
-
when :call
|
440
|
-
if exp == target or include_target? exp, target
|
441
|
-
return exp
|
442
|
-
end
|
443
|
-
else
|
444
|
-
exp.each do |e|
|
445
|
-
if sexp? e
|
446
|
-
res = find_chain e, target
|
447
|
-
return res if res
|
448
|
-
end
|
449
|
-
end
|
450
|
-
nil
|
451
|
-
end
|
452
|
-
end
|
453
|
-
|
454
436
|
#Returns true if +target+ is in +exp+
|
455
437
|
def include_target? exp, target
|
456
438
|
return false unless call? exp
|
@@ -107,12 +107,10 @@ class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
|
|
107
107
|
:link_path => "content_tag"
|
108
108
|
|
109
109
|
elsif not tracker.options[:ignore_model_output] and match = has_immediate_model?(arg)
|
110
|
-
|
111
|
-
|
112
|
-
unless IGNORE_MODEL_METHODS.include? method
|
110
|
+
unless IGNORE_MODEL_METHODS.include? match.method
|
113
111
|
add_result result
|
114
112
|
|
115
|
-
if
|
113
|
+
if likely_model_attribute? match
|
116
114
|
confidence = CONFIDENCE[:high]
|
117
115
|
else
|
118
116
|
confidence = CONFIDENCE[:med]
|
@@ -122,7 +122,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
122
122
|
unless IGNORE_MODEL_METHODS.include? method
|
123
123
|
add_result exp
|
124
124
|
|
125
|
-
if
|
125
|
+
if likely_model_attribute? match
|
126
126
|
confidence = CONFIDENCE[:high]
|
127
127
|
else
|
128
128
|
confidence = CONFIDENCE[:med]
|
@@ -138,12 +138,17 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
138
138
|
warning_code = :xss_to_json
|
139
139
|
end
|
140
140
|
|
141
|
-
code =
|
141
|
+
code = if match == out
|
142
|
+
nil
|
143
|
+
else
|
144
|
+
match
|
145
|
+
end
|
146
|
+
|
142
147
|
warn :template => @current_template,
|
143
148
|
:warning_type => "Cross Site Scripting",
|
144
149
|
:warning_code => warning_code,
|
145
150
|
:message => message,
|
146
|
-
:code =>
|
151
|
+
:code => match,
|
147
152
|
:confidence => confidence,
|
148
153
|
:link_path => link_path
|
149
154
|
end
|
@@ -153,6 +158,19 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
153
158
|
end
|
154
159
|
end
|
155
160
|
|
161
|
+
#Call already involves a model, but might not be acting on a record
|
162
|
+
def likely_model_attribute? exp
|
163
|
+
return false unless call? exp
|
164
|
+
|
165
|
+
method = exp.method
|
166
|
+
|
167
|
+
if MODEL_METHODS.include? method or method.to_s.start_with? "find_by_"
|
168
|
+
true
|
169
|
+
else
|
170
|
+
likely_model_attribute? exp.target
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
156
174
|
#Process an output Sexp
|
157
175
|
def process_output exp
|
158
176
|
process exp.value.dup
|
@@ -82,7 +82,7 @@ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
|
|
82
82
|
return false if IGNORE_MODEL_METHODS.include? method
|
83
83
|
|
84
84
|
confidence = CONFIDENCE[:med]
|
85
|
-
confidence = CONFIDENCE[:high] if
|
85
|
+
confidence = CONFIDENCE[:high] if likely_model_attribute? match
|
86
86
|
warn_xss(result, "Unescaped model attribute in link_to", match, confidence)
|
87
87
|
end
|
88
88
|
|
@@ -1,42 +1,49 @@
|
|
1
1
|
require 'brakeman/checks/base_check'
|
2
2
|
|
3
|
-
# Author: Paul Deardorff (themetric)
|
4
|
-
# Checks models to see if important foreign keys
|
5
|
-
# or attributes are exposed as attr_accessible when
|
6
|
-
# they probably shouldn't be.
|
3
|
+
# Author: Paul Deardorff (themetric)
|
4
|
+
# Checks models to see if important foreign keys
|
5
|
+
# or attributes are exposed as attr_accessible when
|
6
|
+
# they probably shouldn't be.
|
7
7
|
|
8
8
|
class Brakeman::CheckModelAttrAccessible < Brakeman::BaseCheck
|
9
9
|
Brakeman::Checks.add self
|
10
10
|
|
11
11
|
@description = "Reports models which have dangerous attributes defined under the attr_accessible whitelist."
|
12
12
|
|
13
|
-
SUSP_ATTRS =
|
14
|
-
/admin
|
15
|
-
/role
|
16
|
-
/banned
|
17
|
-
:account_id
|
18
|
-
/\S*_id(s?)\z
|
19
|
-
|
13
|
+
SUSP_ATTRS = [
|
14
|
+
[/admin/, CONFIDENCE[:high]], # Very dangerous unless some Rails authorization used
|
15
|
+
[/role/, CONFIDENCE[:med]],
|
16
|
+
[/banned/, CONFIDENCE[:med]],
|
17
|
+
[:account_id, CONFIDENCE[:high]],
|
18
|
+
[/\S*_id(s?)\z/, CONFIDENCE[:low]] # All other foreign keys have weak/low confidence
|
19
|
+
]
|
20
20
|
|
21
21
|
def run_check
|
22
22
|
check_models do |name, model|
|
23
|
-
|
24
|
-
|
23
|
+
model[:attr_accessible].each do |attribute|
|
24
|
+
next if role_limited? model, attribute
|
25
|
+
|
25
26
|
SUSP_ATTRS.each do |susp_attr, confidence|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
36
|
-
end
|
27
|
+
if susp_attr.is_a?(Regexp) and susp_attr =~ attribute.to_s or susp_attr == attribute
|
28
|
+
warn :model => name,
|
29
|
+
:file => model[:file],
|
30
|
+
:warning_type => "Mass Assignment",
|
31
|
+
:warning_code => :dangerous_attr_accessible,
|
32
|
+
:message => "Potentially dangerous attribute #{attribute} available for mass assignment.",
|
33
|
+
:confidence => confidence
|
34
|
+
break # Prevent from matching single attr multiple times
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
41
|
+
def role_limited? model, attribute
|
42
|
+
role_accessible = model[:options][:role_accessible]
|
43
|
+
return if role_accessible.nil?
|
44
|
+
role_accessible.include? attribute
|
45
|
+
end
|
46
|
+
|
40
47
|
def check_models
|
41
48
|
tracker.models.each do |name, model|
|
42
49
|
if !model[:attr_accessible].nil?
|
@@ -44,5 +51,4 @@ class Brakeman::CheckModelAttrAccessible < Brakeman::BaseCheck
|
|
44
51
|
end
|
45
52
|
end
|
46
53
|
end
|
47
|
-
|
48
54
|
end
|
@@ -255,13 +255,16 @@ class Brakeman::Rails3RoutesProcessor < Brakeman::BaseProcessor
|
|
255
255
|
end
|
256
256
|
|
257
257
|
def process_controller_block exp
|
258
|
-
|
258
|
+
if string? exp or symbol? exp
|
259
|
+
self.current_controller = exp.block_call.first_arg.value
|
259
260
|
|
260
|
-
|
261
|
-
|
261
|
+
in_controller_block do
|
262
|
+
process exp[-1] if exp[-1]
|
263
|
+
end
|
264
|
+
|
265
|
+
@current_controller = nil
|
262
266
|
end
|
263
267
|
|
264
|
-
@current_controller = nil
|
265
268
|
exp
|
266
269
|
end
|
267
270
|
|
@@ -2,10 +2,10 @@
|
|
2
2
|
#https://github.com/presidentbeef/brakeman-jenkins-plugin
|
3
3
|
class Brakeman::Report::Tabs < Brakeman::Report::Base
|
4
4
|
def generate_report
|
5
|
-
[[:
|
5
|
+
[[:generic_warnings, "General"], [:controller_warnings, "Controller"],
|
6
6
|
[:model_warnings, "Model"], [:template_warnings, "Template"]].map do |meth, category|
|
7
7
|
|
8
|
-
|
8
|
+
self.send(meth).map do |w|
|
9
9
|
line = w.line || 0
|
10
10
|
w.warning_type.gsub!(/[^\w\s]/, ' ')
|
11
11
|
"#{warning_file(w, :absolute)}\t#{line}\t#{w.warning_type}\t#{category}\t#{w.format_message}\t#{TEXT_CONFIDENCE[w.confidence]}"
|
data/lib/brakeman/rescanner.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'brakeman/scanner'
|
2
2
|
require 'terminal-table'
|
3
3
|
require 'brakeman/util'
|
4
|
+
require 'brakeman/differ'
|
4
5
|
|
5
6
|
#Class for rescanning changed files after an initial scan
|
6
7
|
class Brakeman::Rescanner < Brakeman::Scanner
|
@@ -13,7 +14,7 @@ class Brakeman::Rescanner < Brakeman::Scanner
|
|
13
14
|
super(options, processor)
|
14
15
|
|
15
16
|
@paths = changed_files.map {|f| @app_tree.expand_path(f) }
|
16
|
-
@old_results = tracker.
|
17
|
+
@old_results = tracker.filtered_warnings #Old warnings from previous scan
|
17
18
|
@changes = nil #True if files had to be rescanned
|
18
19
|
@reindex = Set.new
|
19
20
|
end
|
@@ -367,7 +368,6 @@ class Brakeman::RescanReport
|
|
367
368
|
def initialize old_results, tracker
|
368
369
|
@tracker = tracker
|
369
370
|
@old_results = old_results
|
370
|
-
@new_results = tracker.checks
|
371
371
|
@all_warnings = nil
|
372
372
|
@diff = nil
|
373
373
|
end
|
@@ -379,7 +379,7 @@ class Brakeman::RescanReport
|
|
379
379
|
|
380
380
|
#Returns an array of all warnings found
|
381
381
|
def all_warnings
|
382
|
-
@all_warnings ||=
|
382
|
+
@all_warnings ||= @tracker.filtered_warnings
|
383
383
|
end
|
384
384
|
|
385
385
|
#Returns an array of warnings which were in the old report but are not in the
|
@@ -401,7 +401,7 @@ class Brakeman::RescanReport
|
|
401
401
|
|
402
402
|
#Returns a hash of arrays for :new and :fixed warnings
|
403
403
|
def diff
|
404
|
-
@diff ||=
|
404
|
+
@diff ||= Brakeman::Differ.new(all_warnings, @old_results).diff
|
405
405
|
end
|
406
406
|
|
407
407
|
#Returns an array of warnings which were in the old report and the new report
|
data/lib/brakeman/scanner.rb
CHANGED
@@ -282,14 +282,14 @@ class Brakeman::Scanner
|
|
282
282
|
|
283
283
|
parsed = parse_ruby src
|
284
284
|
elsif type == :haml
|
285
|
-
Brakeman.
|
286
|
-
Brakeman.
|
285
|
+
Brakeman.load_brakeman_dependency 'haml'
|
286
|
+
Brakeman.load_brakeman_dependency 'sass'
|
287
287
|
|
288
288
|
src = Haml::Engine.new(text,
|
289
289
|
:escape_html => !!tracker.config[:escape_html]).precompiled
|
290
290
|
parsed = parse_ruby src
|
291
291
|
elsif type == :slim
|
292
|
-
Brakeman.
|
292
|
+
Brakeman.load_brakeman_dependency 'slim'
|
293
293
|
|
294
294
|
src = Slim::Template.new(:disable_capture => true,
|
295
295
|
:generator => Temple::Generators::RailsOutputBuffer) { text }.precompiled_template
|
data/lib/brakeman/tracker.rb
CHANGED
@@ -156,6 +156,16 @@ class Brakeman::Tracker
|
|
156
156
|
self.checks.all_warnings
|
157
157
|
end
|
158
158
|
|
159
|
+
def filtered_warnings
|
160
|
+
if self.ignored_filter
|
161
|
+
self.warnings.reject do |w|
|
162
|
+
self.ignored_filter.ignored? w
|
163
|
+
end
|
164
|
+
else
|
165
|
+
self.warnings
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
159
169
|
def index_call_sites
|
160
170
|
finder = Brakeman::FindAllCalls.new self
|
161
171
|
|
data/lib/brakeman/util.rb
CHANGED
@@ -385,7 +385,7 @@ module Brakeman::Util
|
|
385
385
|
|
386
386
|
def truncate_table str
|
387
387
|
@terminal_width ||= if $stdin && $stdin.tty?
|
388
|
-
Brakeman.
|
388
|
+
Brakeman.load_brakeman_dependency 'highline'
|
389
389
|
::HighLine.new.terminal_size[0]
|
390
390
|
else
|
391
391
|
80
|
@@ -403,7 +403,7 @@ module Brakeman::Util
|
|
403
403
|
|
404
404
|
# rely on Terminal::Table to build the structure, extract the data out in CSV format
|
405
405
|
def table_to_csv table
|
406
|
-
Brakeman.
|
406
|
+
Brakeman.load_brakeman_dependency 'terminal-table'
|
407
407
|
output = CSV.generate_line(table.headings.cells.map{|cell| cell.to_s.strip})
|
408
408
|
table.rows.each do |row|
|
409
409
|
output << CSV.generate_line(row.cells.map{|cell| cell.to_s.strip})
|
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: 9
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 2.1.
|
9
|
+
- 1
|
10
|
+
version: 2.1.1
|
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: 2013-
|
18
|
+
date: 2013-08-21 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: ruby_parser
|