brakeman-lib 4.2.1 → 4.3.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: 7070db1a411e9196bbb90fe7a34209ecd8cf15210e5fa21be1442c668e8f00d0
4
- data.tar.gz: 940132f27d3803e1fa445d51c869cf426a712d065892f49b6e138222dc66ba71
3
+ metadata.gz: '08b3a1c2f84d6667c990309480405c61baa2f2ac878dfdc12dbefacdff64a52e'
4
+ data.tar.gz: 58ba877ea3b52c2e464bb4cca233edf1823f199db71e009df8eb92ce748ee9cf
5
5
  SHA512:
6
- metadata.gz: dfbb4f4f11b1e8b00a206a6185e3e58862061f954a43cdf611fb38d6bd97b0e04ef6439adcc68b6ea6dc1675b5853f8a9af03c378be3d7cc6d9f4f49a61f5d5d
7
- data.tar.gz: 77cb923ae34ee9a094200e1dc08a120ca001b4f646907fcb896bc147694041c989bfea7dc3023d876c0ee1461bedd5dc35cae53b94ef36ee6971baff980ceaae
6
+ metadata.gz: 905adec5711738aaddf2fbfd2bebd9ce9aa039a556fcacbef39177e1d34b44dd953952bf56904444211876466da5c16ae2c2bd8d42ebca00b6a7755a26e600de
7
+ data.tar.gz: da402133851cb1f3035cbe1784bf4c2e36831bd5167914c2bac82665b57430e2b9dbe9a4aa283e1365556dfcbfb07c933726049f9ee96377b83a676e56f1566f
data/CHANGES.md CHANGED
@@ -1,3 +1,19 @@
1
+ # 4.3.0
2
+
3
+ * Check exec-type calls even if they are targets
4
+ * Convert `Array#join` to string interpolation
5
+ * `BaseCheck#include_interp?` should return first string interpolation
6
+ * Add `--parser-timeout` option
7
+ * Track parent calls in CallIndex
8
+ * Warn about dangerous `link_to` href with `sanitize()`
9
+ * Ignore `params#to_h` and `params#to_hash` in SQL checks
10
+ * Change "".freeze to just ""
11
+ * Ignore `Process.pid` in system calls
12
+ * Index Kernel#\` calls even if they are targets
13
+ * Code Climate: omit leading dot from `only_files` (Todd Mazierski)
14
+ * `--color` can be used to force color output
15
+ * Fix reported line numbers for CVE-2018-3741 and CVE-2018-8048
16
+
1
17
  # 4.2.1
2
18
 
3
19
  * Add warning for CVE-2018-3741
@@ -51,6 +51,7 @@ module Brakeman
51
51
  # * :output_files - files for output
52
52
  # * :output_formats - formats for output (:to_s, :to_tabs, :to_csv, :to_html)
53
53
  # * :parallel_checks - run checks in parallel (default: true)
54
+ # * :parser_timeout - set timeout for parsing an individual file (default: 10 seconds)
54
55
  # * :print_report - if no output file specified, print to stdout (default: false)
55
56
  # * :quiet - suppress most messages (default: true)
56
57
  # * :rails3 - force Rails 3 mode (automatic)
@@ -174,6 +175,7 @@ module Brakeman
174
175
  :output_color => true,
175
176
  :pager => true,
176
177
  :parallel_checks => true,
178
+ :parser_timeout => 10,
177
179
  :relative_path => false,
178
180
  :report_progress => true,
179
181
  :safe_methods => Set.new,
@@ -376,7 +378,7 @@ module Brakeman
376
378
 
377
379
  def self.write_report_to_files tracker, output_files
378
380
  require 'fileutils'
379
- tracker.options[:output_color] = false
381
+ tracker.options[:output_color] = false unless tracker.options[:output_color] == :force
380
382
 
381
383
  output_files.each_with_index do |output_file, idx|
382
384
  dir = File.dirname(output_file)
@@ -393,7 +395,7 @@ module Brakeman
393
395
  private_class_method :write_report_to_files
394
396
 
395
397
  def self.write_report_to_formats tracker, output_formats
