brakeman-lib 4.4.0 → 4.7.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.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +63 -0
  3. data/README.md +6 -7
  4. data/lib/brakeman.rb +7 -0
  5. data/lib/brakeman/app_tree.rb +34 -22
  6. data/lib/brakeman/call_index.rb +54 -15
  7. data/lib/brakeman/checks.rb +7 -7
  8. data/lib/brakeman/checks/base_check.rb +75 -56
  9. data/lib/brakeman/checks/check_content_tag.rb +12 -0
  10. data/lib/brakeman/checks/check_cookie_serialization.rb +22 -0
  11. data/lib/brakeman/checks/check_cross_site_scripting.rb +15 -10
  12. data/lib/brakeman/checks/check_default_routes.rb +5 -0
  13. data/lib/brakeman/checks/check_deserialize.rb +49 -0
  14. data/lib/brakeman/checks/check_dynamic_finders.rb +1 -1
  15. data/lib/brakeman/checks/check_evaluation.rb +0 -1
  16. data/lib/brakeman/checks/check_execute.rb +44 -1
  17. data/lib/brakeman/checks/check_file_access.rb +7 -1
  18. data/lib/brakeman/checks/check_force_ssl.rb +27 -0
  19. data/lib/brakeman/checks/check_header_dos.rb +2 -2
  20. data/lib/brakeman/checks/check_i18n_xss.rb +2 -2
  21. data/lib/brakeman/checks/check_jruby_xml.rb +2 -2
  22. data/lib/brakeman/checks/check_json_parsing.rb +7 -2
  23. data/lib/brakeman/checks/check_link_to_href.rb +6 -1
  24. data/lib/brakeman/checks/check_mail_to.rb +1 -1
  25. data/lib/brakeman/checks/check_mime_type_dos.rb +2 -2
  26. data/lib/brakeman/checks/check_model_attr_accessible.rb +1 -1
  27. data/lib/brakeman/checks/check_model_attributes.rb +12 -50
  28. data/lib/brakeman/checks/check_model_serialize.rb +1 -1
  29. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +4 -4
  30. data/lib/brakeman/checks/check_reverse_tabnabbing.rb +54 -0
  31. data/lib/brakeman/checks/check_sanitize_methods.rb +2 -2
  32. data/lib/brakeman/checks/check_secrets.rb +1 -1
  33. data/lib/brakeman/checks/check_send.rb +0 -1
  34. data/lib/brakeman/checks/check_session_manipulation.rb +0 -1
  35. data/lib/brakeman/checks/check_session_settings.rb +15 -12
  36. data/lib/brakeman/checks/check_simple_format.rb +5 -0
  37. data/lib/brakeman/checks/check_skip_before_filter.rb +1 -1
  38. data/lib/brakeman/checks/check_sql.rb +27 -20
  39. data/lib/brakeman/checks/check_validation_regex.rb +1 -1
  40. data/lib/brakeman/checks/check_xml_dos.rb +2 -2
  41. data/lib/brakeman/checks/check_yaml_parsing.rb +10 -18
  42. data/lib/brakeman/differ.rb +16 -28
  43. data/lib/brakeman/file_parser.rb +6 -8
  44. data/lib/brakeman/file_path.rb +85 -0
  45. data/lib/brakeman/options.rb +7 -0
  46. data/lib/brakeman/parsers/haml_embedded.rb +44 -0
  47. data/lib/brakeman/parsers/slim_embedded.rb +44 -0
  48. data/lib/brakeman/parsers/template_parser.rb +8 -8
  49. data/lib/brakeman/processor.rb +4 -5
  50. data/lib/brakeman/processors/alias_processor.rb +49 -7
  51. data/lib/brakeman/processors/base_processor.rb +10 -7
  52. data/lib/brakeman/processors/controller_alias_processor.rb +10 -7
  53. data/lib/brakeman/processors/controller_processor.rb +9 -13
  54. data/lib/brakeman/processors/gem_processor.rb +10 -2
  55. data/lib/brakeman/processors/haml_template_processor.rb +92 -123
  56. data/lib/brakeman/processors/lib/call_conversion_helper.rb +4 -0
  57. data/lib/brakeman/processors/lib/find_all_calls.rb +27 -4
  58. data/lib/brakeman/processors/lib/find_call.rb +3 -64
  59. data/lib/brakeman/processors/lib/module_helper.rb +8 -8
  60. data/lib/brakeman/processors/lib/processor_helper.rb +3 -3
  61. data/lib/brakeman/processors/lib/rails2_config_processor.rb +4 -4
  62. data/lib/brakeman/processors/lib/rails2_route_processor.rb +2 -2
  63. data/lib/brakeman/processors/lib/rails3_config_processor.rb +3 -3
  64. data/lib/brakeman/processors/lib/rails3_route_processor.rb +2 -2
  65. data/lib/brakeman/processors/lib/render_helper.rb +2 -2
  66. data/lib/brakeman/processors/lib/render_path.rb +18 -1
  67. data/lib/brakeman/processors/library_processor.rb +5 -5
  68. data/lib/brakeman/processors/model_processor.rb +4 -5
  69. data/lib/brakeman/processors/output_processor.rb +5 -0
  70. data/lib/brakeman/processors/slim_template_processor.rb +16 -0
  71. data/lib/brakeman/processors/template_alias_processor.rb +32 -5
  72. data/lib/brakeman/processors/template_processor.rb +14 -10
  73. data/lib/brakeman/report.rb +3 -3
  74. data/lib/brakeman/report/ignore/config.rb +2 -3
  75. data/lib/brakeman/report/ignore/interactive.rb +2 -2
  76. data/lib/brakeman/report/pager.rb +1 -0
  77. data/lib/brakeman/report/report_base.rb +51 -6
  78. data/lib/brakeman/report/report_codeclimate.rb +3 -3
  79. data/lib/brakeman/report/report_hash.rb +1 -1
  80. data/lib/brakeman/report/report_html.rb +2 -2
  81. data/lib/brakeman/report/report_json.rb +1 -24
  82. data/lib/brakeman/report/report_table.rb +20 -4
  83. data/lib/brakeman/report/report_tabs.rb +1 -1
  84. data/lib/brakeman/report/report_text.rb +2 -2
  85. data/lib/brakeman/rescanner.rb +13 -12
  86. data/lib/brakeman/scanner.rb +24 -18
  87. data/lib/brakeman/tracker.rb +35 -7
  88. data/lib/brakeman/tracker/collection.rb +4 -3
  89. data/lib/brakeman/tracker/config.rb +44 -48
  90. data/lib/brakeman/tracker/constants.rb +2 -1
  91. data/lib/brakeman/util.rb +18 -147
  92. data/lib/brakeman/version.rb +1 -1
  93. data/lib/brakeman/warning.rb +27 -13
  94. data/lib/brakeman/warning_codes.rb +4 -0
  95. data/lib/ruby_parser/bm_sexp.rb +1 -1
  96. data/lib/ruby_parser/bm_sexp_processor.rb +1 -0
  97. metadata +58 -43
