brakeman 2.5.0 → 2.6.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 (37) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CHANGES +14 -0
  5. data/README.md +6 -28
  6. data/lib/brakeman/checks/base_check.rb +5 -4
  7. data/lib/brakeman/checks/check_basic_auth.rb +1 -2
  8. data/lib/brakeman/checks/check_default_routes.rb +65 -15
  9. data/lib/brakeman/checks/check_detailed_exceptions.rb +5 -4
  10. data/lib/brakeman/checks/check_filter_skipping.rb +1 -1
  11. data/lib/brakeman/checks/check_forgery_setting.rb +9 -9
  12. data/lib/brakeman/checks/check_model_attr_accessible.rb +1 -1
  13. data/lib/brakeman/checks/check_model_attributes.rb +3 -3
  14. data/lib/brakeman/checks/check_model_serialize.rb +1 -1
  15. data/lib/brakeman/checks/check_redirect.rb +27 -6
  16. data/lib/brakeman/checks/check_render.rb +2 -2
  17. data/lib/brakeman/checks/check_skip_before_filter.rb +2 -2
  18. data/lib/brakeman/checks/check_sql.rb +2 -1
  19. data/lib/brakeman/file_parser.rb +49 -0
  20. data/lib/brakeman/options.rb +1 -1
  21. data/lib/brakeman/parsers/template_parser.rb +88 -0
  22. data/lib/brakeman/processors/alias_processor.rb +25 -2
  23. data/lib/brakeman/processors/controller_alias_processor.rb +3 -3
  24. data/lib/brakeman/processors/controller_processor.rb +106 -54
  25. data/lib/brakeman/processors/lib/rails3_route_processor.rb +27 -12
  26. data/lib/brakeman/processors/lib/route_helper.rb +1 -1
  27. data/lib/brakeman/processors/library_processor.rb +37 -28
  28. data/lib/brakeman/processors/model_processor.rb +117 -34
  29. data/lib/brakeman/report/report_base.rb +1 -1
  30. data/lib/brakeman/rescanner.rb +84 -35
  31. data/lib/brakeman/scanner.rb +84 -148
  32. data/lib/brakeman/tracker.rb +32 -12
  33. data/lib/brakeman/util.rb +13 -4
  34. data/lib/brakeman/version.rb +1 -1
  35. data/lib/brakeman/warning_codes.rb +2 -1
  36. metadata +6 -4
  37. metadata.gz.sig +0 -0
@@ -89,18 +89,17 @@ class Brakeman::Rails3RoutesProcessor < Brakeman::BaseProcessor
89
89
  second_arg = exp.second_arg
90
90
  last_arg = exp.last_arg
91
91
 
92
- #Check if there is an unrestricted action parameter
93
- action_variable = false
94
-
95
92
  if string? first_arg
96
- matcher = first_arg.value
97
93
 
94
+ matcher = first_arg.value
98
95
  if matcher == ':controller(/:action(/:id(.:format)))' or
99
- matcher.include? ':controller' and matcher.include? ':action' #Default routes
96
+ matcher.include? ':controller' and action_route?(matcher) #Default routes
100
97
  @tracker.routes[:allow_all_actions] = first_arg
101
98
  return exp
102
- elsif matcher.include? ':action'
103
- action_variable = true
99
+ elsif action_route?(first_arg)
100
+ if hash? second_arg and controller_name = hash_access(second_arg, :controller)
101
+ loose_action(controller_name, "matched") #TODO: Parse verbs
102
+ end
104
103
  elsif second_arg.nil? and in_controller_block? and not matcher.include? ":"
105
104
  add_route matcher
106
105
  end
@@ -123,7 +122,6 @@ class Brakeman::Rails3RoutesProcessor < Brakeman::BaseProcessor
123
122
  add_route v
124
123
  end
125
124
 
126
- action_variable = false
127
125
  when :to
128
126
  if string? v
129
127
  add_route_from_string v[1]
@@ -135,10 +133,6 @@ class Brakeman::Rails3RoutesProcessor < Brakeman::BaseProcessor
135
133
  end
136
134
  end
137
135
 
138
- if action_variable
139
- @tracker.routes[@current_controller] = :allow_all_actions
140
- end
141
-
142
136
  @current_controller = nil unless in_controller_block?
143
137
  exp
144
138
  end
@@ -169,9 +163,17 @@ class Brakeman::Rails3RoutesProcessor < Brakeman::BaseProcessor
169
163
  elsif in_controller_block? and symbol? v
170
164
  add_route v
171
165
  end
166
+ elsif action_route?(first_arg)
167
+ if hash? second_arg and controller_name = hash_access(second_arg, :controller)
168
+ loose_action(controller_name, exp.method)
169
+ end
172
170
  end
