brakeman-min 3.4.0 → 3.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6979dd5270ff39f9f08c1391c27591e26c822a7d
4
- data.tar.gz: a9a5f659a64c9fce7f5d6e8c820e220533d4ccb2
3
+ metadata.gz: b0d820c5971babfb6ebcc3aaa87048ae4cbe2035
4
+ data.tar.gz: 2d95f07bc9731fe3e2e8fff2647d048a39a5a004
5
5
  SHA512:
6
- metadata.gz: 09fae3a07ebe6eda7ef6403eddf52110d85e2a708d6ae167e3053ee8e678d34981bbde2eeba28a2dc0794b47813522c860a99f744197da24c0f1513061ec54d7
7
- data.tar.gz: cc031803fe4afbb9c2572365415ab218e23344a0bfb0f759f2812ed63ab84503a06d354ac60b0a9d83492a1818c648d96c5ae013a48ea7bcec55980bc351cf90
6
+ metadata.gz: 84b96c61f8e105ad374761ba2d4ff5543090683fb29dcc7ac7c8e762dac347317156c98322bb7a4b3556512e0d79fb65e13183492d34fd125dd6bd4373e6768b
7
+ data.tar.gz: 6979582a1d87fa9a31eba9f21c3561ed35d7795184f524522c81d38ba1823c61b8ba64ee5db327daf4b82a66e59088eeda0e809ca5a672b3df2d917d5743d10b
data/CHANGES CHANGED
@@ -1,3 +1,13 @@
1
+ # 3.4.1
2
+
3
+ * Show action help at start of interactive ignore
4
+ * Check CSRF setting in direct subclasses of `ActionController::Base` (Jason Yeo)
5
+ * Configurable engines path (Jason Yeo)
6
+ * Use Ruby version to turn off SymbolDoS check
7
+ * Pull Ruby version from `.ruby-version` or Gemfile
8
+ * Avoid warning about `where_values_hash` in SQLi
9
+ * Fix ignoring link interpolation not at beginning of string
10
+
1
11
  # 3.4.0
2
12
 
3
13
  * Add new `plain` report format
data/lib/brakeman.rb CHANGED
@@ -146,7 +146,8 @@ module Brakeman
146
146
  :relative_path => false,
147
147
  :report_progress => true,
148
148
  :html_style => "#{File.expand_path(File.dirname(__FILE__))}/brakeman/format/style.css",
149
- :output_color => true
149
+ :output_color => true,
150
+ :engine_paths => ["engines/*"]
150
151
  }
151
152
  end
152
153
 
@@ -19,6 +19,7 @@ module Brakeman
19
19
  init_options[:only_files] = regex_for_paths(options[:only_files])
20
20
  end
21
21
  init_options[:additional_libs_path] = options[:additional_libs_path]
22
+ init_options[:engine_paths] = options[:engine_paths]
22
23
  new(root, init_options)
23
24
  end
24
25
 
@@ -57,6 +58,9 @@ module Brakeman
57
58
  @skip_files = init_options[:skip_files]
58
59
  @only_files = init_options[:only_files]
59
60
  @additional_libs_path = init_options[:additional_libs_path] || []
61
+ @engine_paths = init_options[:engine_paths] || []
62
+ @absolute_engine_paths = @engine_paths.select { |path| path.start_with?(File::SEPARATOR) }
63
+ @relative_engine_paths = @engine_paths - @absolute_engine_paths
60
64
  end
61
65
 
62
66
  def expand_path(path)
@@ -101,8 +105,7 @@ module Brakeman
101
105
  end
102
106
 
103
107
  def layout_exists?(name)
104
- pattern = "#{@root}/{engines/*/,}app/views/layouts/#{name}.html.{erb,haml,slim}"
105
- !Dir.glob(pattern).empty?
108
+ !Dir.glob("#{root_search_pattern}app/views/layouts/#{name}.html.{erb,haml,slim}").empty?
106
109
  end
107
110
 
108
111
  def lib_paths
@@ -121,10 +124,14 @@ module Brakeman
121
124
  @additional_libs_path.collect{ |path| find_paths path }.flatten
122
125
  end
123
126
 
124
- def find_paths(directory, extensions = "*.rb")
125
- pattern = @root + "/{engines/*/,}#{directory}/**/#{extensions}"
127
+ def find_paths(directory, extensions = ".rb")
128
+ select_files(glob_files(directory, "*", extensions).sort)
129
+ end
130
+
131
+ def glob_files(directory, name, extensions = ".rb")
132
+ pattern = "#{root_search_pattern}#{directory}/**/#{name}#{extensions}"
126
133
 
