brakeman-lib 3.3.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.
Files changed (159) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +872 -0
  3. data/FEATURES +16 -0
  4. data/README.md +169 -0
  5. data/WARNING_TYPES +95 -0
  6. data/bin/brakeman +89 -0
  7. data/lib/brakeman.rb +495 -0
  8. data/lib/brakeman/app_tree.rb +161 -0
  9. data/lib/brakeman/brakeman.rake +17 -0
  10. data/lib/brakeman/call_index.rb +219 -0
  11. data/lib/brakeman/checks.rb +191 -0
  12. data/lib/brakeman/checks/base_check.rb +518 -0
  13. data/lib/brakeman/checks/check_basic_auth.rb +88 -0
  14. data/lib/brakeman/checks/check_basic_auth_timing_attack.rb +33 -0
  15. data/lib/brakeman/checks/check_content_tag.rb +160 -0
  16. data/lib/brakeman/checks/check_create_with.rb +75 -0
  17. data/lib/brakeman/checks/check_cross_site_scripting.rb +385 -0
  18. data/lib/brakeman/checks/check_default_routes.rb +86 -0
  19. data/lib/brakeman/checks/check_deserialize.rb +57 -0
  20. data/lib/brakeman/checks/check_detailed_exceptions.rb +55 -0
  21. data/lib/brakeman/checks/check_digest_dos.rb +38 -0
  22. data/lib/brakeman/checks/check_dynamic_finders.rb +49 -0
  23. data/lib/brakeman/checks/check_escape_function.rb +21 -0
  24. data/lib/brakeman/checks/check_evaluation.rb +36 -0
  25. data/lib/brakeman/checks/check_execute.rb +167 -0
  26. data/lib/brakeman/checks/check_file_access.rb +63 -0
  27. data/lib/brakeman/checks/check_file_disclosure.rb +35 -0
  28. data/lib/brakeman/checks/check_filter_skipping.rb +31 -0
  29. data/lib/brakeman/checks/check_forgery_setting.rb +74 -0
  30. data/lib/brakeman/checks/check_header_dos.rb +31 -0
  31. data/lib/brakeman/checks/check_i18n_xss.rb +48 -0
  32. data/lib/brakeman/checks/check_jruby_xml.rb +38 -0
  33. data/lib/brakeman/checks/check_json_encoding.rb +47 -0
  34. data/lib/brakeman/checks/check_json_parsing.rb +107 -0
  35. data/lib/brakeman/checks/check_link_to.rb +132 -0
  36. data/lib/brakeman/checks/check_link_to_href.rb +115 -0
  37. data/lib/brakeman/checks/check_mail_to.rb +49 -0
  38. data/lib/brakeman/checks/check_mass_assignment.rb +198 -0
  39. data/lib/brakeman/checks/check_mime_type_dos.rb +39 -0
  40. data/lib/brakeman/checks/check_model_attr_accessible.rb +55 -0
  41. data/lib/brakeman/checks/check_model_attributes.rb +119 -0
  42. data/lib/brakeman/checks/check_model_serialize.rb +67 -0
  43. data/lib/brakeman/checks/check_nested_attributes.rb +38 -0
  44. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +58 -0
  45. data/lib/brakeman/checks/check_number_to_currency.rb +74 -0
  46. data/lib/brakeman/checks/check_quote_table_name.rb +40 -0
  47. data/lib/brakeman/checks/check_redirect.rb +215 -0
  48. data/lib/brakeman/checks/check_regex_dos.rb +69 -0
  49. data/lib/brakeman/checks/check_render.rb +92 -0
  50. data/lib/brakeman/checks/check_render_dos.rb +37 -0
  51. data/lib/brakeman/checks/check_render_inline.rb +54 -0
  52. data/lib/brakeman/checks/check_response_splitting.rb +21 -0
  53. data/lib/brakeman/checks/check_route_dos.rb +42 -0
  54. data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +31 -0
  55. data/lib/brakeman/checks/check_sanitize_methods.rb +79 -0
  56. data/lib/brakeman/checks/check_secrets.rb +40 -0
  57. data/lib/brakeman/checks/check_select_tag.rb +60 -0
  58. data/lib/brakeman/checks/check_select_vulnerability.rb +60 -0
  59. data/lib/brakeman/checks/check_send.rb +48 -0
  60. data/lib/brakeman/checks/check_send_file.rb +19 -0
  61. data/lib/brakeman/checks/check_session_manipulation.rb +36 -0
  62. data/lib/brakeman/checks/check_session_settings.rb +170 -0
  63. data/lib/brakeman/checks/check_simple_format.rb +59 -0
  64. data/lib/brakeman/checks/check_single_quotes.rb +101 -0
  65. data/lib/brakeman/checks/check_skip_before_filter.rb +60 -0
  66. data/lib/brakeman/checks/check_sql.rb +660 -0
  67. data/lib/brakeman/checks/check_sql_cves.rb +101 -0
  68. data/lib/brakeman/checks/check_ssl_verify.rb +49 -0
  69. data/lib/brakeman/checks/check_strip_tags.rb +89 -0
  70. data/lib/brakeman/checks/check_symbol_dos.rb +64 -0
  71. data/lib/brakeman/checks/check_symbol_dos_cve.rb +30 -0
  72. data/lib/brakeman/checks/check_translate_bug.rb +45 -0
  73. data/lib/brakeman/checks/check_unsafe_reflection.rb +51 -0
  74. data/lib/brakeman/checks/check_unscoped_find.rb +41 -0
  75. data/lib/brakeman/checks/check_validation_regex.rb +116 -0
  76. data/lib/brakeman/checks/check_weak_hash.rb +151 -0
  77. data/lib/brakeman/checks/check_without_protection.rb +80 -0
  78. data/lib/brakeman/checks/check_xml_dos.rb +51 -0
  79. data/lib/brakeman/checks/check_yaml_parsing.rb +121 -0
  80. data/lib/brakeman/differ.rb +66 -0
  81. data/lib/brakeman/file_parser.rb +50 -0
  82. data/lib/brakeman/format/style.css +133 -0
  83. data/lib/brakeman/options.rb +301 -0
  84. data/lib/brakeman/parsers/rails2_erubis.rb +6 -0
  85. data/lib/brakeman/parsers/rails2_xss_plugin_erubis.rb +48 -0
  86. data/lib/brakeman/parsers/rails3_erubis.rb +74 -0
  87. data/lib/brakeman/parsers/template_parser.rb +89 -0
  88. data/lib/brakeman/processor.rb +102 -0
  89. data/lib/brakeman/processors/alias_processor.rb +1013 -0
  90. data/lib/brakeman/processors/base_processor.rb +277 -0
  91. data/lib/brakeman/processors/config_processor.rb +14 -0
  92. data/lib/brakeman/processors/controller_alias_processor.rb +273 -0
  93. data/lib/brakeman/processors/controller_processor.rb +326 -0
  94. data/lib/brakeman/processors/erb_template_processor.rb +80 -0
  95. data/lib/brakeman/processors/erubis_template_processor.rb +104 -0
  96. data/lib/brakeman/processors/gem_processor.rb +57 -0
  97. data/lib/brakeman/processors/haml_template_processor.rb +190 -0
  98. data/lib/brakeman/processors/lib/basic_processor.rb +37 -0
  99. data/lib/brakeman/processors/lib/find_all_calls.rb +223 -0
  100. data/lib/brakeman/processors/lib/find_call.rb +183 -0
  101. data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
  102. data/lib/brakeman/processors/lib/processor_helper.rb +75 -0
  103. data/lib/brakeman/processors/lib/rails2_config_processor.rb +145 -0
  104. data/lib/brakeman/processors/lib/rails2_route_processor.rb +313 -0
  105. data/lib/brakeman/processors/lib/rails3_config_processor.rb +132 -0
  106. data/lib/brakeman/processors/lib/rails3_route_processor.rb +308 -0
  107. data/lib/brakeman/processors/lib/render_helper.rb +181 -0
  108. data/lib/brakeman/processors/lib/render_path.rb +107 -0
  109. data/lib/brakeman/processors/lib/route_helper.rb +68 -0
  110. data/lib/brakeman/processors/lib/safe_call_helper.rb +16 -0
  111. data/lib/brakeman/processors/library_processor.rb +119 -0
  112. data/lib/brakeman/processors/model_processor.rb +191 -0
  113. data/lib/brakeman/processors/output_processor.rb +171 -0
  114. data/lib/brakeman/processors/route_processor.rb +17 -0
  115. data/lib/brakeman/processors/slim_template_processor.rb +107 -0
  116. data/lib/brakeman/processors/template_alias_processor.rb +116 -0
  117. data/lib/brakeman/processors/template_processor.rb +74 -0
  118. data/lib/brakeman/report.rb +78 -0
  119. data/lib/brakeman/report/config/remediation.yml +71 -0
  120. data/lib/brakeman/report/ignore/config.rb +135 -0
  121. data/lib/brakeman/report/ignore/interactive.rb +311 -0
  122. data/lib/brakeman/report/renderer.rb +24 -0
  123. data/lib/brakeman/report/report_base.rb +286 -0
  124. data/lib/brakeman/report/report_codeclimate.rb +70 -0
  125. data/lib/brakeman/report/report_csv.rb +55 -0
  126. data/lib/brakeman/report/report_hash.rb +23 -0
  127. data/lib/brakeman/report/report_html.rb +216 -0
  128. data/lib/brakeman/report/report_json.rb +42 -0
  129. data/lib/brakeman/report/report_markdown.rb +156 -0
  130. data/lib/brakeman/report/report_table.rb +107 -0
  131. data/lib/brakeman/report/report_tabs.rb +17 -0
  132. data/lib/brakeman/report/templates/controller_overview.html.erb +22 -0
  133. data/lib/brakeman/report/templates/controller_warnings.html.erb +21 -0
  134. data/lib/brakeman/report/templates/error_overview.html.erb +29 -0
  135. data/lib/brakeman/report/templates/header.html.erb +58 -0
  136. data/lib/brakeman/report/templates/ignored_warnings.html.erb +25 -0
  137. data/lib/brakeman/report/templates/model_warnings.html.erb +21 -0
  138. data/lib/brakeman/report/templates/overview.html.erb +38 -0
  139. data/lib/brakeman/report/templates/security_warnings.html.erb +23 -0
  140. data/lib/brakeman/report/templates/template_overview.html.erb +21 -0
  141. data/lib/brakeman/report/templates/view_warnings.html.erb +34 -0
  142. data/lib/brakeman/report/templates/warning_overview.html.erb +17 -0
  143. data/lib/brakeman/rescanner.rb +483 -0
  144. data/lib/brakeman/scanner.rb +317 -0
  145. data/lib/brakeman/tracker.rb +347 -0
  146. data/lib/brakeman/tracker/collection.rb +93 -0
  147. data/lib/brakeman/tracker/config.rb +101 -0
  148. data/lib/brakeman/tracker/constants.rb +101 -0
  149. data/lib/brakeman/tracker/controller.rb +161 -0
  150. data/lib/brakeman/tracker/library.rb +17 -0
  151. data/lib/brakeman/tracker/model.rb +90 -0
  152. data/lib/brakeman/tracker/template.rb +33 -0
  153. data/lib/brakeman/util.rb +481 -0
  154. data/lib/brakeman/version.rb +3 -0
  155. data/lib/brakeman/warning.rb +255 -0
  156. data/lib/brakeman/warning_codes.rb +111 -0
  157. data/lib/ruby_parser/bm_sexp.rb +610 -0
  158. data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
  159. metadata +362 -0