396
- unless $stdout.tty?
398
+ unless $stdout.tty? or tracker.options[:output_color] == :force
397
399
  tracker.options[:output_color] = false
398
400
  end
399
401
 
@@ -119,7 +119,10 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
119
119
 
120
120
  #Does not actually process string interpolation, but notes that it occurred.
121
121
  def process_dstr exp
122
- @string_interp = Match.new(:interp, exp)
122
+ unless @string_interp # don't overwrite existing value
123
+ @string_interp = Match.new(:interp, exp)
124
+ end
125
+
123
126
  process_default exp
124
127
  end
125
128
 
@@ -15,7 +15,8 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
15
15
 
16
16
  SAFE_VALUES = [s(:const, :RAILS_ROOT),
17
17
  s(:call, s(:const, :Rails), :root),
18
- s(:call, s(:const, :Rails), :env)]
18
+ s(:call, s(:const, :Rails), :env),
19
+ s(:call, s(:const, :Process), :pid)]
19
20
 
20
21
  SHELL_ESCAPES = [:escape, :shellescape, :join]
21
22
 
@@ -32,7 +33,7 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
32
33
  calls = tracker.find_call :targets => [:IO, :Open3, :Kernel, :'POSIX::Spawn', :Process, nil],
33
34
  :methods => [:capture2, :capture2e, :capture3, :exec, :pipeline, :pipeline_r,
34
35
  :pipeline_rw, :pipeline_start, :pipeline_w, :popen, :popen2, :popen2e,
35
- :popen3, :spawn, :syscall, :system]
36
+ :popen3, :spawn, :syscall, :system], :nested => true
36
37
 
37
38
  Brakeman.debug "Processing system calls"
38
39
  calls.each do |result|
@@ -71,14 +71,15 @@ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
71
71
  end
72
72
  end
73
73
 
74
+ CHECK_INSIDE_METHODS = [:url_for, :h, :sanitize]
75
+
74
76
  def check_argument? url_arg
75
77
  return unless call? url_arg
76
78
 
77
79
  target = url_arg.target
78
80
  method = url_arg.method
79
81
 
80
- method == :url_for or
81
- method == :h or
82
+ CHECK_INSIDE_METHODS.include? method or
82
83
  cgi_escaped? target, method
83
84
  end
84
85
 
@@ -46,12 +46,6 @@ class Brakeman::CheckSanitizeMethods < Brakeman::BaseCheck
46
46
 
47
47
  message = "Rails #{rails_version} has a vulnerability in #{method}: upgrade to #{@fix_version} or patch"
48
48
 
49
- if include_user_input? result[:call]
50
- confidence = :high
51
- else
52
- confidence = :medium
53
- end
54
-
55
49
  warn :result => result,
56
50
  :warning_type => "Cross-Site Scripting",
57
51
  :warning_code => code,
@@ -87,7 +81,7 @@ class Brakeman::CheckSanitizeMethods < Brakeman::BaseCheck
87
81
  warn :warning_type => "Cross-Site Scripting",
88
82
  :warning_code => :CVE_2018_8048,
89
83
  :message => message,
90
- :gem_info => gemfile_or_environment,
84
+ :gem_info => gemfile_or_environment(:loofah),
91
85
  :confidence => confidence,
92
86
  :link_path => "https://github.com/flavorjones/loofah/issues/144"
93
87
  end
@@ -111,7 +105,7 @@ class Brakeman::CheckSanitizeMethods < Brakeman::BaseCheck
111
105
  warn :warning_type => "Cross-Site Scripting",
112
106
  :warning_code => cve.tr('-', '_').to_sym,
113
107
  :message => message,
114
- :gem_info => gemfile_or_environment,
108
+ :gem_info => gemfile_or_environment(:'rails-html-sanitizer'),
115
109
  :confidence => confidence,
116
110
  :link_path => link
117
111
  end
@@ -290,7 +290,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
290
290
  end
291
291
 
292
292
  if request_value? arg
293
- unless call? arg and params? arg.target and [:permit, :slice].include? arg.method
293
+ unless call? arg and params? arg.target and [:permit, :slice, :to_h, :to_hash].include? arg.method
294
294
  # Model.where(params[:where])