127
- select_files(Dir.glob(pattern).sort)
134
+ Dir.glob(pattern)
128
135
  end
129
136
 
130
137
  def select_files(paths)
@@ -160,5 +167,15 @@ module Brakeman
160
167
 
161
168
  files.match(project_relative_path)
162
169
  end
170
+
171
+ def root_search_pattern
172
+ return @root_search_pattern if @root_search_pattern
173
+ abs = @absolute_engine_paths.to_a.map { |path| path.gsub /#{File::SEPARATOR}+$/, '' }
174
+ rel = @relative_engine_paths.to_a.map { |path| path.gsub /#{File::SEPARATOR}+$/, '' }
175
+
176
+ roots = ([@root] + abs).join(",")
177
+ rel_engines = (rel + [""]).join("/,")
178
+ @root_search_patrern = "{#{roots}}/{#{rel_engines}}"
179
+ end
163
180
  end
164
181
  end
@@ -7,41 +7,41 @@ require 'brakeman/checks/base_check'
7
7
  class Brakeman::CheckForgerySetting < Brakeman::BaseCheck
8
8
  Brakeman::Checks.add self
9
9
 
10
- @description = "Verifies that protect_from_forgery is enabled in ApplicationController"
10
+ @description = "Verifies that protect_from_forgery is enabled in direct subclasses of ActionController::Base"
11
11
 
12
12
  def run_check
13
- app_controller = tracker.controllers[:ApplicationController]
14
- return unless app_controller and app_controller.ancestor? :"ActionController::Base"
15
-
16
- if tracker.config.allow_forgery_protection?
17
- csrf_warning :warning_code => :csrf_protection_disabled,
18
- :message => "Forgery protection is disabled"
19
-
20
- elsif app_controller and not app_controller.protect_from_forgery?
21
- csrf_warning :warning_code => :csrf_protection_missing,
22
- :message => "'protect_from_forgery' should be called in ApplicationController",
23
- :line => app_controller.top_line
24
-
25
- elsif version_between? "2.1.0", "2.3.10"
26
- cve_2011_0447 "2.3.11"
27
-
28
- elsif version_between? "3.0.0", "3.0.3"
29
- cve_2011_0447 "3.0.4"
30
-
31
- elsif version_between? "4.0.0", "100.0.0" and forgery_opts = app_controller.options[:protect_from_forgery]
32
- unless forgery_opts.is_a?(Array) and sexp?(forgery_opts.first) and
13
+ tracker.controllers
14
+ .select { |_, controller| controller.parent == :"ActionController::Base" }
15
+ .each do |name, controller|
16
+ if controller and not controller.protect_from_forgery?
17
+ csrf_warning :controller => name,
18
+ :warning_code => :csrf_protection_missing,
19
+ :message => "'protect_from_forgery' should be called in #{name}",
20
+ :file => controller.file,
21
+ :line => controller.top_line
22
+ elsif version_between? "4.0.0", "100.0.0" and forgery_opts = controller.options[:protect_from_forgery]
23
+ unless forgery_opts.is_a?(Array) and sexp?(forgery_opts.first) and
33
24
  access_arg = hash_access(forgery_opts.first.first_arg, :with) and symbol? access_arg and
34
25
  access_arg.value == :exception
35
26
 
36
- args = {
37
- :warning_code => :csrf_not_protected_by_raising_exception,
38
- :message => "protect_from_forgery should be configured with 'with: :exception'",
39
- :confidence => CONFIDENCE[:med]
40
- }
27
+ args = {
28
+ :controller => name,
29
+ :warning_type => "Cross-Site Request Forgery",
30
+ :warning_code => :csrf_not_protected_by_raising_exception,
31
+ :message => "protect_from_forgery should be configured with 'with: :exception'",
32
+ :confidence => CONFIDENCE[:med],
33
+ :file => controller.file
34
+ }
35
+
36
+ args.merge!(:code => forgery_opts.first) if forgery_opts.is_a?(Array)
41
37
 
42
- args.merge!(:code => forgery_opts.first) if forgery_opts.is_a?(Array)
38
+ csrf_warning args
39
+ end
43
40
 
44
- csrf_warning args
41
+ end
42
+
43
+ if controller.options[:protect_from_forgery]
44
+ check_cve_2011_0447
45
45
  end
46
46
  end
47
47
  end
@@ -50,14 +50,26 @@ class Brakeman::CheckForgerySetting < Brakeman::BaseCheck
50
50
  opts = {
51
51
  :controller => :ApplicationController,
52
52
  :warning_type => "Cross-Site Request Forgery",
53
- :confidence => CONFIDENCE[:high],
54
- :file => tracker.controllers[:ApplicationController].file
53
+ :confidence => CONFIDENCE[:high]
55
54
  }.merge opts
56
55
 
57
56
  warn opts
58
57
  end
59
58
 
60
- def cve_2011_0447 new_version
59
+ def check_cve_2011_0447
60
+ @warned_cve_2011_0447 ||= false
61
+ return if @warned_cve_2011_0447
62
+
63
+ if version_between? "2.1.0", "2.3.10"
64
+ new_version = "2.3.11"
65
+ elsif version_between? "3.0.0", "3.0.3"
66
+ new_version = "3.0.4"
67
+ else
68
+ return
69
+ end
70
+
71
+ @warned_cve_2011_0447 = true # only warn once
72
+
61
73
  csrf_warning :warning_code => :CVE_2011_0447,
62
74
  :message => "CSRF protection is flawed in unpatched versions of Rails #{rails_version} (CVE-2011-0447). Upgrade to #{new_version} or apply patches as needed",
63
75
  :gem_info => gemfile_or_environment,
@@ -1,14 +1,14 @@
1
1
  require 'brakeman/checks/check_cross_site_scripting'
2
2
 
3
3
  #Checks for calls to link_to which pass in potentially hazardous data
4
- #to the second argument. While this argument must be html_safe to not break
5
- #the html, it must also be url safe as determined by calling a
6
- #:url_safe_method. This prevents attacks such as javascript:evil() or
4
+ #to the second argument. While this argument must be html_safe to not break
5
+ #the html, it must also be url safe as determined by calling a
6
+ #:url_safe_method. This prevents attacks such as javascript:evil() or
7
7
  #data:<encoded XSS> which is html_safe, but not safe as an href
8
8
  #Props to Nick Green for the idea.
9
9
  class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
10
10
  Brakeman::Checks.add self
11
-
11
+
12
12
  @description = "Checks to see if values used for hrefs are sanitized using a :url_safe_method to protect against javascript:/data: XSS"
13
13
 
14
14
  def run_check
@@ -23,7 +23,7 @@ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
23
23
  @models = tracker.models.keys
24
24
  @inspect_arguments = tracker.options[:check_arguments]
25
25
 
26
- methods = tracker.find_call :target => false, :method => :link_to
26
+ methods = tracker.find_call :target => false, :method => :link_to
27
27
  methods.each do |call|
28
28
  process_result call
29
29
  end
@@ -40,19 +40,15 @@ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
40
40
  url_arg = url_arg.first_arg
41
41
  end
42
42
 
43
- #Ignore situations where the href is an interpolated string
44
- #with something before the user input
45
- return if string_interp?(url_arg) && !url_arg[1].chomp.empty?
46
-
47
43
  return if call? url_arg and ignore_call? url_arg.target, url_arg.method
48
44
 
49
45
  if input = has_immediate_user_input?(url_arg)
50
46
  message = "Unsafe #{friendly_type_of input} in link_to href"
51
47
 
52
- unless duplicate? result or call_on_params? url_arg
48
+ unless duplicate? result or call_on_params? url_arg or ignore_interpolation? url_arg, input.match
53
49
  add_result result
54
50
  warn :result => result,
55
- :warning_type => "Cross Site Scripting",
51
+ :warning_type => "Cross Site Scripting",
56
52
  :warning_code => :xss_link_to_href,
57
53
  :message => message,
58
54
  :user_input => input,
@@ -61,19 +57,19 @@ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
61
57
  end
62
58
  elsif has_immediate_model? url_arg or model_find_call? url_arg
63
59
 
64
- # Decided NOT warn on models. polymorphic_path is called it a model is
60
+ # Decided NOT warn on models. polymorphic_path is called it a model is
65
61
  # passed to link_to (which passes it to url_for)
66
62
 
67
63
  elsif array? url_arg
68
- # Just like models, polymorphic path/url is called if the argument is
69
- # an array
64
+ # Just like models, polymorphic path/url is called if the argument is
65
+ # an array
70
66
 
71
67
  elsif hash? url_arg
72
68
 
73
69
  # url_for uses the key/values pretty carefully and I don't see a risk.
74
70
  # IF you have default routes AND you accept user input for :controller
75
- # and :only_path, then MAYBE you could trigger a javascript:/data:
76
- # attack.
71
+ # and :only_path, then MAYBE you could trigger a javascript:/data:
72
+ # attack.
77
73
 
78
74
  elsif @matched
79
75
  if @matched.type == :model and not tracker.options[:ignore_model_output]
@@ -82,10 +78,10 @@ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
82
78
  message = "Unsafe parameter value in link_to href"
83
79
  end
84
80
 
85
- if message and not duplicate? result
81
+ if message and not duplicate? result and not ignore_interpolation? url_arg, @matched.match
86
82
  add_result result
87
- warn :result => result,
88
- :warning_type => "Cross Site Scripting",
83
+ warn :result => result,
84
+ :warning_type => "Cross Site Scripting",
89
85
  :warning_code => :xss_link_to_href,
90
86
  :message => message,
91
87
  :user_input => @matched,
@@ -95,6 +91,24 @@ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
95
91
  end
96
92
  end
97
93
 
94
+ #Ignore situations where the href is an interpolated string
95
+ #with something before the user input
96
+ def ignore_interpolation? arg, suspect
97
+ return unless string_interp? arg
98
+ return true unless arg[1].chomp.empty? # plain string before interpolation
99
+
100
+ first_interp = arg.find_nodes(:evstr).first
101
+ return unless first_interp
102
+
103
+ first_interp[1].deep_each do |e|
104
+ if suspect == e
105
+ return false
106
+ end
107
+ end
108
+
109
+ true
110
+ end
111
+
98
112
  def ignore_call? target, method
99
113
  decorated_model? method or super
100
114
  end
@@ -549,7 +549,9 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
549
549
  :quoted_primary_key, :to_i, :to_f, :sanitize_sql, :sanitize_sql_array,
550
550
  :sanitize_sql_for_assignment, :sanitize_sql_for_conditions, :sanitize_sql_hash,
551
551
  :sanitize_sql_hash_for_assignment, :sanitize_sql_hash_for_conditions,
552
- :to_sql, :sanitize, :primary_key, :table_name_prefix, :table_name_suffix]
552
+ :to_sql, :sanitize, :primary_key, :table_name_prefix, :table_name_suffix,
553
+ :where_values_hash
554
+ ]
553
555
 