@@ -40,6 +40,10 @@ module Brakeman
40
40
  else
41
41
  original_exp
42
42
  end
43
+ rescue Encoding::CompatibilityError => e
44
+ # If the two strings are different encodings, we can't join them.
45
+ Brakeman.debug e.inspect
46
+ original_exp
43
47
  end
44
48
 
45
49
  def math_op op, lhs, rhs, original_exp = nil
@@ -5,9 +5,9 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
5
5
 
6
6
  def initialize tracker
7
7
  super
8
- @current_class = nil
9
- @current_method = nil
8
+
10
9
  @in_target = false
10
+ @processing_class = false
11
11
  @calls = []
12
12
  @cache = {}
13
13
  end
@@ -23,10 +23,33 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
23
23
  process exp
24
24
  end
25
25
 
26
+ #For whatever reason, originally the indexing of calls
27
+ #was performed on individual method bodies (see process_defn).
28
+ #This method explicitly indexes all calls everywhere given any
29
+ #source.
30
+ def process_all_source exp, opts
31
+ @processing_class = true
32
+ process_source exp, opts
33
+ ensure
34
+ @processing_class = false
35
+ end
36
+
26
37
  #Process body of method
27
38
  def process_defn exp
28
- return exp unless @current_method
29
- process_all exp.body
39
+ return exp unless @current_method or @processing_class
40
+
41
+ # 'Normal' processing assumes the method name was given
42
+ # as an option to `process_source` but for `process_all_source`
43
+ # we don't want to do that.
44
+ if @current_method.nil?
45
+ @current_method = exp.method_name
46
+ process_all exp.body
47
+ @current_method = nil
48
+ else
49
+ process_all exp.body
50
+ end
51
+
52
+ exp
30
53
  end
