brakeman 3.0.5 → 3.1.0
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 +19 -0
- data/README.md +3 -13
- data/lib/brakeman.rb +3 -0
- data/lib/brakeman/checks/base_check.rb +19 -47
- data/lib/brakeman/checks/check_basic_auth.rb +3 -3
- data/lib/brakeman/checks/check_cross_site_scripting.rb +26 -12
- data/lib/brakeman/checks/check_default_routes.rb +1 -1
- data/lib/brakeman/checks/check_detailed_exceptions.rb +2 -2
- data/lib/brakeman/checks/check_evaluation.rb +3 -0
- data/lib/brakeman/checks/check_execute.rb +3 -3
- data/lib/brakeman/checks/check_file_disclosure.rb +2 -2
- data/lib/brakeman/checks/check_forgery_setting.rb +9 -12
- data/lib/brakeman/checks/check_header_dos.rb +1 -1
- data/lib/brakeman/checks/check_i18n_xss.rb +2 -2
- data/lib/brakeman/checks/check_jruby_xml.rb +1 -1
- data/lib/brakeman/checks/check_json_encoding.rb +1 -1
- data/lib/brakeman/checks/check_json_parsing.rb +3 -3
- data/lib/brakeman/checks/check_link_to.rb +1 -1
- data/lib/brakeman/checks/check_link_to_href.rb +9 -2
- data/lib/brakeman/checks/check_mass_assignment.rb +5 -2
- data/lib/brakeman/checks/check_model_attr_accessible.rb +4 -4
- data/lib/brakeman/checks/check_model_attributes.rb +7 -7
- data/lib/brakeman/checks/check_model_serialize.rb +6 -6
- data/lib/brakeman/checks/check_nested_attributes.rb +2 -2
- data/lib/brakeman/checks/check_number_to_currency.rb +2 -2
- data/lib/brakeman/checks/check_quote_table_name.rb +1 -1
- data/lib/brakeman/checks/check_redirect.rb +2 -10
- data/lib/brakeman/checks/check_render.rb +1 -1
- data/lib/brakeman/checks/check_render_dos.rb +1 -1
- data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +1 -1
- data/lib/brakeman/checks/check_sanitize_methods.rb +1 -1
- 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_session_settings.rb +1 -2
- data/lib/brakeman/checks/check_simple_format.rb +2 -2
- data/lib/brakeman/checks/check_single_quotes.rb +3 -3
- data/lib/brakeman/checks/check_skip_before_filter.rb +5 -7
- data/lib/brakeman/checks/check_sql.rb +10 -14
- data/lib/brakeman/checks/check_sql_cves.rb +4 -4
- data/lib/brakeman/checks/check_ssl_verify.rb +27 -9
- data/lib/brakeman/checks/check_strip_tags.rb +5 -5
- data/lib/brakeman/checks/check_symbol_dos_cve.rb +1 -1
- data/lib/brakeman/checks/check_translate_bug.rb +3 -4
- data/lib/brakeman/checks/check_unscoped_find.rb +1 -1
- data/lib/brakeman/checks/check_validation_regex.rb +2 -2
- data/lib/brakeman/checks/check_xml_dos.rb +1 -1
- data/lib/brakeman/checks/check_yaml_parsing.rb +1 -1
- data/lib/brakeman/file_parser.rb +1 -0
- data/lib/brakeman/parsers/template_parser.rb +6 -5
- data/lib/brakeman/processor.rb +7 -7
- data/lib/brakeman/processors/alias_processor.rb +30 -12
- data/lib/brakeman/processors/base_processor.rb +4 -8
- data/lib/brakeman/processors/controller_alias_processor.rb +33 -132
- data/lib/brakeman/processors/controller_processor.rb +29 -53
- data/lib/brakeman/processors/erb_template_processor.rb +4 -6
- data/lib/brakeman/processors/erubis_template_processor.rb +8 -11
- data/lib/brakeman/processors/gem_processor.rb +19 -35
- data/lib/brakeman/processors/haml_template_processor.rb +10 -12
- data/lib/brakeman/processors/lib/find_all_calls.rb +3 -5
- data/lib/brakeman/processors/lib/find_call.rb +2 -2
- data/lib/brakeman/processors/lib/find_return_value.rb +1 -1
- data/lib/brakeman/processors/lib/rails2_config_processor.rb +7 -8
- data/lib/brakeman/processors/lib/rails3_config_processor.rb +6 -7
- data/lib/brakeman/processors/lib/render_helper.rb +15 -14
- data/lib/brakeman/processors/lib/render_path.rb +11 -5
- data/lib/brakeman/processors/library_processor.rb +13 -35
- data/lib/brakeman/processors/model_processor.rb +22 -64
- data/lib/brakeman/processors/output_processor.rb +1 -37
- data/lib/brakeman/processors/slim_template_processor.rb +6 -8
- data/lib/brakeman/processors/template_alias_processor.rb +9 -9
- data/lib/brakeman/processors/template_processor.rb +5 -9
- data/lib/brakeman/report/report_base.rb +7 -7
- data/lib/brakeman/report/report_html.rb +5 -7
- data/lib/brakeman/report/report_markdown.rb +4 -6
- data/lib/brakeman/report/report_table.rb +4 -6
- data/lib/brakeman/rescanner.rb +29 -31
- data/lib/brakeman/scanner.rb +17 -8
- data/lib/brakeman/tracker.rb +24 -34
- data/lib/brakeman/tracker/collection.rb +77 -0
- data/lib/brakeman/tracker/config.rb +93 -0
- data/lib/brakeman/tracker/controller.rb +161 -0
- data/lib/brakeman/tracker/library.rb +17 -0
- data/lib/brakeman/tracker/model.rb +90 -0
- data/lib/brakeman/tracker/template.rb +33 -0
- data/lib/brakeman/util.rb +17 -9
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +8 -9
- data/lib/ruby_parser/bm_sexp.rb +16 -16
- data/lib/ruby_parser/bm_sexp_processor.rb +1 -120
- metadata +42 -31
- checksums.yaml.gz.sig +0 -1
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'brakeman/util'
|
2
|
+
|
3
|
+
module Brakeman
|
4
|
+
class Collection
|
5
|
+
include Brakeman::Util
|
6
|
+
|
7
|
+
attr_reader :collection, :files, :includes, :name, :options, :parent, :src, :tracker
|
8
|
+
|
9
|
+
def initialize name, parent, file_name, src, tracker
|
10
|
+
@name = name
|
11
|
+
@parent = parent
|
12
|
+
@file_name = file_name
|
13
|
+
@files = [ file_name ]
|
14
|
+
@src = { file_name => src }
|
15
|
+
@includes = []
|
16
|
+
@methods = { :public => {}, :private => {}, :protected => {} }
|
17
|
+
@options = {}
|
18
|
+
@tracker = tracker
|
19
|
+
end
|
20
|
+
|
21
|
+
def ancestor? parent, seen={}
|
22
|
+
seen[self.name] = true
|
23
|
+
|
24
|
+
if self.parent == parent or seen[self.parent]
|
25
|
+
true
|
26
|
+
elsif parent_model = collection[self.parent]
|
27
|
+
parent_model.ancestor? parent, seen
|
28
|
+
else
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_file file_name, src
|
34
|
+
@files << file_name unless @files.include? file_name
|
35
|
+
@src[file_name] = src
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_include class_name
|
39
|
+
@includes << class_name
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_option name, exp
|
43
|
+
@options[name] ||= []
|
44
|
+
@options[name] << exp
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_method visibility, name, src, file_name
|
48
|
+
@methods[visibility][name] = { :src => src, :file => file_name }
|
49
|
+
end
|
50
|
+
|
51
|
+
def each_method
|
52
|
+
@methods.each do |vis, meths|
|
53
|
+
meths.each do |name, info|
|
54
|
+
yield name, info
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_method name
|
60
|
+
each_method do |n, info|
|
61
|
+
if n == name
|
62
|
+
return info
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
|
69
|
+
def file
|
70
|
+
@files.first
|
71
|
+
end
|
72
|
+
|
73
|
+
def methods_public
|
74
|
+
@methods[:public]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'brakeman/util'
|
2
|
+
|
3
|
+
module Brakeman
|
4
|
+
class Config
|
5
|
+
include Util
|
6
|
+
|
7
|
+
attr_reader :rails, :tracker
|
8
|
+
attr_accessor :rails_version
|
9
|
+
attr_writer :erubis, :escape_html
|
10
|
+
|
11
|
+
def initialize tracker
|
12
|
+
@tracker = tracker
|
13
|
+
@rails = {}
|
14
|
+
@gems = {}
|
15
|
+
@settings = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def allow_forgery_protection?
|
19
|
+
@rails[:action_controller] and
|
20
|
+
@rails[:action_controller][:allow_forgery_protection] == Sexp.new(:false)
|
21
|
+
end
|
22
|
+
|
23
|
+
def erubis?
|
24
|
+
@erubis
|
25
|
+
end
|
26
|
+
|
27
|
+
def escape_html?
|
28
|
+
@escape_html
|
29
|
+
end
|
30
|
+
|
31
|
+
def escape_html_entities_in_json?
|
32
|
+
#TODO add version-specific information here
|
33
|
+
@rails[:active_support] and
|
34
|
+
true? @rails[:active_support][:escape_html_entities_in_json]
|
35
|
+
end
|
36
|
+
|
37
|
+
def whitelist_attributes?
|
38
|
+
@rails[:active_record] and
|
39
|
+
@rails[:active_record][:whitelist_attributes] == Sexp.new(:true)
|
40
|
+
end
|
41
|
+
|
42
|
+
def gem_version name
|
43
|
+
@gems[name] and @gems[name][:version]
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_gem name, version, file, line
|
47
|
+
name = name.to_sym
|
48
|
+
@gems[name] = {
|
49
|
+
:version => version,
|
50
|
+
:file => file,
|
51
|
+
:line => line
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def has_gem? name
|
56
|
+
!!@gems[name]
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_gem name
|
60
|
+
@gems[name]
|
61
|
+
end
|
62
|
+
|
63
|
+
def set_rails_version
|
64
|
+
# Ignore ~>, etc. when using values from Gemfile
|
65
|
+
version = gem_version(:rails) || gem_version(:railties)
|
66
|
+
if version and version.match(/(\d+\.\d+\.\d+.*)/)
|
67
|
+
@rails_version = $1
|
68
|
+
|
69
|
+
if tracker.options[:rails3].nil? and tracker.options[:rails4].nil?
|
70
|
+
if @rails_version.start_with? "3"
|
71
|
+
tracker.options[:rails3] = true
|
72
|
+
Brakeman.notify "[Notice] Detected Rails 3 application"
|
73
|
+
elsif @rails_version.start_with? "4"
|
74
|
+
tracker.options[:rails3] = true
|
75
|
+
tracker.options[:rails4] = true
|
76
|
+
Brakeman.notify "[Notice] Detected Rails 4 application"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
if get_gem :rails_xss
|
82
|
+
@escape_html = true
|
83
|
+
Brakeman.notify "[Notice] Escaping HTML by default"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def session_settings
|
88
|
+
@rails[:action_controller] &&
|
89
|
+
@rails[:action_controller][:session]
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'brakeman/tracker/collection'
|
2
|
+
|
3
|
+
module Brakeman
|
4
|
+
module ControllerMethods
|
5
|
+
attr_accessor :layout
|
6
|
+
|
7
|
+
def initialize_controller
|
8
|
+
@options[:before_filters] = []
|
9
|
+
@options[:skip_filters] = []
|
10
|
+
@layout = nil
|
11
|
+
@skip_filter_cache = nil
|
12
|
+
@before_filter_cache = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def protect_from_forgery?
|
16
|
+
@options[:protect_from_forgery]
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_before_filter exp
|
20
|
+
@options[:before_filters] << exp
|
21
|
+
end
|
22
|
+
|
23
|
+
def prepend_before_filter exp
|
24
|
+
@options[:before_filters].unshift exp
|
25
|
+
end
|
26
|
+
|
27
|
+
def before_filters
|
28
|
+
@options[:before_filters]
|
29
|
+
end
|
30
|
+
|
31
|
+
def skip_filter exp
|
32
|
+
@options[:skip_filters] << exp
|
33
|
+
end
|
34
|
+
|
35
|
+
def skip_filters
|
36
|
+
@options[:skip_filters]
|
37
|
+
end
|
38
|
+
|
39
|
+
def before_filter_list processor, method
|
40
|
+
controller = self
|
41
|
+
filters = []
|
42
|
+
|
43
|
+
while controller
|
44
|
+
filters = controller.get_before_filters(processor, method) + filters
|
45
|
+
|
46
|
+
controller = tracker.controllers[controller.parent] ||
|
47
|
+
tracker.libs[controller.parent]
|
48
|
+
end
|
49
|
+
|
50
|
+
remove_skipped_filters processor, filters, method
|
51
|
+
end
|
52
|
+
|
53
|
+
def get_skipped_filters processor, method
|
54
|
+
filters = []
|
55
|
+
|
56
|
+
if @skip_filter_cache.nil?
|
57
|
+
@skip_filter_cache = skip_filters.map do |filter|
|
58
|
+
before_filter_to_hash(processor, filter.args)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
@skip_filter_cache.each do |f|
|
63
|
+
if f[:all] or
|
64
|
+
(f[:only] == method) or
|
65
|
+
(f[:only].is_a? Array and f[:only].include? method) or
|
66
|
+
(f[:except].is_a? Symbol and f[:except] != method) or
|
67
|
+
(f[:except].is_a? Array and not f[:except].include? method)
|
68
|
+
|
69
|
+
filters.concat f[:methods]
|
70
|
+
else
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
filters
|
75
|
+
end
|
76
|
+
|
77
|
+
def remove_skipped_filters processor, filters, method
|
78
|
+
controller = self
|
79
|
+
|
80
|
+
while controller
|
81
|
+
filters = filters - controller.get_skipped_filters(processor, method)
|
82
|
+
|
83
|
+
controller = tracker.controllers[controller.parent] ||
|
84
|
+
tracker.libs[controller.parent]
|
85
|
+
end
|
86
|
+
|
87
|
+
filters
|
88
|
+
end
|
89
|
+
|
90
|
+
def get_before_filters processor, method
|
91
|
+
filters = []
|
92
|
+
|
93
|
+
if @before_filter_cache.nil?
|
94
|
+
@before_filter_cache = []
|
95
|
+
|
96
|
+
before_filters.each do |filter|
|
97
|
+
@before_filter_cache << before_filter_to_hash(processor, filter.args)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
@before_filter_cache.each do |f|
|
102
|
+
if f[:all] or
|
103
|
+
(f[:only] == method) or
|
104
|
+
(f[:only].is_a? Array and f[:only].include? method) or
|
105
|
+
(f[:except].is_a? Symbol and f[:except] != method) or
|
106
|
+
(f[:except].is_a? Array and not f[:except].include? method)
|
107
|
+
|
108
|
+
filters.concat f[:methods]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
filters
|
114
|
+
end
|
115
|
+
|
116
|
+
def before_filter_to_hash processor, args
|
117
|
+
filter = {}
|
118
|
+
|
119
|
+
#Process args for the uncommon but possible situation
|
120
|
+
#in which some variables are used in the filter.
|
121
|
+
args.each do |a|
|
122
|
+
if sexp? a
|
123
|
+
a = processor.process_default a
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
filter[:methods] = [args[0][1]]
|
128
|
+
|
129
|
+
args[1..-1].each do |a|
|
130
|
+
filter[:methods] << a[1] if a.node_type == :lit
|
131
|
+
end
|
132
|
+
|
133
|
+
if args[-1].node_type == :hash
|
134
|
+
option = args[-1][1][1]
|
135
|
+
value = args[-1][2]
|
136
|
+
case value.node_type
|
137
|
+
when :array
|
138
|
+
filter[option] = value[1..-1].map {|v| v[1] }
|
139
|
+
when :lit, :str
|
140
|
+
filter[option] = value[1]
|
141
|
+
else
|
142
|
+
Brakeman.debug "[Notice] Unknown before_filter value: #{option} => #{value}"
|
143
|
+
end
|
144
|
+
else
|
145
|
+
filter[:all] = true
|
146
|
+
end
|
147
|
+
|
148
|
+
filter
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
class Controller < Brakeman::Collection
|
153
|
+
include ControllerMethods
|
154
|
+
|
155
|
+
def initialize name, parent, file_name, src, tracker
|
156
|
+
super
|
157
|
+
initialize_controller
|
158
|
+
@collection = tracker.controllers
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'brakeman/tracker/collection'
|
2
|
+
require 'brakeman/tracker/controller'
|
3
|
+
require 'brakeman/tracker/model'
|
4
|
+
|
5
|
+
module Brakeman
|
6
|
+
class Library < Brakeman::Collection
|
7
|
+
include ControllerMethods
|
8
|
+
include ModelMethods
|
9
|
+
|
10
|
+
def initialize name, parent, file_name, src, tracker
|
11
|
+
super
|
12
|
+
initialize_controller
|
13
|
+
initialize_model
|
14
|
+
@collection = tracker.libs
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'brakeman/tracker/collection'
|
2
|
+
|
3
|
+
module Brakeman
|
4
|
+
module ModelMethods
|
5
|
+
attr_reader :associations, :attr_accessible, :role_accessible
|
6
|
+
|
7
|
+
def initialize_model
|
8
|
+
@associations = {}
|
9
|
+
@role_accessible = []
|
10
|
+
@attr_accessible = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def association? method_name
|
14
|
+
@associations.each do |name, args|
|
15
|
+
args.each do |arg|
|
16
|
+
if symbol? arg and arg.value == method_name
|
17
|
+
return true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
def unprotected_model?
|
26
|
+
@attr_accessible.nil? and !parent_classes_protected? and ancestor?(:"ActiveRecord::Base")
|
27
|
+
end
|
28
|
+
|
29
|
+
# go up the chain of parent classes to see if any have attr_accessible
|
30
|
+
def parent_classes_protected? seen={}
|
31
|
+
seen[self.name] = true
|
32
|
+
|
33
|
+
if @attr_accessible or self.includes.include? :"ActiveModel::ForbiddenAttributesProtection"
|
34
|
+
true
|
35
|
+
elsif parent = tracker.models[self.parent] and !seen[self.parent]
|
36
|
+
parent.parent_classes_protected? seen
|
37
|
+
else
|
38
|
+
false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def set_attr_accessible exp = nil
|
43
|
+
if exp
|
44
|
+
args = []
|
45
|
+
|
46
|
+
exp.each_arg do |e|
|
47
|
+
if node_type? e, :lit
|
48
|
+
args << e.value
|
49
|
+
elsif hash? e
|
50
|
+
@role_accessible.concat args
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
@attr_accessible ||= []
|
55
|
+
@attr_accessible.concat args
|
56
|
+
else
|
57
|
+
@attr_accessible ||= []
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def set_attr_protected exp
|
62
|
+
add_option :attr_protected, exp
|
63
|
+
end
|
64
|
+
|
65
|
+
def attr_protected
|
66
|
+
@options[:attr_protected]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class Model < Brakeman::Collection
|
71
|
+
include ModelMethods
|
72
|
+
|
73
|
+
ASSOCIATIONS = Set[:belongs_to, :has_one, :has_many, :has_and_belongs_to_many]
|
74
|
+
|
75
|
+
def initialize name, parent, file_name, src, tracker
|
76
|
+
super
|
77
|
+
initialize_model
|
78
|
+
@collection = tracker.models
|
79
|
+
end
|
80
|
+
|
81
|
+
def add_option name, exp
|
82
|
+
if ASSOCIATIONS.include? name
|
83
|
+
@associations[name] ||= []
|
84
|
+
@associations[name].concat exp.args
|
85
|
+
else
|
86
|
+
super name, exp.arglist.line(exp.line)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'brakeman/tracker/collection'
|
2
|
+
|
3
|
+
module Brakeman
|
4
|
+
class Template < Brakeman::Collection
|
5
|
+
attr_accessor :type
|
6
|
+
attr_reader :render_path
|
7
|
+
attr_writer :src
|
8
|
+
|
9
|
+
def initialize name, called_from, file_name, tracker
|
10
|
+
super name, nil, file_name, nil, tracker
|
11
|
+
@render_path = called_from
|
12
|
+
@outputs = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_output exp
|
16
|
+
@outputs << exp
|
17
|
+
end
|
18
|
+
|
19
|
+
def each_output
|
20
|
+
@outputs.each do |o|
|
21
|
+
yield o
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def rendered_from_controller?
|
26
|
+
if @render_path
|
27
|
+
@render_path.rendered_from_controller?
|
28
|
+
else
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|