brakeman 2.1.0 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|