554
556
  def safe_value? exp
555
557
  return true unless sexp? exp
@@ -9,6 +9,7 @@ class Brakeman::CheckSymbolDoS < Brakeman::BaseCheck
9
9
 
10
10
  def run_check
11
11
  return if rails_version and rails_version >= "5.0.0"
12
+ return if tracker.config.ruby_version >= "2.2"
12
13
 
13
14
  tracker.find_call(:methods => UNSAFE_METHODS, :nested => true).each do |result|
14
15
  check_unsafe_symbol_creation(result)
@@ -3,7 +3,7 @@ require 'brakeman/checks/base_check'
3
3
  # Checks for string interpolation and parameters in calls to
4
4
  # String#constantize, String#safe_constantize, Module#const_get and Module#qualified_const_get.
5
5
  #
6
- # Exploit examples at: http://blog.conviso.com.br/2013/02/exploiting-unsafe-reflection-in.html
6
+ # Exploit examples at: http://blog.conviso.com.br/exploiting-unsafe-reflection-in-rubyrails-applications/
7
7
  class Brakeman::CheckUnsafeReflection < Brakeman::BaseCheck
8
8
  Brakeman::Checks.add self
9
9
 
@@ -136,6 +136,11 @@ module Brakeman::Options
136
136
  options[:additional_libs_path].merge paths
