brakeman-min 3.2.1 → 3.3.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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +18 -0
  3. data/bin/brakeman +1 -1
  4. data/lib/brakeman.rb +9 -1
  5. data/lib/brakeman/call_index.rb +1 -1
  6. data/lib/brakeman/checks/check_content_tag.rb +1 -1
  7. data/lib/brakeman/checks/check_cross_site_scripting.rb +1 -1
  8. data/lib/brakeman/checks/check_execute.rb +4 -0
  9. data/lib/brakeman/checks/check_forgery_setting.rb +3 -2
  10. data/lib/brakeman/checks/check_link_to.rb +1 -1
  11. data/lib/brakeman/checks/check_link_to_href.rb +2 -2
  12. data/lib/brakeman/checks/check_mass_assignment.rb +1 -1
  13. data/lib/brakeman/checks/check_redirect.rb +6 -0
  14. data/lib/brakeman/checks/check_secrets.rb +40 -0
  15. data/lib/brakeman/checks/check_sql.rb +1 -1
  16. data/lib/brakeman/processor.rb +6 -6
  17. data/lib/brakeman/processors/alias_processor.rb +29 -3
  18. data/lib/brakeman/processors/base_processor.rb +35 -4
  19. data/lib/brakeman/processors/controller_alias_processor.rb +4 -4
  20. data/lib/brakeman/processors/haml_template_processor.rb +1 -1
  21. data/lib/brakeman/processors/lib/basic_processor.rb +18 -0
  22. data/lib/brakeman/processors/lib/rails2_config_processor.rb +3 -2
  23. data/lib/brakeman/processors/lib/rails2_route_processor.rb +2 -1
  24. data/lib/brakeman/processors/lib/rails3_config_processor.rb +3 -2
  25. data/lib/brakeman/processors/lib/rails3_route_processor.rb +2 -1
  26. data/lib/brakeman/processors/template_alias_processor.rb +4 -4
  27. data/lib/brakeman/processors/template_processor.rb +1 -0
  28. data/lib/brakeman/report/report_codeclimate.rb +2 -1
  29. data/lib/brakeman/scanner.rb +1 -1
  30. data/lib/brakeman/tracker.rb +11 -1
  31. data/lib/brakeman/tracker/constants.rb +101 -0
  32. data/lib/brakeman/util.rb +4 -0
  33. data/lib/brakeman/version.rb +1 -1
  34. data/lib/brakeman/warning_codes.rb +1 -0
  35. data/lib/ruby_parser/bm_sexp.rb +6 -0
  36. metadata +5 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 17de56675dc2f00c7a1b4c10e833501ac3b039c2
4
- data.tar.gz: 8c9399690ad552f470057f3945248784e1ff7cb4
3
+ metadata.gz: bfbe9bf6ab37921809b33145342e4bcd6df55e8e
4
+ data.tar.gz: 62f41f3c6a63e4f1b9c662b28779cb821d60a7b9
5
5
  SHA512:
6
- metadata.gz: ab231cd491eb31cab3ab399788c2bfab81dd1a79a231bb303e409ab67e66688ba6b2044884f6fb2418c2b408c8f33e69dd7d6cde9188aa9122c4b7647c01de78
7
- data.tar.gz: cb931ae85cf06d0607a25d6c4ce10f5f82b11e5a8e7bfa9f31a70a49f72aa769602f8868756f2fb21972ee21cc7cd0555241654bf961859ee0a76e5913d4645b
6
+ metadata.gz: 3724d2c9aad208a2c5197decc4e72e46e9306a7745aaecdd6326bb8357367941b6f14586163bab5e299928cec1acb1d4f994f884441b78f521580cc0b26cbbcf
7
+ data.tar.gz: 26f0ab2c6871b2a304773c7d93c1b25e2958adef16f97d96257a39ba8cf1c085c1451e5180754e2ae18f197b7b5efc2370e081bd21ec6cb2ab17bb9bc554321d
data/CHANGES CHANGED
@@ -1,3 +1,21 @@
1
+ # 3.3.0
2
+
3
+ * Skip processing obviously false if branches (more broadly)
4
+ * Skip if branches with `Rails.env.test?`
5
+ * Return exit code `4` if no Rails application is detected
6
+ * Avoid warning about mass assignment with `params.slice`
7
+ * Avoid warning about `u` helper (Chad Dollins)
8
+ * Add optional check for secrets in source code
9
+ * Process `Array#first`
10
+ * Allow non-Hash arguments in `protect_from_forgery` (Jason Yeo)
11
+ * Avoid warning on `popen` with array
12
+ * Bundle all dependencies in gem
13
+ * Track constants globally
14
+ * Handle HAML `find_and_preserve` with a block
15
+ * [Code Climate engine] When possible, output to /dev/stdout (Gordon Diggs)
16
+ * [Code Climate engine] Remove nil entries from include_paths (Gordon Diggs)
17
+ * [Code Climate engine] Report end lines for issues (Gordon Diggs)
18
+
1
19
  # 3.2.1