295
295
  arg
296
296
  end
@@ -87,9 +87,9 @@ module Brakeman
87
87
 
88
88
  def stripped_include_path(prefix, subprefixes, path)
89
89
  if path.start_with?(prefix)
90
- path.sub(%r{^#{prefix}/?}, "./")
90
+ path.sub(%r{^#{prefix}/?}, "/")
91
91
  elsif subprefixes.any? { |subprefix| path =~ %r{^#{subprefix}/?$} }
92
- "./"
92
+ "/"
93
93
  end
94
94
  end
95
95
  end
@@ -7,6 +7,7 @@ module Brakeman
7
7
 
8
8
  def initialize tracker, app_tree
9
9
  @tracker = tracker
10
+ @timeout = @tracker.options[:parser_timeout]
10
11
  @app_tree = app_tree
11
12
  @file_list = {}
12
13
  end
@@ -33,10 +34,13 @@ module Brakeman
33
34
  def parse_ruby input, path
34
35
  begin
35
36
  Brakeman.debug "Parsing #{path}"
36
- RubyParser.new.parse input, path
37
+ RubyParser.new.parse input, path, @timeout
37
38
  rescue Racc::ParseError => e
38
39
  @tracker.error e, "Could not parse #{path}"
39
40
  nil
41
+ rescue Timeout::Error => e
42
+ @tracker.error Exception.new("Parsing #{path} took too long (> #{@timeout} seconds). Try increasing the limit with --parser-timeout"), caller
43
+ nil
40
44
  rescue => e
41
45
  @tracker.error e.exception(e.message + "\nWhile processing #{path}"), e.backtrace
42
46
  nil
@@ -127,6 +127,10 @@ module Brakeman::Options
127
127
  options[:branch_limit] = limit
128
128
  end
129
129
 
130
+ opts.on "--parser-timeout SECONDS", Integer, "Set parse timeout (Default: 10)" do |timeout|
131
+ options[:parser_timeout] = timeout
132
+ end
133
+
130
134
  opts.on "-r", "--report-direct", "Only report direct use of untrusted data" do |option|
131
135
  options[:check_arguments] = !option
132
136
  end
@@ -229,7 +233,11 @@ module Brakeman::Options
229
233
  end
230
234
 
231
235
  opts.on "--[no-]color", "Use ANSI colors in report (Default)" do |color|
232
- options[:output_color] = color
236
+ if color
237
+ options[:output_color] = :force
238
+ else
239
+ options[:output_color] = color
240
+ end
233
241
  end
234
242
 
235
243
  opts.on "-m", "--routes", "Report controller information" do
@@ -93,7 +93,7 @@ module Brakeman
93
93
  end
94
94
 
95
95
  def self.parse_inline_erb tracker, text
96
- fp = Brakeman::FileParser.new(nil, nil)
96
+ fp = Brakeman::FileParser.new(tracker, nil)
97
97
  tp = self.new(tracker, fp)
98
98
  src = tp.parse_erb '_inline_', text
99
99
  type = tp.erubis? ? :erubis : :erb
@@ -197,7 +197,6 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
197
197
  return Sexp.new(:false)
198
198
  end
199
199
 
200
-
201
200
  #See if it is possible to simplify some basic cases
202
201
  #of addition/concatenation.
203
202
  case method
@@ -287,11 +286,80 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
287
286
  if array? target and first_arg.nil? and sexp? target[1]
288
287
  exp = target[1]
289
288
  end
289
+ when :freeze
290
+ if string? target
291
+ exp = process exp.target
292
+ end
293
+ when :join
294
+ if array? target and target.length > 2 and (string? first_arg or first_arg.nil?)
295
+ exp = process_array_join(target, first_arg)
296
+ end
290
297
  end
291
298
 
292
299
  exp
293
300
  end
294
301
 
302
+ # Painful conversion of Array#join into string interpolation
303
+ def process_array_join array, join_str
304
+ result = s()
305
+
306
+ join_value = if string? join_str
307
+ join_str.value
308
+ else
309
+ nil
310
+ end
311
+
312
+ array[1..-2].each do |e|
313
+ result << join_item(e, join_value)
314
+ end
315
+
316
+ result << join_item(array.last, nil)
317
+
318
+ # Combine the strings at the beginning because that's what RubyParser does
319
+ combined_first = ""
320
+ result.each do |e|
321
+ if string? e
322
+ combined_first << e.value
323
+ elsif e.is_a? String
324
+ combined_first << e
325
+ else
326
+ break
327
+ end
328
+ end
329
+
330
+ # Remove the strings at the beginning
331
+ result.reject! do |e|
332
+ if e.is_a? String or string? e
333
+ true
334
+ else
335
+ break
336
+ end
337
+ end
338
+
339
+ result.unshift combined_first
340
+
341
+ # Have to fix up strings that follow interpolation
342
+ result.reduce(s(:dstr)) do |memo, e|
343
+ if string? e and node_type? memo.last, :evstr
344
+ e.value = "#{join_value}#{e.value}"
345
+ elsif join_value and node_type? memo.last, :evstr and node_type? e, :evstr
346
+ memo << s(:str, join_value)
347
+ end
348
+
349
+ memo << e
350
+ end
351
+ end
352
+
353
+ def join_item item, join_value
354
+ if item.is_a? String
355
+ "#{item}#{join_value}"
356
+ elsif string? item or symbol? item or number? item
357
+ s(:str, "#{item.value}#{join_value}")
358
+ else
359
+ s(:evstr, item)
360
+ end
361
+ end
362
+
295
363
  def process_iter exp
296
364
  @exp_context.push exp
297
365
  exp[1] = process exp.block_call
@@ -19,6 +19,7 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
19
19
  @current_method = opts[:method]
20
20
  @current_template = opts[:template]
21
21
  @current_file = opts[:file]
22
+ @current_call = nil
22
23
  process exp
23
24
  end
24
25
 
@@ -111,7 +112,8 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
111
112
  :method => method_name,
112
113
  :call => exp,
113
114
  :nested => false,
114
- :location => make_location }
115
+ :location => make_location,
116
+ :parent => @current_call }
115
117
  end
116
118
 
117
119
  #Gets the target of a call as a Symbol
@@ -189,7 +191,7 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
189
191
  def create_call_hash exp
190
192
  target = get_target exp.target
191
193
 
192
- if call? target
194
+ if call? target or node_type? target, :dxstr # need to index `` even if target of a call
193
195
  already_in_target = @in_target
194
196
  @in_target = true
195
197
  process target
@@ -199,13 +201,24 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
199
201
  end
200
202
 
201
203
  method = exp.method
202
- process_call_args exp
203
204
 
204
- { :target => target,
205
+ call_hash = {
206
+ :target => target,
205
207
  :method => method,
206
208
  :call => exp,
207
209
  :nested => @in_target,
208
210
  :chain => get_chain(exp),
209
- :location => make_location }
211
+ :location => make_location,
212
+ :parent => @current_call
213
+ }
214
+
215
+ old_parent = @current_call
216
+ @current_call = call_hash
217
+
218
+ process_call_args exp
219
+
220
+ @current_call = old_parent
221
+
222
+ call_hash
210
223
  end
211
224
  end
@@ -102,7 +102,9 @@ module Brakeman
102
102
  end
103
103
 
104
104
  def set_color
105
- unless @tracker and less_options.include? "-R "
105
+ return unless @tracker
106
+
107
+ unless less_options.include? "-R " or @tracker.options[:output_color] == :force
106
108
  @tracker.options[:output_color] = false
107
109
  end
108
110
  end
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "4.2.1"
2
+ Version = "4.3.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brakeman-lib
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.1
4
+ version: 4.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: 2018-03-24 00:00:00.000000000 Z
12
+ date: 2018-05-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -380,7 +380,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
380
380
  version: '0'
381
381
  requirements: []
382
382
  rubyforge_project:
383
- rubygems_version: 2.7.3
383
+ rubygems_version: 2.7.6
384
384
  signing_key:
385
385
  specification_version: 4
386
386
  summary: Security vulnerability scanner for Ruby on Rails.