brakeman-min 4.6.1 → 4.7.0

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
  SHA256:
3
- metadata.gz: fa71f00920d2ad833cc54ef035dee162db5ee298cb2c7ba63076e541c1b7680f
4
- data.tar.gz: 00c48ba72c0a5a832368a5f14b28db4228bacaf3e9c5386d0a41dee187bc17de
3
+ metadata.gz: d12973a3773547b33ce1f73a567fd04fe1619683fcce1e1a3c62dd47c474c6d1
4
+ data.tar.gz: 8f10628132f2446664c4bcd350091f531cc5c6628240c6e65187871031ad231b
5
5
  SHA512:
6
- metadata.gz: ce035b30cc3f0f79328b4574c8ea9a7ffd06782de7b201401804f4241fc8abc02ec873835c8bbf1ba1bdd9fba8c436eb5c7f8110b298f53a7d938e6786e8a5ff
7
- data.tar.gz: df6afc3cd5c0255a18c0dbaf0de78c539e5a71018bc59de3c3ac9b56041bf93c4cd69d1cc1e819fbb729d0f77efce4b55c4c2c60f004522db1ce7a1e4db8c136
6
+ metadata.gz: eb6cfb7af8cc3cec4306bfab523ebbcc462c30f0c5547ab8df6937d8fa19c3e6002c66528918dfd17d58c32c4f81c5ce6c97b43aa22f7695b257ea36fe8019b2
7
+ data.tar.gz: 4e17c46419d7bb0b632542fa6a904a438e5413acf257240f895be5fb64f32af10206ce5d3ba2d21dd0cfed56c080842c75d423c8360743a9a1065e341a6c1759
data/CHANGES.md CHANGED
@@ -1,3 +1,14 @@
1
+ # 4.7.0
2
+
3
+ * Refactor `Brakeman::Differ#second_pass` (Benoit Côté-Jodoin)
4
+ * Ignore interpolation in `%W[]`
5
+ * Fix `version_between?` (Andrey Glushkov)
6
+ * Add support for `ruby_parser` 3.14.0
7
+ * Ignore `form_for` for XSS check
8
+ * Update Haml support to Haml 5.x
9
+ * Catch shell injection from `-c` shell commands (Jacob Evelyn)
10
+ * Correctly handle non-symbols in `CheckCookieSerialization` (Phil Turnbull)
11
+
1
12
  # 4.6.1
2
13
 
3
14
  * Fix Reverse Tabnabbing warning message (Steffen Schildknecht / Jörg Schiller)
@@ -39,6 +39,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
39
39
  @active_record_models = nil
40
40
  @mass_assign_disabled = nil
41
41
  @has_user_input = nil
42
+ @in_array = false
42
43
  @safe_input_attributes = Set[:to_i, :to_f, :arel_table, :id]
43
44
  @comparison_ops = Set[:==, :!=, :>, :<, :>=, :<=]
44
45
  end
@@ -109,9 +110,16 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
109
110
  exp
110
111
  end
111
112
 
113
+ def process_array exp
114
+ @in_array = true
115
+ process_default exp
116
+ ensure
117
+ @in_array = false
118
+ end
119
+
112
120
  #Does not actually process string interpolation, but notes that it occurred.
113
121
  def process_dstr exp
114
- unless @string_interp # don't overwrite existing value
122
+ unless array_interp? exp or @string_interp # don't overwrite existing value
115
123
  @string_interp = Match.new(:interp, exp)
116
124
  end
117
125
 
@@ -120,6 +128,20 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
120
128
 
121
129
  private
122
130
 
131
+ # Checking for
132
+ #
133
+ # %W[#{a}]
134
+ #
135
+ # which will be parsed as
136
+ #
137
+ # s(:array, s(:dstr, "", s(:evstr, s(:call, nil, :a))))
138
+ def array_interp? exp
139
+ @in_array and
140
+ string_interp? exp and
141
+ exp[1] == "".freeze and
142
+ exp.length == 3 # only one interpolated value
143
+ end
144
+
123
145
  def always_safe_method? meth
124
146
  @safe_input_attributes.include? meth or
125
147
  @comparison_ops.include? meth
@@ -9,7 +9,7 @@ class Brakeman::CheckCookieSerialization < Brakeman::BaseCheck
9
9
  tracker.find_call(target: :'Rails.application.config.action_dispatch', method: :cookies_serializer=).each do |result|