137
137
  end
138
138
 
139
+ opts.on "--add-engines-path path1,path2,etc", Array, "Include these engines in the scan" do |paths|
140
+ options[:engine_paths] ||= Set.new
141
+ options[:engine_paths].merge paths
142
+ end
143
+
139
144
  opts.on "-t", "--test Check1,Check2,etc", Array, "Only run the specified checks" do |checks|
140
145
  checks.each_with_index do |s, index|
141
146
  if s[0,5] != "Check"
@@ -21,19 +21,26 @@ class Brakeman::GemProcessor < Brakeman::BasicProcessor
21
21
  end
22
22
 
23
23
  def process_call exp
24
- if exp.target == nil and exp.method == :gem
25
- gem_name = exp.first_arg
26
- return exp unless string? gem_name
24
+ if exp.target == nil
25
+ if exp.method == :gem
26
+ gem_name = exp.first_arg
27
+ return exp unless string? gem_name
27
28
 
28
- gem_version = exp.second_arg
29
+ gem_version = exp.second_arg
29
30
 
30
- version = if string? gem_version
31
- gem_version.value
32
- else
33
- nil
34
- end
31
+ version = if string? gem_version
32
+ gem_version.value
33
+ else
34
+ nil
35
+ end
35
36
 
36
- @tracker.config.add_gem gem_name.value, version, @gemfile, exp.line
37
+ @tracker.config.add_gem gem_name.value, version, @gemfile, exp.line
38
+ elsif exp.method == :ruby
39
+ version = exp.first_arg
40
+ if string? version
41
+ @tracker.config.set_ruby_version version.value
42
+ end
43
+ end
37
44
  end