2
20
 
3
21
  * Remove `multi_json` dependency from `bin/brakeman`
data/bin/brakeman CHANGED
@@ -85,5 +85,5 @@ begin
85
85
  end
86
86
  rescue Brakeman::NoApplication => e
87
87
  $stderr.puts e.message
88
- exit 1
88
+ exit Brakeman::No_App_Found_Exit_Code
89
89
  end
data/lib/brakeman.rb CHANGED
@@ -1,12 +1,20 @@
1
- require 'rubygems'
2
1
  require 'set'
3
2
 
3
+ path_load = "#{File.expand_path(File.dirname(__FILE__))}/../bundle/load.rb"
4
+
5
+ if File.exist? path_load
6
+ require path_load
7
+ end
8
+
4
9
  module Brakeman
5
10
 
6
11
  #This exit code is used when warnings are found and the --exit-on-warn
7
12
  #option is set
8
13
  Warnings_Found_Exit_Code = 3
9
14
 
15
+ #Exit code returned when no Rails application is detected
16
+ No_App_Found_Exit_Code = 4
17
+
10
18
  @debug = false
11
19
  @quiet = false
12
20
  @loaded_dependencies = []
@@ -53,7 +53,7 @@ class Brakeman::CallIndex
53
53
  elsif method
54
54
  calls = calls_by_method method
55
55
  else
56
- notify "Invalid arguments to CallCache#find_calls: #{options.inspect}"
56
+ raise "Invalid arguments to CallCache#find_calls: #{options.inspect}"
57
57
  end
58
58
 
59
59
  return [] if calls.nil?
@@ -24,7 +24,7 @@ class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
24
24
  :hidden_field, :hidden_field_tag, :image_tag, :label,
25
25
  :mail_to, :radio_button, :select,
26
26
  :submit_tag, :text_area, :text_field,
27
- :text_field_tag, :url_encode, :url_for,
27
+ :text_field_tag, :url_encode, :u, :url_for,
28
28
  :will_paginate].merge tracker.options[:safe_methods]
29
29
 
30
30
  @known_dangerous = []
@@ -286,7 +286,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
286
286
  :hidden_field, :hidden_field_tag, :image_tag, :label,
287
287
  :link_to, :mail_to, :radio_button, :select,
288
288
  :submit_tag, :text_area, :text_field,
289
- :text_field_tag, :url_encode, :url_for,
289
+ :text_field_tag, :url_encode, :u, :url_for,
290
290
  :will_paginate].merge tracker.options[:safe_methods]
291
291
 
292
292
  @models = tracker.models.keys
@@ -43,6 +43,10 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
43
43
  first_arg = call.first_arg
44
44
 
45
45
  case call.method
46
+ when :popen
47
+ unless array? first_arg
48
+ failure = include_user_input?(args) || dangerous_interp?(args)
49
+ end
46
50
  when :system, :exec
47
51
  failure = include_user_input?(first_arg) || dangerous_interp?(first_arg)
48
52
  else
@@ -13,7 +13,7 @@ class Brakeman::CheckForgerySetting < Brakeman::BaseCheck
13
13
  app_controller = tracker.controllers[:ApplicationController]
14
14
  return unless app_controller and app_controller.ancestor? :"ActionController::Base"
15
15
 
16
- if tracker.config.allow_forgery_protection?
16
+ if tracker.config.allow_forgery_protection?
17
17
  warn :controller => :ApplicationController,
18
18
  :warning_type => "Cross-Site Request Forgery",
19
19
  :warning_code => :csrf_protection_disabled,
@@ -53,7 +53,8 @@ class Brakeman::CheckForgerySetting < Brakeman::BaseCheck
53
53
  elsif version_between? "4.0.0", "100.0.0" and forgery_opts = app_controller.options[:protect_from_forgery]