31
54
 
32
55
  alias process_defs process_defn
@@ -33,14 +33,13 @@ require 'brakeman/processors/lib/basic_processor'
33
33
  # FindCall.new nil, /^g?sub!?$/
34
34
  class Brakeman::FindCall < Brakeman::BasicProcessor
35
35
 
36
- def initialize targets, methods, tracker, in_depth = false
36
+ def initialize targets, methods, tracker
37
37
  super tracker
38
38
  @calls = []
39
39
  @find_targets = targets
40
40
  @find_methods = methods
41
41
  @current_class = nil
42
42
  @current_method = nil
43
- @in_depth = in_depth
44
43
  end
45
44
 
46
45
  #Returns a list of results.
@@ -48,10 +47,6 @@ class Brakeman::FindCall < Brakeman::BasicProcessor
48
47
  #A result looks like:
49
48
  #
50
49
  # s(:result, :ClassName, :method_name, s(:call, ...))
51
- #
52
- #or
53
- #
54
- # s(:result, :template_name, s(:call, ...))
55
50
  def matches
56
51
  @calls
57
52
  end
@@ -60,10 +55,7 @@ class Brakeman::FindCall < Brakeman::BasicProcessor
60
55
  #or the template. These names are used when reporting results.
61
56
  #
62
57
  #Use FindCall#matches to retrieve results.
63
- def process_source exp, klass = nil, method = nil, template = nil
64
- @current_class = klass
65
- @current_method = method
66
- @current_template = template
58
+ def process_source exp
67
59
  process exp
68
60
  end
69
61
 
@@ -74,11 +66,6 @@ class Brakeman::FindCall < Brakeman::BasicProcessor
74
66
 
75
67
  alias :process_defs :process_defn
76
68
 
77
- #Process body of block
78
- def process_rlist exp
79
- process_all exp
80
- end
81
-
82
69
  #Look for matching calls and add them to results
83
70
  def process_call exp
84
71
  target = get_target exp.target
@@ -87,25 +74,9 @@ class Brakeman::FindCall < Brakeman::BasicProcessor
87
74
  process_call_args exp
88
75
 
89
76
  if match(@find_targets, target) and match(@find_methods, method)
90
-
91
- if @current_template
92
- @calls << Sexp.new(:result, @current_template, exp).line(exp.line)
93
- else
94
- @calls << Sexp.new(:result, @current_module, @current_class, @current_method, exp).line(exp.line)
95
- end
96
-
77
+ @calls << Sexp.new(:result, @current_module, @current_class, @current_method, exp).line(exp.line)
97
78
  end
98
79
 
99
- #Normally FindCall won't match a method invocation that is the target of
100
- #another call, such as:
101
- #
102
- # User.find(:first, :conditions => "user = '#{params['user']}').name
103
- #
104
- #A search for User.find will not match this unless @in_depth is true.
105
- if @in_depth and call? exp.target
106
- process exp.target
107
- end
108
-
109
80
  exp
110
81
  end
111
82
 
@@ -123,8 +94,6 @@ class Brakeman::FindCall < Brakeman::BasicProcessor
123
94
  case exp.node_type
124
95
  when :ivar, :lvar, :const, :lit
125
96
  exp.value
126
- when :true, :false
127
- exp.node_type
128
97
  when :colon2
129
98
  class_name exp
130
99
  else
@@ -141,43 +110,13 @@ class Brakeman::FindCall < Brakeman::BasicProcessor
141
110
  when Symbol
142
111
  if search_terms == item
143
112
  true
144
- elsif sexp? item
145
- is_instance_of? item, search_terms
146
113
  else
147
114
  false
148
115
  end
149
- when Sexp
150
- search_terms == item
151
116
  when Enumerable
152
117
  if search_terms.empty?
153
118
  item == nil
154
- else
155
- search_terms.each do|term|
156
- if match(term, item)
157
- return true
158
- end
159
- end
160
- false
161
119
  end
162
- when Regexp
163
- search_terms.match item.to_s
164
- when nil
165
- true
166
- else
167
- raise "Cannot match #{search_terms} and #{item}"
168
- end
169
- end
170
-
171
- #Checks if +item+ is an instance of +klass+ by looking for Klass.new
172
- def is_instance_of? item, klass
173
- if call? item
174
- if sexp? item.target
175
- item.method == :new and item.target.node_type == :const and item.target.value == klass
176
- else
177
- item.method == :new and item.target == klass
178
- end
179
- else
180
- false
181
120
  end
182
121
  end
183
122
  end
@@ -13,9 +13,9 @@ module Brakeman::ModuleHelper
13
13
 
14
14
  if @tracker.libs[name]
15
15
  @current_module = @tracker.libs[name]
16
- @current_module.add_file @file_name, exp
16
+ @current_module.add_file @current_file, exp
17
17
  else
18
- @current_module = tracker_class.new name, parent, @file_name, exp, @tracker
18
+ @current_module = tracker_class.new name, parent, @current_file, exp, @tracker
19
19
  @tracker.libs[name] = @current_module
20
20
  end
21
21
 
@@ -45,9 +45,9 @@ module Brakeman::ModuleHelper
45
45
 
46
46
  if collection[name]
47
47
  @current_class = collection[name]
48
- @current_class.add_file @file_name, exp
48
+ @current_class.add_file @current_file, exp
49
49
  else
50
- @current_class = tracker_class.new name, parent, @file_name, exp, @tracker
50
+ @current_class = tracker_class.new name, parent, @current_file, exp, @tracker
51
51
  collection[name] = @current_class
52
52
  end
53
53
 
@@ -85,9 +85,9 @@ module Brakeman::ModuleHelper
85
85
  @current_method = nil
86
86
 
87
87
  if @current_class
88
- @current_class.add_method @visibility, name, res, @file_name
88
+ @current_class.add_method @visibility, name, res, @current_file
89
89
  elsif @current_module
90
- @current_module.add_method @visibility, name, res, @file_name
90
+ @current_module.add_method @visibility, name, res, @current_file
91
91
  end
92
92
  res
93
93
  end
@@ -101,9 +101,9 @@ module Brakeman::ModuleHelper
101
101
  @current_method = nil
102
102
 
103
103
  if @current_class
104
- @current_class.add_method @visibility, name, res, @file_name
104
+ @current_class.add_method @visibility, name, res, @current_file
105
105
  elsif @current_module
106
- @current_module.add_method @visibility, name, res, @file_name
106
+ @current_module.add_method @visibility, name, res, @current_file
107
107
  end
108
108
 
109
109
  res
@@ -73,10 +73,10 @@ module Brakeman::ProcessorHelper
73
73
  end
74
74
  end
75
75
 
76
- def current_file_name
76
+ def current_file
77
77
  case
78
- when @file_name
79
- @file_name
78
+ when @current_file
79
+ @current_file
80
80
  when @current_class.is_a?(Brakeman::Collection)
