brakeman 2.5.0 → 2.6.0

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