10
10
  setting = result[:call].first_arg
11
11
 
12
- if symbol? setting and setting.value == :marshal or setting.value == :hybrid
12
+ if symbol? setting and [:marshal, :hybrid].include? setting.value
13
13
  warn :result => result,
14
14
  :warning_type => "Remote Code Execution",
15
15
  :warning_code => :unsafe_cookie_serialization,
@@ -287,7 +287,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
287
287
 
288
288
  def setup
289
289
  @ignore_methods = Set[:==, :!=, :button_to, :check_box, :content_tag, :escapeHTML, :escape_once,
290
- :field_field, :fields_for, :h, :hidden_field,
290
+ :field_field, :fields_for, :form_for, :h, :hidden_field,
291
291
  :hidden_field, :hidden_field_tag, :image_tag, :label,
292
292
  :link_to, :mail_to, :radio_button, :select,
293
293
  :submit_tag, :text_area, :text_field,
@@ -21,6 +21,10 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
21
21
  SHELL_ESCAPE_MODULE_METHODS = Set[:escape, :join, :shellescape, :shelljoin]
22
22
  SHELL_ESCAPE_MIXIN_METHODS = Set[:shellescape, :shelljoin]
23
23
 
24
+ # These are common shells that are known to allow the execution of commands
25
+ # via a -c flag. See dash_c_shell_command? for more info.
26
+ KNOWN_SHELL_COMMANDS = Set["sh", "bash", "ksh", "csh", "tcsh", "zsh"]
27
+
24
28
  SHELLWORDS = s(:const, :Shellwords)
25
29
 
26
30
  #Check models, controllers, and views for command injection.
@@ -42,6 +46,8 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
42
46
  end
43
47
  end
44
48
 
49
+ private
50
+
45
51
  #Processes results from Tracker#find_call.
46
52
  def process_result result
47
53
  call = result[:call]
@@ -54,7 +60,17 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
54
60
  failure = include_user_input?(args) || dangerous_interp?(args)
55
61
  end
56
62
  when :system, :exec
57
- failure = include_user_input?(first_arg) || dangerous_interp?(first_arg)
63
+ # Normally, if we're in a `system` or `exec` call, we only are worried
64
+ # about shell injection when there's a single argument, because comma-
65
+ # separated arguments are always escaped by Ruby. However, an exception is
66
+ # when the first two arguments are something like "bash -c" because then
67
+ # the third argument is effectively the command being run and might be
68
+ # a malicious executable if it comes (partially or fully) from user input.
69
+ if dash_c_shell_command?(first_arg, call.second_arg)
70
+ failure = include_user_input?(args[3]) || dangerous_interp?(args[3])
71
+ else
72
+ failure = include_user_input?(first_arg) || dangerous_interp?(first_arg)
73
+ end
58
74
  else
59
75
  failure = include_user_input?(args) || dangerous_interp?(args)
60
76
  end
@@ -77,6 +93,15 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
77
93
  end
78
94
  end
79
95
 
96
+ # @return [Boolean] true iff the command given by `first_arg`, `second_arg`
97
+ # invokes a new shell process via `<shell_command> -c` (like `bash -c`)
98
+ def dash_c_shell_command?(first_arg, second_arg)
99
+ string?(first_arg) &&
100
+ KNOWN_SHELL_COMMANDS.include?(first_arg.value) &&
101
+ string?(second_arg) &&
102
+ second_arg.value == "-c"
103
+ end
104
+
80
105
  def check_open_calls
81
106
  tracker.find_call(:targets => [nil, :Kernel], :method => :open).each do |result|
82
107
  if match = dangerous_open_arg?(result[:call].first_arg)
@@ -24,43 +24,31 @@ class Brakeman::Differ
24
24
  # second pass to cleanup any vulns which have changed in line number only.
25
25
  # Given a list of new warnings, delete pairs of new/fixed vulns that differ
26
26
  # only by line number.
27
- # Horrible O(n^2) performance. Keep n small :-/
28
27
  def second_pass(warnings)
29
- # keep track of the number of elements deleted because the index numbers
30
- # won't update as the list is modified
31
- elements_deleted_offset = 0
28
+ new_fingerprints = Set.new(warnings[:new].map(&method(:fingerprint)))
29
+ fixed_fingerprints = Set.new(warnings[:fixed].map(&method(:fingerprint)))
32
30
 
33
- # dup this list since we will be deleting from it and the iterator gets confused.
34
- # use _with_index for fast deletion as opposed to .reject!{|obj| obj == *_warning}
35
- warnings[:new].dup.each_with_index do |new_warning, new_warning_id|
36
- warnings[:fixed].each_with_index do |fixed_warning, fixed_warning_id|
37
- if eql_except_line_number new_warning, fixed_warning
38
- warnings[:new].delete_at(new_warning_id - elements_deleted_offset)
39
- elements_deleted_offset += 1
40
- warnings[:fixed].delete_at(fixed_warning_id)
41
- break
42
- end
31
+ # Remove warnings which fingerprints are both in :new and :fixed
32
+ shared_fingerprints = new_fingerprints.intersection(fixed_fingerprints)
33
+
34
+ unless shared_fingerprints.empty?
35
+ warnings[:new].delete_if do |warning|
36
+ shared_fingerprints.include?(fingerprint(warning))
37
+ end
38
+
39
+ warnings[:fixed].delete_if do |warning|
40
+ shared_fingerprints.include?(fingerprint(warning))
43
41
  end
44
42
  end
45
43
 
46
44
  warnings
47
45
  end
48
46
 
49
- def eql_except_line_number new_warning, fixed_warning
50
- # can't do this ahead of time, as callers may be expecting a Brakeman::Warning
51
- if new_warning.is_a? Brakeman::Warning
52
- new_warning = new_warning.to_hash
53
- fixed_warning = fixed_warning.to_hash
54
- end
55
-
56
- if new_warning[:fingerprint] and fixed_warning[:fingerprint]
57
- new_warning[:fingerprint] == fixed_warning[:fingerprint]
47
+ def fingerprint(warning)
48
+ if warning.is_a?(Brakeman::Warning)
49
+ warning.fingerprint
58
50
  else
59
- OLD_WARNING_KEYS.each do |attr|
60
- return false if new_warning[attr] != fixed_warning[attr]
61
- end
62
-
63
- true
51
+ warning[:fingerprint]
64
52
  end
65
53
  end
66
54
  end
@@ -1,6 +1,6 @@
1
1
  module Brakeman
2
2
  module FakeHamlFilter
3
- # Copied from Haml - force delayed compilation
3
+ # Copied from Haml 4 - force delayed compilation
4
4
  def compile(compiler, text)
5
5
  filter = self
6
6
  compiler.instance_eval do
@@ -79,7 +79,9 @@ module Brakeman
79
79
 
80
80
  Haml::Engine.new(text,
81
81
  :filename => path,
82
- :escape_html => tracker.config.escape_html?).precompiled.gsub(/([^\\])\\n/, '\1')
82
+ :escape_html => tracker.config.escape_html?,
83
+ :escape_filter_interpolations => tracker.config.escape_filter_interpolations?
84
+ ).precompiled.gsub(/([^\\])\\n/, '\1')
83
85
  rescue Haml::Error => e