81
81
  @current_class.file
82
82
  when @current_module.is_a?(Brakeman::Collection)
@@ -27,9 +27,9 @@ class Brakeman::Rails2ConfigProcessor < Brakeman::BasicProcessor
27
27
  end
28
28
 
29
29
  #Use this method to process configuration file
30
- def process_config src, file_name
31
- @file_name = file_name
32
- res = Brakeman::ConfigAliasProcessor.new.process_safely(src, nil, file_name)
30
+ def process_config src, current_file
31
+ @current_file = current_file
32
+ res = Brakeman::ConfigAliasProcessor.new.process_safely(src, nil, current_file)
33
33
  process res
34
34
  end
35
35
 
@@ -75,7 +75,7 @@ class Brakeman::Rails2ConfigProcessor < Brakeman::BasicProcessor
75
75
  def process_cdecl exp
76
76
  #Set Rails version required
77
77
  if exp.lhs == :RAILS_GEM_VERSION
78
- @tracker.config.rails_version = exp.rhs.value
78
+ @tracker.config.set_rails_version exp.rhs.value
79
79
  end
80
80
 
81
81
  exp
@@ -16,7 +16,7 @@ class Brakeman::Rails2RoutesProcessor < Brakeman::BasicProcessor
16
16
  @prefix = [] #Controller name prefix (a module name, usually)
17
17
  @current_controller = nil
18
18
  @with_options = nil #For use inside map.with_options
19
- @file_name = "config/routes.rb"
19
+ @current_file = "config/routes.rb"
20
20
  end
21
21
 
22
22
  #Call this with parsed route file information.
@@ -24,7 +24,7 @@ class Brakeman::Rails2RoutesProcessor < Brakeman::BasicProcessor
24
24
  #This method first calls RouteAliasProcessor#process_safely on the +exp+,
25
25
  #so it does not modify the +exp+.
26
26
  def process_routes exp
27
- process Brakeman::RouteAliasProcessor.new.process_safely(exp, nil, @file_name)
27
+ process Brakeman::RouteAliasProcessor.new.process_safely(exp, nil, @current_file)
28
28
  end
29
29
 
30
30
  #Looking for mapping of routes
@@ -24,9 +24,9 @@ class Brakeman::Rails3ConfigProcessor < Brakeman::BasicProcessor
24
24
  end
25
25
 
26
26
  #Use this method to process configuration file
27
- def process_config src, file_name
28
- @file_name = file_name
29
- res = Brakeman::AliasProcessor.new(@tracker).process_safely(src, nil, @file_name)
27
+ def process_config src, current_file
28
+ @current_file = current_file
29
+ res = Brakeman::AliasProcessor.new(@tracker).process_safely(src, nil, @current_file)
30
30
  process res
31
31
  end
32
32
 
@@ -17,11 +17,11 @@ class Brakeman::Rails3RoutesProcessor < Brakeman::BasicProcessor
17
17
  @current_controller = nil
18
18
  @with_options = nil #For use inside map.with_options
19
19
  @controller_block = false
20
- @file_name = "config/routes.rb"
20
+ @current_file = "config/routes.rb"
21
21
  end
22
22
 
23
23
  def process_routes exp
24
- process Brakeman::AliasProcessor.new.process_safely(exp, nil, @file_name)
24
+ process Brakeman::AliasProcessor.new.process_safely(exp, nil, @current_file)
25
25
  end
26
26
 
27
27
  def process_call exp
@@ -36,7 +36,7 @@ module Brakeman::RenderHelper
36
36
 
37
37
  #Determines file name for partial and then processes it
38
38
  def process_partial name, args, line
39
- if name == "" or !(string? name or symbol? name)
39
+ if !(string? name or symbol? name) or name.value == ""
40
40
  return
41
41
  end
42
42
 
@@ -148,7 +148,7 @@ module Brakeman::RenderHelper
148
148
  #This information will be stored in tracker.templates, but with a name