54
54
 
55
55
  unless forgery_opts.is_a?(Array) and sexp?(forgery_opts.first) and
56
- access_arg = hash_access(forgery_opts.first.first_arg, :with) and access_arg.value == :exception
56
+ access_arg = hash_access(forgery_opts.first.first_arg, :with) and symbol? access_arg and
57
+ access_arg.value == :exception
57
58
 
58
59
  args = {
59
60
  :controller => :ApplicationController,
@@ -17,7 +17,7 @@ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
17
17
  :hidden_field, :hidden_field_tag, :image_tag, :label,
18
18
  :mail_to, :radio_button, :select,
19
19
  :submit_tag, :text_area, :text_field,
20
- :text_field_tag, :url_encode, :url_for,
20
+ :text_field_tag, :url_encode, :u, :url_for,
21
21
  :will_paginate].merge tracker.options[:safe_methods]
22
22
 
23
23
  @known_dangerous = []
@@ -15,9 +15,9 @@ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
15
15
  @ignore_methods = Set[:button_to, :check_box,
16
16
  :field_field, :fields_for, :hidden_field,
17
17
  :hidden_field, :hidden_field_tag, :image_tag, :label,
18
- :mail_to, :polymorphic_url, :radio_button, :select,
18
+ :mail_to, :polymorphic_url, :radio_button, :select, :slice,
19
19
  :submit_tag, :text_area, :text_field,
20
- :text_field_tag, :url_encode, :url_for,
20
+ :text_field_tag, :url_encode, :u, :url_for,
21
21
  :will_paginate].merge(tracker.options[:url_safe_methods] || [])
22
22
 
23
23
  @models = tracker.models.keys
@@ -160,7 +160,7 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
160
160
  # Look for and warn about uses of Parameters#permit! for mass assignment
161
161
  def check_permit!
162
162
  tracker.find_call(:method => :permit!).each do |result|
163
- if params? result[:call].target
163
+ if params? result[:call].target and not result[:chain].include? :slice
164
164
  warn_on_permit! result
165
165
  end
166
166
  end
@@ -38,6 +38,7 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
38
38
  if method == :redirect_to and
39
39
  not only_path?(call) and
40
40
  not explicit_host?(call.first_arg) and
41
+ not slice_call?(call.first_arg) and
41
42
  res = include_user_input?(call)
42
43
 
43
44
  add_result result
@@ -206,4 +207,9 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
206
207
 
207
208
  model.association? meth
208
209
  end
210
+
211
+ def slice_call? exp
212
+ return unless call? exp
213
+ exp.method == :slice
214
+ end
209
215
  end
@@ -0,0 +1,40 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckSecrets < Brakeman::BaseCheck
4
+ Brakeman::Checks.add_optional self
5
+
6
+ @description = "Checks for secrets stored in source code"
7
+
8
+ def run_check
9
+ check_constants
10
+ end
11
+
12
+ def check_constants
13
+ @warned = Set.new
14
+
15
+ @tracker.constants.each do |constant|
16
+ name = constant.name.last
17
+ value = constant.value
18
+
19
+ if string? value and not value.value.empty? and looks_like_secret? name
20
+ match = [name, value, value.line]
21
+
22
+ unless @warned.include? match
23
+ @warned << match
24
+
25
+ warn :warning_code => :secret_in_source,
26
+ :warning_type => "Authentication",
27
+ :message => "Hardcoded value for #{name} in source code",
28
+ :confidence => CONFIDENCE[:med],
29
+ :file => constant.file,
30
+ :line => constant.line
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ def looks_like_secret? name
37
+ # REST_AUTH_SITE_KEY is the pepper in Devise
38
+ name.match /password|secret|(rest_auth_site|api)_key$/i
39
+ end
40
+ end
@@ -264,7 +264,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
264
264
  end
265
265
 
266
266
  if request_value? arg
267
- unless call? arg and params? arg.target and arg.method == :permit
267
+ unless call? arg and params? arg.target and [:permit, :slice].include? arg.method
268
268
  # Model.where(params[:where])
269
269
  arg
270
270
  end
@@ -22,8 +22,8 @@ module Brakeman
22
22
  end
23
23
 
24
24
  #Process configuration file source