84
86
  tracker.error e, ["While compiling HAML in #{path}"] << e.backtrace
85
87
  nil
@@ -249,6 +249,9 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
249
249
  end
250
250
  env[target_var] = target
251
251
  return first_arg
252
+ elsif new_string? target
253
+ env[target_var] = first_arg
254
+ return first_arg
252
255
  elsif array? target
253
256
  target << first_arg
254
257
  env[target_var] = target
@@ -1198,6 +1201,13 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
1198
1201
  call? exp and exp.method == :raise
1199
1202
  end
1200
1203
 
1204
+ STRING_NEW = s(:call, s(:const, :String), :new)
1205
+
1206
+ # String.new ?
1207
+ def new_string? exp
1208
+ exp == STRING_NEW
1209
+ end
1210
+
1201
1211
  #Set variable to given value.
1202
1212
  #Creates "branched" versions of values when appropriate.
1203
1213
  #Avoids creating multiple branched versions inside same
@@ -114,6 +114,8 @@ class Brakeman::BaseProcessor < Brakeman::SexpProcessor
114
114
  exp.unshift :rlist
115
115
  end
116
116
 
117
+ alias process_rlist process_block
118
+
117
119
  #Processes the inside of an interpolated String.
118
120
  def process_evstr exp
119
121
  exp = exp.dup