149
149
  #specifying this particular route. The original source should remain
150
150
  #pristine (so it can be processed within other environments).
151
- @tracker.processor.process_template name, src, template.type, called_from
151
+ @tracker.processor.process_template name, src, template.type, called_from, template.file
152
152
  end
153
153
  end
154
154
 
@@ -83,7 +83,7 @@ module Brakeman
83
83
  end
84
84
 
85
85
  def map &block
86
- @path.map &block
86
+ @path.map(&block)
87
87
  end
88
88
 
89
89
  def to_a
@@ -114,6 +114,23 @@ module Brakeman
114
114
  JSON.generate(@path)
115
115
  end
116
116
 
117
+ def with_relative_paths
118
+ @path.map do |loc|
119
+ r = loc.dup
120
+
121
+ if r[:file]
122
+ r[:file] = r[:file].relative
123
+ end
124
+
125
+ if r[:rendered] and r[:rendered][:file]
126
+ r[:rendered] = r[:rendered].dup
127
+ r[:rendered][:file] = r[:rendered][:file].relative
128
+ end
129
+
130
+ r
131
+ end
132
+ end
133
+
117
134
  def initialize_copy original
118
135
  @path = original.path.dup
119
136
  self
@@ -9,15 +9,15 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
9
9
 
10
10
  def initialize tracker
11
11
  super
12
- @file_name = nil
12
+ @current_file = nil
13
13
  @alias_processor = Brakeman::AliasProcessor.new tracker
14
14
  @current_module = nil
15
15
  @current_class = nil
16
16
  @initializer_env = nil
17
17
  end
18
18
 
19
- def process_library src, file_name = nil
20
- @file_name = file_name
19
+ def process_library src, current_file = @current_file
20
+ @current_file = current_file
21
21
  process src
22
22
  end
23
23
 
@@ -41,10 +41,10 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
41
41
 
42
42
  if @current_class
43
43
  exp.body = process_all! exp.body
44
- @current_class.add_method :public, exp.method_name, exp, @file_name
44
+ @current_class.add_method :public, exp.method_name, exp, @current_file
45
45
  elsif @current_module
46
46
  exp.body = process_all! exp.body
47
- @current_module.add_method :public, exp.method_name, exp, @file_name
47
+ @current_module.add_method :public, exp.method_name, exp, @current_file
48
48
  end
49
49
 
50
50
  exp
@@ -12,24 +12,23 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
12
12
  @current_method = nil
13
13
  @current_module = nil
14
14
  @visibility = :public
15
- @file_name = nil
15
+ @current_file = nil
16
16
  end
17
17
 
18
18
  #Process model source
19
- def process_model src, file_name = nil
20
- @file_name = file_name
19
+ def process_model src, current_file = @current_file
20
+ @current_file = current_file
21
21
  process src
22
22
  end
23
23
 
24
24
  #s(:class, NAME, PARENT, BODY)
25
25
  def process_class exp
26
26
  name = class_name(exp.class_name)
27
- parent = class_name(exp.parent_name)
28
27
 
29
28
  #If inside an inner class we treat it as a library.
30
29
  if @current_class
31
30
  Brakeman.debug "[Notice] Treating inner class as library: #{name}"
32
- Brakeman::LibraryProcessor.new(@tracker).process_library exp, @file_name
31
+ Brakeman::LibraryProcessor.new(@tracker).process_library exp, @current_file
33
32
  return exp
34
33
  end
35
34
 
@@ -8,6 +8,11 @@ require 'brakeman/util'
8
8
  class Brakeman::OutputProcessor < Ruby2Ruby
9
9
  include Brakeman::Util
10
10
 
11
+ def initialize *args
12
+ super
13
+ @user_input = nil
14
+ end
15
+
11
16
  #Copies +exp+ and then formats it.
12
17
  def format exp, user_input = nil, &block
13
18
  @user_input = user_input