173
171
  end
174
172
  elsif string? first_arg
173
+ if first_arg.value.include? ':controller' and action_route?(first_arg) #Default routes
174
+ @tracker.routes[:allow_all_actions] = first_arg
175
+ end
176
+
175
177
  route = first_arg.value.split "/"
176
178
  if route.length != 2
177
179
  add_route route[0]
@@ -287,4 +289,17 @@ class Brakeman::Rails3RoutesProcessor < Brakeman::BaseProcessor
287
289
  yield
288
290
  @controller_block = prev_block
289
291
  end
292
+
293
+ def action_route? arg
294
+ if string? arg
295
+ arg = arg.value
296
+ end
297
+
298
+ arg.is_a? String and (arg.include? ":action" or arg.include? "*action")
299
+ end
300
+
301
+ def loose_action controller_name, verb = "any"
302
+ self.current_controller = controller_name.value
303
+ @tracker.routes[@current_controller] = [:allow_all_actions, {:allow_verb => verb}]
304
+ end
290
305
  end
@@ -39,7 +39,7 @@ module Brakeman::RouteHelper
39
39
 
40
40
  routes = @tracker.routes[@current_controller]
41
41
 
42
- if routes and routes != :allow_all_actions
42
+ if routes and not routes.include? :allow_all_actions
43
43
  routes << route
44
44
  end
45
45
  end
@@ -8,6 +8,8 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
8
8
  super
9
9
  @file_name = nil
10
10
  @alias_processor = Brakeman::AliasProcessor.new tracker
11
+ @current_module = nil
12
+ @current_class = nil
11
13
  end
12
14
 
13
15
  def process_library src, file_name = nil
@@ -17,7 +19,8 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
17
19
 
18
20
  def process_class exp
19
21
  name = class_name(exp.class_name)
20
-
22
+ parent = class_name exp.parent_name
23
+
21
24
  if @current_class
22
25
  outer_class = @current_class
23
26
  name = (outer_class[:name].to_s + "::" + name.to_s).to_sym
@@ -29,18 +32,20 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
29
32
 
30
33
  if @tracker.libs[name]
31
34
  @current_class = @tracker.libs[name]
35
+ @current_class[:files] << @file_name unless @current_class[:files].include? @file_name
36
+ @current_class[:src][@file_name] = exp
32
37
  else
33
- parent = class_name exp.parent_name
34
-
35
- @current_class = { :name => name,
36
- :parent => parent,
37
- :includes => [],
38
- :public => {},
39
- :private => {},
40
- :protected => {},
41
- :src => exp,
42
- :file => @file_name }
43
-
38
+ @current_class = {
39
+ :name => name,
40
+ :parent => parent,
41
+ :includes => [],
42
+ :public => {},
43
+ :private => {},
44
+ :protected => {},
45
+ :src => { @file_name => exp },
46
+ :files => [ @file_name ]
47
+ }
48
+
44
49
  @tracker.libs[name] = @current_class
45
50
  end
46
51
 
@@ -59,8 +64,8 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
59
64
  name = class_name(exp.module_name)
60
65
 
61
66
  if @current_module
62
- outer_class = @current_module
63
- name = (outer_class[:name].to_s + "::" + name.to_s).to_sym
67
+ outer_module = @current_module
68
+ name = (outer_module[:name].to_s + "::" + name.to_s).to_sym
64
69
  end
65
70
 
66
71
  if @current_class
@@ -69,22 +74,26 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
69
74
 
70
75
  if @tracker.libs[name]
71
76
  @current_module = @tracker.libs[name]
77
+ @current_module[:files] << @file_name unless @current_module[:files].include? @file_name
78
+ @current_module[:src][@file_name] = exp
72
79
  else
73
- @current_module = { :name => name,
74
- :includes => [],
75
- :public => {},
76
- :private => {},
77
- :protected => {},
78
- :src => exp,
79
- :file => @file_name }
80
-
80
+ @current_module = {
81
+ :name => name,
82
+ :includes => [],
83
+ :public => {},
84
+ :private => {},
85
+ :protected => {},
86
+ :src => { @file_name => exp },
87
+ :files => [ @file_name ]
88
+ }
89
+
81
90
  @tracker.libs[name] = @current_module
82
91
  end
83
92
 
84
93
  exp.body = process_all! exp.body
85
94
 
86
- if outer_class
87
- @current_module = outer_class
95
+ if outer_module
96
+ @current_module = outer_module
88
97
  else
89
98
  @current_module = nil
90
99
  end
@@ -97,9 +106,9 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
97
106
  exp.node_type = :methdef
98
107
 
99
108
  if @current_class