@@ -2,8 +2,10 @@ require 'brakeman/processors/template_processor'
2
2
 
3
3
  #Processes HAML templates.
4
4
  class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
5
- HAML_FORMAT_METHOD = /format_script_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)/
5
+ HAMLOUT = s(:call, nil, :_hamlout)
6
+ HAML_BUFFER = s(:call, HAMLOUT, :buffer)
6
7
  HAML_HELPERS = s(:colon2, s(:const, :Haml), :Helpers)
8
+ HAML_HELPERS2 = s(:colon2, s(:colon3, :Haml), :Helpers)
7
9
  JAVASCRIPT_FILTER = s(:colon2, s(:colon2, s(:const, :Haml), :Filters), :Javascript)
8
10
  COFFEE_FILTER = s(:colon2, s(:colon2, s(:const, :Haml), :Filters), :Coffee)
9
11
 
@@ -14,130 +16,46 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
14
16
 
15
17
  #Processes call, looking for template output
16
18
  def process_call exp
17
- target = exp.target
18
- if sexp? target
19
- target = process target
19
+ exp = process_default exp
20
+
21
+ if buffer_append? exp
22
+ output = normalize_output(exp.first_arg)
23
+ res = get_pushed_value(output)
20
24
  end
21
25
 
22
- method = exp.method
23
-
24
- if (call? target and target.method == :_hamlout)
25
- res = case method
26
- when :adjust_tabs, :rstrip!, :attributes #Check attributes, maybe?
27
- ignore
28
- when :options, :buffer
29
- exp
30
- when :open_tag
31
- process_call_args exp
32
- else
33
- arg = exp.first_arg
34
-
35
- if arg
36
- @inside_concat = true
37
- exp.first_arg = process(arg)
38
- out = normalize_output(exp.first_arg)
39
- @inside_concat = false
40
- else
41
- raise "Empty _hamlout.#{method}()?"
42
- end
43
-
44
- if string? out
45
- ignore
46
- else
47
- r = case method.to_s
48
- when "push_text"
49
- build_output_from_push_text(out)
50
- when HAML_FORMAT_METHOD
51
- if $4 == "true"
52
- if string_interp? out
53
- build_output_from_push_text(out, :escaped_output)
54
- else
55
- Sexp.new :format_escaped, out
56
- end
57
- else
58
- if string_interp? out
59
- build_output_from_push_text(out)
60
- else
61
- Sexp.new :format, out
62
- end
63
- end
64
-
65
- else
66
- raise "Unrecognized action on _hamlout: #{method}"
67
- end
68
-
69
- @javascript = false
70
- r
71
- end
72
- end
73
-
74
- res.line(exp.line)
75
- res
76
-
77
- #_hamlout.buffer <<
78
- #This seems to be used rarely, but directly appends args to output buffer.
79
- #Has something to do with values of blocks?
80
- elsif sexp? target and method == :<< and is_buffer_target? target
81
- @inside_concat = true
82
- exp.first_arg = process(exp.first_arg)
83
- out = normalize_output(exp.first_arg)
84
- @inside_concat = false
85
-
86
- if out.node_type == :str #ignore plain strings
87
- ignore
88
- else
89
- add_output out
90
- end
91
- elsif target == nil and method == :render
92
- #Process call to render()
93
- exp.arglist = process exp.arglist
94
- make_render_in_view exp
95
- elsif target == nil and method == :find_and_preserve and exp.first_arg
96
- process exp.first_arg
97
- elsif method == :render_with_options
98
- if target == JAVASCRIPT_FILTER or target == COFFEE_FILTER
99
- @javascript = true
100
- end
26
+ res or exp
27
+ end
101
28
 
102
- process exp.first_arg
103
- else
104
- exp.target = target
105
- exp.arglist = process exp.arglist
106
- exp
107
- end
29
+ # _haml_out.buffer << ...
30
+ def buffer_append? exp
31
+ call? exp and
32
+ exp.target == HAML_BUFFER and
33
+ exp.method == :<<
34
+ end
35
+
36
+ PRESERVE_METHODS = [:find_and_preserve, :preserve]
37
+
38
+ def find_and_preserve? exp
39
+ call? exp and
40
+ PRESERVE_METHODS.include?(exp.method) and
41
+ exp.first_arg
108
42
  end
109
43
 