25
- def process_config src
26
- ConfigProcessor.new(@tracker).process_config src
25
+ def process_config src, file_name
26
+ ConfigProcessor.new(@tracker).process_config src, file_name
27
27
  end
28
28
 
29
29
  #Process Gemfile
@@ -88,10 +88,10 @@ module Brakeman
88
88
  end
89
89
 
90
90
  #Process source for initializing files
91
- def process_initializer name, src
92
- res = BaseProcessor.new(@tracker).process src
93
- res = AliasProcessor.new(@tracker).process res
94
- @tracker.initializers[Pathname.new(name).basename.to_s] = res
91
+ def process_initializer file_name, src
92
+ res = BaseProcessor.new(@tracker).process_file src, file_name
93
+ res = AliasProcessor.new(@tracker).process_safely res, nil, file_name
94
+ @tracker.initializers[Pathname.new(file_name).basename.to_s] = res
95
95
  end
96
96
 
97
97
  #Process source for a library file
@@ -16,7 +16,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
16
16
  #The recommended usage is:
17
17
  #
18
18
  # AliasProcessor.new.process_safely src
19
- def initialize tracker = nil
19
+ def initialize tracker = nil, file_name = nil
20
20
  super()
21
21
  @env = SexpProcessor::Environment.new
22
22
  @inside_if = false
@@ -28,6 +28,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
28
28
  @helper_method_info = Hash.new({})
29
29
  @or_depth_limit = (tracker && tracker.options[:branch_limit]) || 5 #arbitrary default
30
30
  @meth_env = nil
31
+ @file_name = file_name
31
32
  set_env_defaults
32
33
  end
33
34
 
@@ -39,7 +40,8 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
39
40
  #
40
41
  #This method returns a new Sexp with variables replaced with their values,
41
42
  #where possible.
42
- def process_safely src, set_env = nil
43
+ def process_safely src, set_env = nil, file_name = nil
44
+ @file_name = file_name
43
45
  @env = set_env || SexpProcessor::Environment.new
44
46
  @result = src.deep_clone
45
47
  process @result
@@ -73,8 +75,11 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
73
75
  def replace exp, int = 0
74
76
  return exp if int > 3
75
77
 
78
+
76
79
  if replacement = env[exp] and not duplicate? replacement
77
80
  replace(replacement.deep_clone(exp.line), int + 1)
81
+ elsif tracker and replacement = tracker.constant_lookup(exp) and not duplicate? replacement
82
+ replace(replacement.deep_clone(exp.line), int + 1)
78
83
  else
79
84
  exp
80
85
  end
@@ -82,6 +87,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
82
87
 
83
88
  ARRAY_CONST = s(:const, :Array)
84
89
  HASH_CONST = s(:const, :Hash)
90
+ RAILS_TEST = s(:call, s(:call, s(:const, :Rails), :env), :test?)
85
91
 
86
92
  #Process a method call.
87
93
  def process_call exp
@@ -110,8 +116,11 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
110
116
  return Sexp.new(:array, *exp.args)
111
117
  elsif target == HASH_CONST and method == :new and first_arg.nil? and !node_type?(@exp_context.last, :iter)
112
118
  return Sexp.new(:hash)
119
+ elsif exp == RAILS_TEST
120
+ return Sexp.new(:false)
113
121
  end
114
122
 
123
+
115
124
  #See if it is possible to simplify some basic cases
116
125
  #of addition/concatenation.
117
126
  case method
@@ -204,6 +213,10 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
204
213
  target = find_push_target(target_var)
205
214
  env[target] = exp unless target.nil? # Happens in TemplateAliasProcessor
206
215
  end
216
+ when :first
217
+ if array? target and first_arg.nil? and sexp? target[1]
218
+ exp = target[1]
219
+ end
207
220
  end
208
221
 
209
222
  exp
@@ -504,6 +517,19 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
504
517
  exp.rhs = process exp.rhs
505
518
  end
506
519
 
520
+ file = case
521
+ when @file_name
522
+ @file_name
523
+ when @current_class.is_a?(Brakeman::Collection)
524
+ @current_class.file
525
+ when @current_module.is_a?(Brakeman::Collection)
526
+ @current_module.file
527
+ else
528
+ nil
529
+ end
530
+
531
+ @tracker.add_constant exp.lhs, exp.rhs, :file => file if @tracker
532
+
507
533
  if exp.lhs.is_a? Symbol
508
534
  match = Sexp.new(:const, exp.lhs)
509
535
  else
@@ -543,7 +569,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
543
569
  @ignore_ifs = @tracker && @tracker.options[:ignore_ifs]
544
570
  end
545
571
 
546
- condition = process exp.condition
572
+ condition = exp.condition = process exp.condition
547
573
 
548
574
  #Check if a branch is obviously going to be taken
549
575
  if true? condition
@@ -13,7 +13,12 @@ class Brakeman::BaseProcessor < Brakeman::SexpProcessor
13
13
  super()
14
14
  @last = nil
15
15
  @tracker = tracker
16
- @current_template = @current_module = @current_class = @current_method = nil
16
+ @current_template = @current_module = @current_class = @current_method = @file_name = nil
17
+ end
18
+
19
+ def process_file exp, file_name
20
+ @file_name = file_name
21
+ process exp
17
22
  end
18
23
 
19
24
  def ignore
@@ -43,9 +48,19 @@ class Brakeman::BaseProcessor < Brakeman::SexpProcessor
43
48
  #Process an if statement.
44
49
  def process_if exp
45
50
  exp = exp.dup
46
- exp[1] = process exp.condition
47
- exp[2] = process exp.then_clause if exp.then_clause
48
- exp[3] = process exp.else_clause if exp.else_clause
51
+ condition = exp[1] = process exp.condition
52
+
53
+ if true? condition
54
+ exp[2] = process exp.then_clause if exp.then_clause
55
+ exp[3] = nil
56
+ elsif false? condition
57
+ exp[2] = nil
58
+ exp[3] = process exp.else_clause if exp.else_clause
59
+ else
60
+ exp[2] = process exp.then_clause if exp.then_clause
61
+ exp[3] = process exp.else_clause if exp.else_clause
62
+ end
63
+
49
64
  exp
50
65
  end
51
66
 
@@ -173,6 +188,22 @@ class Brakeman::BaseProcessor < Brakeman::SexpProcessor
173
188
  exp
174
189
  end
175
190
 
191
+ def process_cdecl exp
192
+ file = case
193
+ when @file_name
194
+ @file_name
195
+ when @current_class.is_a?(Brakeman::Collection)
196
+ @current_class.file
197
+ when @current_module.is_a?(Brakeman::Collection)
198
+ @current_module.file
199
+ else
200
+ nil
201
+ end
202
+
203
+ @tracker.add_constant exp.lhs, exp.rhs, :file => file if @tracker
204
+ exp
205
+ end
206
+
176
207
  #Convenience method for `make_render exp, true`
177
208
  def make_render_in_view exp
178
209
  make_render exp, true
@@ -20,13 +20,13 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
20
20
  @method_cache = {} #Cache method lookups
21
21
  end
22
22
 
23
- def process_controller name, src, file
23
+ def process_controller name, src, file_name
24
24
  if not node_type? src, :class
25
25
  Brakeman.debug "#{name} is not a class, it's a #{src.node_type}"
26
26
  return
27
27
  else
28
28
  @current_class = name
29
- @file = file
29
+ @file_name = file_name
30
30
 
31
31
  process_default src
32
32
 
@@ -59,7 +59,7 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
59
59
  method = processor.process method
60
60
  end
61
61
 
62
- @file = mixin.file
62
+ @file_name = mixin.file
63
63
  #Then process it like any other method in the controller
64
64
  process method
65
65
  end
@@ -182,7 +182,7 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
182
182
  end
183
183
  end
184
184
 
185
- render_path = Brakeman::RenderPath.new.add_controller_render(@current_class, @current_method, line, relative_path(@file))
185
+ render_path = Brakeman::RenderPath.new.add_controller_render(@current_class, @current_method, line, relative_path(@file_name))
186
186
  super name, args, render_path, line
187
187
  end
188
188
 
@@ -88,7 +88,7 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
88
88
  #Process call to render()
89
89
  exp.arglist = process exp.arglist
90
90
  make_render_in_view exp
91
- elsif target == nil and method == :find_and_preserve
91
+ elsif target == nil and method == :find_and_preserve and exp.first_arg
92
92
  process exp.first_arg
93
93
  elsif method == :render_with_options
94
94
  if target == JAVASCRIPT_FILTER or target == COFFEE_FILTER
@@ -30,4 +30,22 @@ class Brakeman::BasicProcessor < Brakeman::SexpProcessor
30
30
  process_default exp
31
31
  end
32
32
  end
33
+
34
+ def process_if exp
35
+ condition = exp.condition
36
+
37
+ process condition
38
+
39
+ if true? condition
40
+ process exp.then_clause
41
+ elsif false? condition
42
+ process exp.else_clause
43
+ else
44
+ [exp.then_clause, exp.else_clause].compact.map do |e|
45
+ process e
46
+ end
47
+ end
48
+
49
+ exp
50
+ end
33
51
  end
@@ -27,8 +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
31
- res = Brakeman::ConfigAliasProcessor.new.process_safely(src)
30
+ def process_config src, file_name
31
+ @file_name = file_name
32
+ res = Brakeman::ConfigAliasProcessor.new.process_safely(src, nil, file_name)
32
33
  process res
33
34
  end
34
35
 
@@ -16,6 +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
20
  end
20
21
 
21
22
  #Call this with parsed route file information.
@@ -23,7 +24,7 @@ class Brakeman::Rails2RoutesProcessor < Brakeman::BasicProcessor
23
24
  #This method first calls RouteAliasProcessor#process_safely on the +exp+,
24
25
  #so it does not modify the +exp+.
25
26
  def process_routes exp
26
- process Brakeman::RouteAliasProcessor.new.process_safely(exp)
27
+ process Brakeman::RouteAliasProcessor.new.process_safely(exp, nil, @file_name)
27
28
  end
28
29
 
29
30
  #Looking for mapping of routes
@@ -24,8 +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
28
- res = Brakeman::AliasProcessor.new(@tracker).process_safely(src)
27
+ def process_config src, file_name
28
+ @file_name = file_name
29
+ res = Brakeman::AliasProcessor.new(@tracker).process_safely(src, nil, @file_name)
29
30
  process res
30
31
  end
31
32
 
@@ -17,10 +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
21
  end
21
22
 
22
23
  def process_routes exp
23
- process exp.dup
24
+ process Brakeman::AliasProcessor.new.process_safely(exp, nil, @file_name)
24
25
  end
25
26
 
26
27
  def process_call exp
@@ -18,8 +18,8 @@ class Brakeman::TemplateAliasProcessor < Brakeman::AliasProcessor
18
18
  end
19
19
 
20
20
  #Process template
21
- def process_template name, args, _, line = nil
22
- file = relative_path(@template.file || @tracker.templates[@template.name])
21
+ def process_template name, args, _, line = nil, file_name = nil
22
+ @file_name = file_name || relative_path(@template.file || @tracker.templates[@template.name])
23
23
 
24
24
  if @called_from
25
25
  if @called_from.include_template? name
@@ -27,9 +27,9 @@ class Brakeman::TemplateAliasProcessor < Brakeman::AliasProcessor
27
27
  return
28
28
  end
29
29
 
30
- super name, args, @called_from.dup.add_template_render(@template.name, line, file)
30
+ super name, args, @called_from.dup.add_template_render(@template.name, line, @file_name)
31
31
  else
32
- super name, args, Brakeman::RenderPath.new.add_template_render(@template.name, line, file)
32
+ super name, args, Brakeman::RenderPath.new.add_template_render(@template.name, line, @file_name)
33
33
  end
34
34
  end
35
35
 
@@ -8,6 +8,7 @@ class Brakeman::TemplateProcessor < Brakeman::BaseProcessor
8
8
  def initialize tracker, template_name, called_from = nil, file_name = nil
9
9
  super(tracker)
10
10
  @current_template = Brakeman::Template.new template_name, called_from, file_name, tracker
11
+ @file_name = file_name
11
12
 
12
13
  if called_from
13
14
  template_name = (template_name.to_s + "." + called_from.to_s).to_sym
@@ -26,7 +26,8 @@ class Brakeman::Report::CodeClimate < Brakeman::Report::Base
26
26
  location: {
27
27
  path: warning.relative_path,
28
28
  lines: {
29
- begin: warning.line || 1
29
+ begin: warning.line || 1,
30
+ end: warning.line || 1,
30
31
  }
31
32
  },