100
- @current_class[:public][exp.method_name] = exp
109
+ @current_class[:public][exp.method_name] = { :src => exp, :file => @file_name }
101
110
  elsif @current_module
102
- @current_module[:public][exp.method_name] = exp
111
+ @current_module[:public][exp.method_name] = { :src => exp, :file => @file_name }
103
112
  end
104
113
 
105
114
  exp
@@ -110,9 +119,9 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
110
119
  exp.node_type = :selfdef
111
120
 
112
121
  if @current_class
113
- @current_class[:public][exp.method_name] = exp
122
+ @current_class[:public][exp.method_name] = { :src => exp, :file => @file_name }
114
123
  elsif @current_module
115
- @current_module[:public][exp.method_name] = exp
124
+ @current_module[:public][exp.method_name] = { :src => exp, :file => @file_name }
116
125
  end
117
126
 
118
127
  exp
@@ -6,9 +6,10 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
6
6
  ASSOCIATIONS = Set[:belongs_to, :has_one, :has_many, :has_and_belongs_to_many]
7
7
 
8
8
  def initialize tracker
9
- super
10
- @model = nil
9
+ super
10
+ @current_class = nil
11
11
  @current_method = nil
12
+ @current_module = nil
12
13
  @visibility = :public
13
14
  @file_name = nil
14
15
  end
@@ -21,34 +22,104 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
21
22
 
22
23
  #s(:class, NAME, PARENT, BODY)
23
24
  def process_class exp
24
- name = class_name exp.class_name
25
+ name = class_name(exp.class_name)
26
+ parent = class_name(exp.parent_name)
27
+
28
+ #If inside an inner class we treat it as a library.
29
+ if @current_class
30
+ Brakeman.debug "[Notice] Treating inner class as library: #{name}"
31
+ Brakeman::LibraryProcessor.new(@tracker).process_library exp, @file_name
32
+ return exp
33
+ end
25
34
 
26
- if @model
27
- Brakeman.debug "[Notice] Skipping inner class: #{name}"
28
- ignore
29
- else
30
- parent = class_name exp.parent_name
35
+ if @current_class
36
+ outer_class = @current_class
37
+ name = (outer_class[:name].to_s + "::" + name.to_s).to_sym
38
+ end
39
+
40
+ if @current_module
41
+ name = (@current_module[:name].to_s + "::" + name.to_s).to_sym
42
+ end
31
43
 
32
- @model = { :name => name,
44
+ if @tracker.models[name]
45
+ @current_class = @tracker.models[name]
46
+ @current_class[:files] << @file_name unless @current_class[:files].include? @file_name
47
+ @current_class[:src][@file_name] = exp
48
+ else
49
+ @current_class = {
50
+ :name => name,
33
51
  :parent => parent,
34
52
  :includes => [],
35
53
  :public => {},
36
54
  :private => {},
37
55
  :protected => {},
38
56
  :options => {},
57
+ :src => { @file_name => exp },
39
58
  :associations => {},
40
- :file => @file_name }
41
- @tracker.models[@model[:name]] = @model
42
- exp.body = process_all! exp.body
43
- @model = nil
44
- exp
59
+ :files => [ @file_name ]
60
+ }
61
+
62
+ @tracker.models[name] = @current_class
63
+ end
64
+
65
+ exp.body = process_all! exp.body
66
+
67
+ if outer_class
68
+ @current_class = outer_class
69
+ else
70
+ @current_class = nil
45
71
  end
72
+
73
+ exp
74
+ end
75
+
76
+ def process_module exp
77
+ name = class_name(exp.class_name)
78
+
79
+ if @current_module
80
+ outer_module = @current_module
81
+ name = (outer_module[:name].to_s + "::" + name.to_s).to_sym
82
+ end
83
+
84
+ if @current_class
85
+ name = (@current_class[:name].to_s + "::" + name.to_s).to_sym
86
+ end
87
+
88
+ if @tracker.libs[name]
89
+ @current_module = @tracker.libs[name]
90
+ @current_module[:files] << @file_name unless @current_module[:files].include? @file_name
91
+ @current_module[:src][@file_name] = exp
92
+ else
93
+ @current_module = {
94
+ :name => name,
95
+ :includes => [],
96
+ :public => {},
97
+ :private => {},
98
+ :protected => {},
99
+ :options => {},
100
+ :src => { @file_name => exp },
101
+ :associations => {},
102
+ :files => [ @file_name ]
103
+ }
104
+
105
+ @tracker.libs[name] = @current_module
106
+ end
107
+
108
+ exp.body = process_all! exp.body
109
+
110
+ if outer_module
111
+ @current_module = outer_module
112
+ else
113
+ @current_module = nil
114
+ end
115
+
116
+ exp
46
117
  end
47
118
 
48
119
  #Handle calls outside of methods,
49
120
  #such as include, attr_accessible, private, etc.
50
121
  def process_call exp
51
- return exp unless @model
122
+ return exp unless @current_class
52
123
  target = exp.target
53
124
  if sexp? target
54
125
  target = process target
@@ -65,36 +136,36 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
65
136
  when :private, :protected, :public
66
137
  @visibility = method
67
138
  when :attr_accessible
68
- @model[:attr_accessible] ||= []
139
+ @current_class[:attr_accessible] ||= []
69
140
  else
70
141
  #??
71
142
  end
72
143
  else
73
144
  case method
74
145
  when :include
75
- @model[:includes] << class_name(first_arg) if @model
146
+ @current_class[:includes] << class_name(first_arg) if @current_class
76
147
  when :attr_accessible
77
- @model[:attr_accessible] ||= []
148
+ @current_class[:attr_accessible] ||= []
78
149
  args = []
79
150
 
80
151
  exp.each_arg do |e|
81
152
  if node_type? e, :lit
82
153
  args << e.value
83
154
  elsif hash? e
84
- @model[:options][:role_accessible] ||= []
85
- @model[:options][:role_accessible].concat args
155
+ @current_class[:options][:role_accessible] ||= []
156
+ @current_class[:options][:role_accessible].concat args
86
157
  end
87
158
  end
88
159
 
89
- @model[:attr_accessible].concat args
160
+ @current_class[:attr_accessible].concat args
90
161
  else
91
- if @model
162
+ if @current_class
92
163
  if ASSOCIATIONS.include? method
93
- @model[:associations][method] ||= []
94
- @model[:associations][method].concat exp.args
164
+ @current_class[:associations][method] ||= []
165
+ @current_class[:associations][method].concat exp.args
95
166
  else
96
- @model[:options][method] ||= []
97
- @model[:options][method] << exp.arglist.line(exp.line)
167
+ @current_class[:options][method] ||= []
168
+ @current_class[:options][method] << exp.arglist.line(exp.line)
98
169
  end
99
170
  end
100
171
  end
@@ -109,27 +180,36 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
109
180
 
110
181
  #Add method definition to tracker
111
182
  def process_defn exp
112
- return exp unless @model
183
+ return exp unless @current_class
113
184
  name = exp.method_name
114
185
 
115
186
  @current_method = name
116
187
  res = Sexp.new :methdef, name, exp.formal_args, *process_all!(exp.body)
117
188
  res.line(exp.line)
118
189
  @current_method = nil
119
- if @model
120
- list = @model[@visibility]
121
- list[name] = res
190
+
191
+ if @current_class
192
+ @current_class[@visibility][name] = { :src => res, :file => @file_name }
193
+ elsif @current_module
194
+ @current_module[@visibility][name] = { :src => res, :file => @file_name }
122
195
  end
196
+
123
197
  res
124
198
  end
125
199
 
126
200
  #Add method definition to tracker
127
201
  def process_defs exp
128
- return exp unless @model
202
+ return exp unless @current_class
129
203
  name = exp.method_name
130
204
 
131
205
  if exp[1].node_type == :self
132
- target = @model[:name]
206
+ if @current_class
207
+ target = @current_class[:name]
208
+ elsif @current_module
209
+ target = @current_module
210
+ else
211
+ target = nil
212
+ end
133
213
  else
134
214
  target = class_name exp[1]
135
215
  end
@@ -138,8 +218,11 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
138
218
  res = Sexp.new :selfdef, target, name, exp.formal_args, *process_all!(exp.body)
139
219
  res.line(exp.line)
140
220
  @current_method = nil
141
- if @model
142
- @model[@visibility][name] = res unless @model.nil?
221
+
222
+ if @current_class
223
+ @current_class[@visibility][name] = { :src => res, :file => @file_name }
224
+ elsif @current_module
225
+ @current_module[@visibility][name] = { :src => res, :file => @file_name }
143
226
  end
144
227
  res
145
228
  end
@@ -39,7 +39,7 @@ class Brakeman::Report::Base
39
39
  name = name.to_sym
40
40
  c = tracker.controllers[name]
41
41
 
42
- if tracker.routes[:allow_all_actions] or tracker.routes[name] == :allow_all_actions
42
+ if tracker.routes.include? :allow_all_actions or (tracker.routes[name] and tracker.routes[name].include? :allow_all_actions)
43
43
  routes = c[:public].keys.map{|e| e.to_s}.sort.join(", ")
44
44
  elsif tracker.routes[name].nil?
45
45
  #No routes defined for this controller.