110
44
  #If inside an output stream, only return the final expression
111
45
  def process_block exp
112
46
  exp = exp.dup
113
47
  exp.shift
114
- if @inside_concat
115
- @inside_concat = false
116
- exp[0..-2].each do |e|
117
- process e
118
- end
119
- @inside_concat = true
120
- process exp[-1]
121
- else
122
- exp.map! do |e|
123
- res = process e
124
- if res.empty?
125
- nil
126
- else
127
- res
128
- end
48
+
49
+ exp.map! do |e|
50
+ res = process e
51
+ if res.empty?
52
+ nil
53
+ else
54
+ res
129
55
  end
130
- Sexp.new(:rlist).concat(exp).compact
131
56
  end
132
- end
133
57
 
134
- #Checks if the buffer is the target in a method call Sexp.
135
- #TODO: Test this
136
- def is_buffer_target? exp
137
- exp.node_type == :call and
138
- node_type? exp.target, :lvar and
139
- exp.target.value == :_hamlout and
140
- exp.method == :buffer
58
+ Sexp.new(:rlist).concat(exp).compact
141
59
  end
142
60
 
143
61
  #HAML likes to put interpolated values into _hamlout.push_text
@@ -158,7 +76,6 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
158
76
  end
159
77
  end
160
78
 
161
- #Gets outputs from values interpolated into _hamlout.push_text
162
79
  def get_pushed_value exp, default = :output
163
80
  return exp unless sexp? exp
164
81
 
@@ -173,24 +90,71 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
173
90
  exp
174
91
  when :str, :ignore, :output, :escaped_output
175
92
  exp
176
- when :block, :rlist, :dstr
177
- exp.map! { |e| get_pushed_value e }
93
+ when :block, :rlist
94
+ exp.map! { |e| get_pushed_value(e, default) }
95
+ when :dstr
96
+ build_output_from_push_text(exp, default)
178
97
  when :if
179
- clauses = [get_pushed_value(exp.then_clause), get_pushed_value(exp.else_clause)].compact
98
+ clauses = [get_pushed_value(exp.then_clause, default), get_pushed_value(exp.else_clause, default)].compact
180
99
 
181
100
  if clauses.length > 1
182
101
  s(:or, *clauses).line(exp.line)
183
102
  else
184
103
  clauses.first
185
104
  end
186
- else
187
- if call? exp and exp.target == HAML_HELPERS and exp.method == :html_escape
188
- add_escaped_output exp.first_arg
189
- elsif @javascript and call? exp and (exp.method == :j or exp.method == :escape_javascript)
190
- add_escaped_output exp.first_arg
105
+ when :call
106
+ if exp.method == :to_s or exp.method == :strip
107
+ get_pushed_value(exp.target, default)
108
+ elsif haml_helpers? exp.target and exp.method == :html_escape
109
+ get_pushed_value(exp.first_arg, :escaped_output)
110
+ elsif @javascript and (exp.method == :j or exp.method == :escape_javascript) # TODO: Remove - this is not safe
111
+ get_pushed_value(exp.first_arg, :escaped_output)
112
+ elsif find_and_preserve? exp or fix_textareas? exp
113
+ get_pushed_value(exp.first_arg, default)
114
+ elsif raw? exp
115
+ get_pushed_value(exp.first_arg, :output)
116
+ elsif hamlout_attributes? exp
117
+ ignore # ignore _hamlout.attributes calls
118
+ elsif exp.target.nil? and exp.method == :render
119
+ #Process call to render()
120
+ exp.arglist = process exp.arglist
121
+ make_render_in_view exp
122
+ elsif exp.method == :render_with_options
123
+ if exp.target == JAVASCRIPT_FILTER or exp.target == COFFEE_FILTER
124
+ @javascript = true
125
+ end
126
+
127
+ get_pushed_value(exp.first_arg, default)
128
+ @javascript = false
191
129
  else
192
130
  add_output exp, default
193
131
  end
132
+ else
133
+ add_output exp, default
194
134
  end
195
135
  end