38
45
 
39
46
  exp
@@ -58,11 +58,13 @@ module Brakeman
58
58
  HighLine.new.choose do |m|
59
59
  m.choice "Inspect all warnings" do
60
60
  @skip_ignored = false
61
+ pre_show_help
61
62
  process_warnings
62
63
  end
63
64
 
64
65
  m.choice "Hide previously ignored warnings" do
65
66
  @skip_ignored = true
67
+ pre_show_help
66
68
  process_warnings
67
69
  end
68
70
 
@@ -92,7 +94,20 @@ module Brakeman
92
94
  m.choice "s"
93
95
  m.choice "q"
94
96
  m.choice "?" do
95
- say <<-HELP
97
+ show_help
98
+ "?"
99
+ end
100
+ end
101
+ end
102
+
103
+ def pre_show_help
104
+ say "-" * 20
105
+ say "Actions:", :cyan
106
+ show_help
107
+ end
108
+
109
+ def show_help
110
+ say <<-HELP
96
111
  i - Add warning to ignore list
97
112
  n - Add warning to ignore list and add note
98
113
  s - Skip this warning (will remain ignored or shown)
@@ -101,11 +116,7 @@ a - Ignore this warning and all remaining warnings
101
116
  k - Skip this warning and all remaining warnings
102
117
  q - Quit, do not update ignored warnings
103
118
  ? - Display this help
104
- HELP
105
-
106
- "?"
107
- end
108
- end
119
+ HELP
109
120
  end
110
121
 
111
122
  def penultimate_menu
@@ -108,6 +108,10 @@ class Brakeman::Scanner
108
108
  tracker.config.escape_html = true
109
109
  Brakeman.notify "[Notice] Escaping HTML by default"
110
110
  end
111
+
112
+ if @app_tree.exists? ".ruby-version"
113
+ tracker.config.set_ruby_version @app_tree.read ".ruby-version"
114
+ end
111
115
  end
112
116
 
113
117
  def process_config_file file
@@ -5,7 +5,7 @@ module Brakeman
5
5
  include Util
6
6
 
7
7
  attr_reader :rails, :tracker
8
- attr_accessor :rails_version
8
+ attr_accessor :rails_version, :ruby_version
9
9
  attr_writer :erubis, :escape_html
10
10
  attr_reader :gems
11
11
 
@@ -16,6 +16,7 @@ module Brakeman
16
16
  @settings = {}
17
17
  @escape_html = nil
18
18
  @erubis = nil
19
+ @ruby_version = ""
19
20
  end
20
21
 
21
22
  def allow_forgery_protection?
@@ -92,6 +93,14 @@ module Brakeman
92
93
  end
93
94
  end
94
95
 
96
+ def set_ruby_version version
97
+ return unless version.is_a? String
98
+
99
+ if version =~ /(\d+\.\d+\.\d+)/
100
+ self.ruby_version = $1
101
+ end
102
+ end
103
+
95
104
  def session_settings
96
105
  @rails[:action_controller] &&
97
106
  @rails[:action_controller][:session]
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "3.4.0"
2
+ Version = "3.4.1"
3
3
  end
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.4.0
4
+ version: 3.4.1
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-09-07 00:00:00.000000000 Z
12
+ date: 2016-11-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -31,14 +31,14 @@ dependencies:
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: 3.8.1
34
+ version: 3.8.3
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: 3.8.1
41
+ version: 3.8.3
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: ruby2ruby
44
44
  requirement: !ruby/object:Gem::Requirement