32
33
  content: {
@@ -116,7 +116,7 @@ class Brakeman::Scanner
116
116
  path = "config/#{file}"
117
117
 
118
118
  if @app_tree.exists?(path)
119
- @processor.process_config(parse_ruby(@app_tree.read(path)))
119
+ @processor.process_config(parse_ruby(@app_tree.read(path)), path)
120
120
  end
121
121
 
122
122
  rescue => e
@@ -5,10 +5,11 @@ require 'brakeman/report'
5
5
  require 'brakeman/processors/lib/find_call'
6
6
  require 'brakeman/processors/lib/find_all_calls'
7
7
  require 'brakeman/tracker/config'
8
+ require 'brakeman/tracker/constants'
8
9
 
9
10
  #The Tracker keeps track of all the processed information.
10
11
  class Brakeman::Tracker
11
- attr_accessor :controllers, :templates, :models, :errors,
12
+ attr_accessor :controllers, :constants, :templates, :models, :errors,
12
13
  :checks, :initializers, :config, :routes, :processor, :libs,
13
14
  :template_cache, :options, :filter_cache, :start_time, :end_time,
14
15
  :duration, :ignored_filter
@@ -38,6 +39,7 @@ class Brakeman::Tracker
38
39
  @initializers = {}
39
40
  @errors = []
40
41
  @libs = {}
42
+ @constants = Brakeman::Constants.new
41
43
  @checks = nil
42
44
  @processed = nil
43
45
  @template_cache = Set.new
@@ -188,6 +190,14 @@ class Brakeman::Tracker
188
190
  end
189
191
  end
190
192
 
193
+ def add_constant name, value, context = nil
194
+ @constants.add name, value, context
195
+ end
196
+
197
+ def constant_lookup name
198
+ @constants.get_literal name
199
+ end
200
+
191
201
  def index_call_sites
192
202
  finder = Brakeman::FindAllCalls.new self
193
203
 
@@ -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
data/lib/brakeman/util.rb CHANGED
@@ -254,6 +254,10 @@ module Brakeman::Util
254
254
  request_env? exp
255
255
  end
256
256
 
257
+ def constant? exp
258
+ node_type? exp, :const, :colon2, :colon3
259
+ end
260
+
257
261
  #Check if _exp_ is a Sexp.
258
262
  def sexp? exp
259
263
  exp.is_a? Sexp
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "3.2.1"
2
+ Version = "3.3.0"
3
3
  end
@@ -102,6 +102,7 @@ module Brakeman::WarningCodes
102
102
  :CVE_2015_7579 => 98,
103
103
  :dynamic_render_path_rce => 99,
104
104
  :CVE_2015_7581 => 100,
105
+ :secret_in_source => 101,
105
106
  }
106
107
 
107
108
  def self.code name
@@ -326,6 +326,12 @@ class Sexp
326
326
  self[1]
327
327
  end
328
328
 
329
+ def condition= exp
330
+ expect :if
331
+ self[1] = exp
332
+ end
333
+
334
+
329
335
  #Returns 'then' clause of an if expression:
330
336
  #
331
337
  # s(:if,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brakeman-min
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.1
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Collins
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain:
11
11
  - brakeman-public_cert.pem
12
- date: 2016-02-25 00:00:00.000000000 Z
12
+ date: 2016-05-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: test-unit
@@ -130,6 +130,7 @@ files:
130
130
  - lib/brakeman/checks/check_route_dos.rb
131
131
  - lib/brakeman/checks/check_safe_buffer_manipulation.rb
132
132
  - lib/brakeman/checks/check_sanitize_methods.rb
133
+ - lib/brakeman/checks/check_secrets.rb
133
134
  - lib/brakeman/checks/check_select_tag.rb
134
135
  - lib/brakeman/checks/check_select_vulnerability.rb
135
136
  - lib/brakeman/checks/check_send.rb
@@ -220,6 +221,7 @@ files:
220
221
  - lib/brakeman/tracker.rb
221
222
  - lib/brakeman/tracker/collection.rb
222
223
  - lib/brakeman/tracker/config.rb
224
+ - lib/brakeman/tracker/constants.rb
223
225
  - lib/brakeman/tracker/controller.rb
224
226
  - lib/brakeman/tracker/library.rb
225
227
  - lib/brakeman/tracker/model.rb
@@ -250,7 +252,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
250
252
  version: '0'
251
253
  requirements: []
252
254
  rubyforge_project:
253
- rubygems_version: 2.4.8
255
+ rubygems_version: 2.5.1
254
256
  signing_key:
255
257
  specification_version: 4
256
258
  summary: Security vulnerability scanner for Ruby on Rails.