136
+
137
+ def haml_helpers? exp
138
+ # Sometimes its Haml::Helpers and
139
+ # sometimes its ::Haml::Helpers
140
+ exp == HAML_HELPERS or
141
+ exp == HAML_HELPERS2
142
+ end
143
+
144
+ def hamlout_attributes? exp
145
+ call? exp and
146
+ exp.target == HAMLOUT and
147
+ exp.method == :attributes
148
+ end
149
+
150
+ def fix_textareas? exp
151
+ call? exp and
152
+ exp.target == HAMLOUT and
153
+ exp.method == :fix_textareas!
154
+ end
155
+
156
+ def raw? exp
157
+ call? exp and
158
+ exp.method == :raw
159
+ end
196
160
  end
@@ -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
@@ -32,6 +32,34 @@ class Brakeman::TemplateAliasProcessor < Brakeman::AliasProcessor
32
32
  end
33
33
  end
34
34
 
35
+ def process_lasgn exp
36
+ if exp.lhs == :haml_temp or haml_capture? exp.rhs
37
+ exp.rhs = process exp.rhs
38
+
39
+ # Avoid propagating contents of block
40
+ if node_type? exp.rhs, :iter
41
+ new_exp = exp.dup
42
+ new_exp.rhs = exp.rhs.block_call
43
+
44
+ super new_exp
45
+
46
+ exp # Still save the original, though
47
+ else
48
+ super exp
49
+ end
50
+ else
51
+ super exp
52
+ end
53
+ end
54
+
55
+ HAML_CAPTURE = [:capture, :capture_haml]
56
+
57
+ def haml_capture? exp
58
+ node_type? exp, :iter and
59
+ call? exp.block_call and
60
+ HAML_CAPTURE.include? exp.block_call.method
61
+ end
62
+
35
63
  #Determine template name
36
64
  def template_name name
37
65
  if !name.to_s.include?('/') && @template.name.to_s.include?('/')
@@ -4,10 +4,8 @@ module Brakeman
4
4
  class Config
5
5
  include Util
6
6
 
7
- attr_reader :rails, :tracker
8
- attr_accessor :rails_version, :ruby_version
7
+ attr_reader :gems, :rails, :ruby_version, :tracker
9
8
  attr_writer :erubis, :escape_html
10
- attr_reader :gems
11
9
 
12
10
  def initialize tracker
13
11
  @tracker = tracker
@@ -20,7 +18,7 @@ module Brakeman
20
18
  end
21
19
 
22
20
  def default_protect_from_forgery?
23
- if version_between? "5.2.0", "9.9.9"
21
+ if version_between? "5.2.0.beta1", "9.9.9"
24
22
  if @rails.dig(:action_controller, :default_protect_from_forgery) == Sexp.new(:false)
25
23
  return false
26
24
  else
@@ -44,12 +42,18 @@ module Brakeman
44
42
  true? @rails.dig(:active_support, :escape_html_entities_in_json)
45
43
  end
46
44
 
45
+ def escape_filter_interpolations?
46
+ # TODO see if app is actually turning this off itself
47
+ has_gem?(:haml) and
48
+ version_between? "5.0.0", "5.99", gem_version(:haml)
49
+ end
50
+
47
51
  def whitelist_attributes?
48
52
  @rails.dig(:active_record, :whitelist_attributes) == Sexp.new(:true)
49
53
  end
50
54
 
51
55
  def gem_version name
52
- @gems.dig(name, :version)
56
+ extract_version @gems.dig(name, :version)
53
57
  end
54
58
 
55
59
  def add_gem name, version, file, line
@@ -69,11 +73,16 @@ module Brakeman
69
73
  @gems[name]
70
74
  end
71
75
 
72
- def set_rails_version
73
- # Ignore ~>, etc. when using values from Gemfile
74
- version = gem_version(:rails) || gem_version(:railties)
75
- if version and version.match(/(\d+\.\d+(\.\d+.*)?)/)
76
- @rails_version = $1
76
+ def set_rails_version version = nil
77
+ version = if version
78
+ # Only used by Rails2ConfigProcessor right now
79
+ extract_version(version)
80
+ else
81
+ gem_version(:rails) || gem_version(:railties)
82
+ end
83
+
84
+ if version
85
+ @rails_version = version
77
86
 
78
87
  if tracker.options[:rails3].nil? and tracker.options[:rails4].nil?
79
88
  if @rails_version.start_with? "3"
@@ -102,16 +111,22 @@ module Brakeman
102
111
  @escape_html = true
103
112
  Brakeman.notify "[Notice] Escaping HTML by default"
104
113
  end
114
+ end
105
115
 