@@ -0,0 +1,93 @@
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
+ if src.node_type == :defs
49
+ name = :"#{src[1]}.#{name}"
50
+ end
51
+
52
+ @methods[visibility][name] = { :src => src, :file => file_name }
53
+ end
54
+
55
+ def each_method
56
+ @methods.each do |vis, meths|
57
+ meths.each do |name, info|
58
+ yield name, info
59
+ end
60
+ end
61
+ end
62
+
63
+ def get_method name
64
+ each_method do |n, info|
65
+ if n == name
66
+ return info
67
+ end
68
+ end
69
+
70
+ nil
71
+ end
72
+
73
+ def file
74
+ @files.first
75
+ end
76
+
77
+ def top_line
78
+ if sexp? @src[file]
79
+ @src[file].line
80
+ else
81
+ @src.each_value do |source|
82
+ if sexp? source
83
+ return source.line
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ def methods_public
90
+ @methods[:public]
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,101 @@
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
+ attr_reader :gems
11
+
12
+ def initialize tracker
13
+ @tracker = tracker
14
+ @rails = {}
15
+ @gems = {}
16
+ @settings = {}
17
+ @escape_html = nil
18
+ @erubis = nil
19
+ end
20
+
21
+ def allow_forgery_protection?
22
+ @rails[:action_controller] and
23
+ @rails[:action_controller][:allow_forgery_protection] == Sexp.new(:false)
24
+ end
25
+
26
+ def erubis?
27
+ @erubis
28
+ end
29
+
30
+ def escape_html?
31
+ @escape_html
32
+ end
33
+
34
+ def escape_html_entities_in_json?
35
+ #TODO add version-specific information here
36
+ @rails[:active_support] and
37
+ true? @rails[:active_support][:escape_html_entities_in_json]
38
+ end
39
+
40
+ def whitelist_attributes?
41
+ @rails[:active_record] and
42
+ @rails[:active_record][:whitelist_attributes] == Sexp.new(:true)
43
+ end
44
+
45
+ def gem_version name
46
+ @gems[name] and @gems[name][:version]
47
+ end
48
+
49
+ def add_gem name, version, file, line
50
+ name = name.to_sym
51
+ @gems[name] = {
52
+ :version => version,
53
+ :file => file,
54
+ :line => line
55
+ }
56
+ end
57
+
58
+ def has_gem? name
59
+ !!@gems[name]
60
+ end
61
+
62
+ def get_gem name
63
+ @gems[name]
64
+ end
65
+
66
+ def set_rails_version
67
+ # Ignore ~>, etc. when using values from Gemfile
68
+ version = gem_version(:rails) || gem_version(:railties)
69
+ if version and version.match(/(\d+\.\d+\.\d+.*)/)
70
+ @rails_version = $1
71
+
72
+ if tracker.options[:rails3].nil? and tracker.options[:rails4].nil?
73
+ if @rails_version.start_with? "3"
74
+ tracker.options[:rails3] = true
75
+ Brakeman.notify "[Notice] Detected Rails 3 application"
76
+ elsif @rails_version.start_with? "4"
77
+ tracker.options[:rails3] = true
78
+ tracker.options[:rails4] = true
79
+ Brakeman.notify "[Notice] Detected Rails 4 application"
80
+ elsif @rails_version.start_with? "5"
81
+ tracker.options[:rails3] = true
82
+ tracker.options[:rails4] = true
83
+ tracker.options[:rails5] = true
84
+ Brakeman.notify "[Notice] Detected Rails 5 application"
85
+ end
86
+ end
87
+ end
88
+
89
+ if get_gem :rails_xss
90
+ @escape_html = true
91
+ Brakeman.notify "[Notice] Escaping HTML by default"
92
+ end
93
+ end
94
+
95
+ def session_settings
96
+ @rails[:action_controller] &&
97
+ @rails[:action_controller][:session]
98
+ end
99
+
100
+ end
101
+ end
@@ -0,0 +1,101 @@
1
+ require 'brakeman/processors/output_processor'
2
+
3
+ module Brakeman
4
+ class Constant
5
+ attr_reader :name, :file
6
+
7
+ def initialize name, value = nil, context = nil
8
+ set_name name, context
9
+ @values = [ value ]
10
+ @context = context
11
+
12
+ if @context
13
+ @file = @context[:file]
14
+ end
15
+ end
16
+
17
+ def line
18
+ if @values.first.is_a? Sexp
19
+ @values.first.line
20
+ end
21
+ end
22
+
23
+ def set_name name, context
24
+ @name = Constants.constant_as_array(name)
25
+ end
26
+
27
+ def match? name
28
+ @name.reverse.zip(name.reverse).reduce(true) { |m, a| a[1] ? a[0] == a[1] && m : m }
29
+ end
30
+
31
+ def value
32
+ @values.reverse.reduce do |m, v|
33
+ Sexp.new(:or, v, m)
34
+ end
35
+ end
36
+
37
+ def add_value exp
38
+ unless @values.include? exp
39
+ @values << exp
40
+ end
41
+ end
42
+ end
43
+
44
+ class Constants
45
+ include Brakeman::Util
46
+
47
+ def initialize
48
+ @constants = []
49
+ end
50
+
51
+ def [] exp
52
+ return unless constant? exp
53
+ match = find_constant exp
54
+
55
+ if match
56
+ match.value
57
+ else
58
+ nil
59
+ end
60
+ end
61
+
62
+ def find_constant exp
63
+ name = Constants.constant_as_array(exp)
64
+ @constants.find do |c|
65
+ c.match? name
66
+ end
67
+ end
68
+
69
+ def add name, value, context = nil
70
+ if existing = self.find_constant(name)
71
+ existing.add_value value
72
+ else
73
+ @constants << Constant.new(name, value, context)
74
+ end
75
+ end
76
+
77
+ def get_literal name
78
+ if x = self[name] and [:lit, :false, :str, :true, :array, :hash].include? x.node_type
79
+ x
80
+ else
81
+ nil
82
+ end
83
+ end
84
+
85
+ def each &block
86
+ @constants.each &block
87
+ end
88
+
89
+ def self.constant_as_array exp
90
+ get_constant_name(exp).split('::')
91
+ end
92
+
93
+ def self.get_constant_name exp
94
+ if exp.is_a? Sexp
95
+ Brakeman::OutputProcessor.new.format(exp)
96
+ else
97
+ exp.to_s
98
+ end
99
+ end
100
+ end
101
+ 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] = []
128
+
129
+ args.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