106
- check_haml_version
116
+ def rails_version
117
+ # This needs to be here because Util#rails_version calls Tracker::Config#rails_version
118
+ # but Tracker::Config includes Util...
119
+ @rails_version
107
120
  end
108
121
 
109
122
  def set_ruby_version version
123
+ @ruby_version = extract_version(version)
124
+ end
125
+
126
+ def extract_version version
110
127
  return unless version.is_a? String
111
128
 
112
- if version =~ /(\d+\.\d+\.\d+)/
113
- self.ruby_version = $1
114
- end
129
+ version[/\d+\.\d+(\.\d+.*)?/]
115
130
  end
116
131
 
117
132
  #Returns true if low_version <= RAILS_VERSION <= high_version
@@ -121,89 +136,15 @@ module Brakeman
121
136
  current_version ||= rails_version
122
137
  return false unless current_version
123
138
 
124
- version = current_version.split(".").map! { |v| convert_version_number v }
125
- low_version = low_version.split(".").map! { |v| convert_version_number v }
126
- high_version = high_version.split(".").map! { |v| convert_version_number v }
127
-
128
- version.each_with_index do |v, i|
129
- if lower? v, low_version.fetch(i, 0)
130
- return false
131
- elsif higher? v, low_version.fetch(i, 0)
132
- break
133
- end
134
- end
135
-
136
- version.each_with_index do |v, i|
137
- if higher? v, high_version.fetch(i, 0)
138
- return false
139
- elsif lower? v, high_version.fetch(i, 0)
140
- break
141
- end
142
- end
139
+ low = Gem::Version.new(low_version)
140
+ high = Gem::Version.new(high_version)
141
+ current = Gem::Version.new(current_version)
143
142
 
144
- true
143
+ current.between?(low, high)
145
144
  end
146
145
 
147
146
  def session_settings
148
147
  @rails.dig(:action_controller, :session)
149
148
  end
150
-
151
- private
152
-
153
- # Brakeman does not support Haml 5 yet.
154
- # (https://github.com/presidentbeef/brakeman/issues/1370) Fortunately, Haml
155
- # 5 doesn't add much new syntax, and brakeman (which uses the haml 4 parser)
156
- # will parse most Haml 5 files without errors. Therefore, we only print a
157
- # warning here, instead of raising an error.
158
- def check_haml_version
159
- return if supported_haml_version?
160
- Brakeman.notify <<~EOS
161
- Brakeman does not fully support Haml 5 yet. Your Gemfile (or gemspec)
162
- allows Haml 5. Brakeman uses the Haml 4 parser and thus may produce
163
- errors when parsing Haml 5 syntax. If Brakeman encounters such an error,
164
- it will be unable to scan that file.
165
- EOS
166
- end
167
-
168
- def convert_version_number value
169
- if value.match(/\A\d+\z/)
170
- value.to_i
171
- else
172
- value
173
- end
174
- end
175
-
176
- def lower? lhs, rhs
177
- if lhs.class == rhs.class
178
- lhs < rhs
179
- else
180
- false
181
- end
182
- end
183
-
184
- # Brakeman does not support Haml 5 yet. See `check_haml_version`.
185
- #
186
- # This method is messy because all we have is a version `Requirement` (like
187
- # `~> 5.0.3`, or `> 4.99`) The only way I could think of was to loop over
188
- # known Haml 5 versions and test whether the `Requirement` is satisfied. I
189
- # included '5.99.99' in the list so that this method might stand a chance of
190
- # working in the future.
191
- def supported_haml_version?
192
- haml_version = gem_version(:haml)
193
- return true unless haml_version
194
-
195
- requirement = Gem::Requirement.new(haml_version)
196
- ['5.99.99', '5.1.1', '5.1.0', '5.0.4', '5.0.3', '5.0.2', '5.0.1', '5.0.0'].none? do |v|
197
- requirement.satisfied_by?(Gem::Version.new(v))
198
- end
199
- end
200
-
201
- def higher? lhs, rhs
202
- if lhs.class == rhs.class
203
- lhs > rhs
204
- else
205
- false
206
- end
207
- end
208
149
  end
209
150
  end
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "4.6.1"
2
+ Version = "4.7.0"
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: 4.6.1
4
+ version: 4.7.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: 2019-07-24 00:00:00.000000000 Z
12
+ date: 2019-10-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest