brakeman-min 4.0.1 → 4.1.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
  SHA1:
3
- metadata.gz: 730e9fa0a5a00feba7a5c64d6cdb6e5eabc914da
4
- data.tar.gz: 1b75b40d02c13de9191aa9a5f6643d2609ec3a78
3
+ metadata.gz: 26a5b1305b5c9bf834d1ce617ea77ebc78c4f5c4
4
+ data.tar.gz: b63c0c4376d1eff140a6bd83542db488fd127b11
5
5
  SHA512:
6
- metadata.gz: 9d35409bcb12d0790b5b8cbb0ba90137caff38bcd7d0bfebca7cd039e2964197e4422b77be305eaa8daaf10ef8b22b9c675c55b24c8f75ebc8f70f31f3ec187b
7
- data.tar.gz: 4bdd9e7f614bde8928b4d3722d6f49e40136db09bcdfb247a9a2ea9642cc04f2f10a3e1b247c85b9d8ad0826f6982037c3ba4fe5703a5eab26c515bd66139c0b
6
+ metadata.gz: a3ad9c8667a8d7affdfcd597dba9a810d53753219cecad3e90a2d59d43718ca7040c080fcacb9bc6be5dd8b0c6e20dc9180acae6f21a4e30d251a58b047566d2
7
+ data.tar.gz: 1626d4a585f49872e94a378d65efdf998f942eb3197f9a077f0937070b41bf0dff77acedb1dea654b6b15c028ed1b2ee334083027e2eda0183777b40bebac774
@@ -1,3 +1,26 @@
1
+ # 4.1.0
2
+
3
+ * Process models as root sexp instead of each sexp
4
+ * Avoid CSRF warning in Rails 5.2 default config
5
+ * Show better location for Sass errors (Andrew Bromwich)
6
+ * Warn about dynamic values in `Arel.sql`
7
+ * Fix `include_paths` for Code Climate engine (Will Fleming)
8
+ * Add check for dangerous keys in `permit`
9
+ * Try to guess options for `less` pager
10
+ * Better processing of op_asgn1 (e.g. x[:y] += 1)
11
+ * Add optional check for divide by zero
12
+ * Remove errors about divide by zero
13
+ * Avoid warning about file access for temp files
14
+ * Do not warn on params.permit with safe values
15
+ * Add Sexp#call_chain
16
+ * Use HTTPS for warning links
17
+ * Handle nested destructuring/multiple assignment
18
+ * Leave results on screen after paging
19
+ * Do not page if results fit on screen
20
+ * Support `app_path` configuration for Code Climate engine (Noah Davis)
21
+ * Refactor Code Climate engine options parsing (Noah Davis)
22
+ * Fix upgrade version for CVE-2016-6316
23
+
1
24
  # 4.0.1
2
25
 
3
26
  * Disable pager when `CI` environment variable is set
data/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
  [![Brakeman Pro Logo](https://brakemanpro.com/images/bmp_square_white.png)](https://brakemanpro.com)
3
3
 
4
4
  [![Build Status](https://travis-ci.org/presidentbeef/brakeman.svg?branch=master)](https://travis-ci.org/presidentbeef/brakeman)
5
- [![Code Climate](https://codeclimate.com/github/presidentbeef/brakeman/badges/gpa.svg)](https://codeclimate.com/github/presidentbeef/brakeman)
6
- [![Test Coverage](https://codeclimate.com/github/presidentbeef/brakeman/badges/coverage.svg)](https://codeclimate.com/github/presidentbeef/brakeman/coverage)
5
+ [![Maintainability](https://api.codeclimate.com/v1/badges/1b08a5c74695cb0d11ec/maintainability)](https://codeclimate.com/github/presidentbeef/brakeman/maintainability)
6
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/1b08a5c74695cb0d11ec/test_coverage)](https://codeclimate.com/github/presidentbeef/brakeman/test_coverage)
7
7
  [![Gitter](https://badges.gitter.im/presidentbeef/brakeman.svg)](https://gitter.im/presidentbeef/brakeman)
8
8
 
9
9
  # Brakeman
data/lib/brakeman.rb CHANGED
@@ -402,39 +402,12 @@ module Brakeman
402
402
  puts tracker.report.format(output_format)
403
403
  end
404
404
  else
405
- page_output tracker.report.format(output_formats.first)
406
- end
407
- end
408
- private_class_method :write_report_to_formats
409
-
410
- def self.page_output text
411
- ci = ENV["CI"]
405
+ require "brakeman/report/pager"
412
406
 
413
- if ci.is_a? String and ci.downcase == "true"
414
- puts text
415
- elsif system("which less")
416
- # Adapted from https://github.com/piotrmurach/tty-pager/
417
- write_io = open("|less -R", 'w')
418
- pid = write_io.pid
419
-
420
- write_io.write(text)
421
- write_io.close
422
-
423
- Process.waitpid2(pid, Process::WNOHANG)
424
- else
425
- load_brakeman_dependency 'highline'
426
- h = ::HighLine.new
427
- h.page_at = :auto
428
- h.say text
407
+ Brakeman::Pager.new(tracker).page_report(tracker.report, output_formats.first)
429
408
  end
430
- rescue Errno::ECHILD
431
- # on jruby 9x waiting on pid raises (per tty-pager)
432
- true
433
- rescue => e
434
- warn "[Error] #{e}"
435
- warn "[Error] Could not use pager. Set --no-pager to avoid this issue."
436
- puts text
437
409
  end
410
+ private_class_method :write_report_to_formats
438
411
 
439
412
  #Rescan a subset of files in a Rails application.
440
413
  #
@@ -445,41 +445,16 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
445
445
  false
446
446
  end
447
447
 
448
- #Returns true if low_version <= RAILS_VERSION <= high_version
449
- #
450
- #If the Rails version is unknown, returns false.
451
- def version_between? low_version, high_version, current_version = nil
452
- current_version ||= rails_version
453
- return false unless current_version
454
-
455
- version = current_version.split(".").map! { |n| n.to_i }
456
- low_version = low_version.split(".").map! { |n| n.to_i }
457
- high_version = high_version.split(".").map! { |n| n.to_i }
458
-
459
- version.each_with_index do |v, i|
460
- if v < low_version.fetch(i, 0)
461
- return false
462
- elsif v > low_version.fetch(i, 0)
463
- break
464
- end
465
- end
466
-
467
- version.each_with_index do |v, i|
468
- if v > high_version.fetch(i, 0)
469
- return false
470
- elsif v < high_version.fetch(i, 0)
471
- break
472
- end
473
- end
474
-
475
- true
476
- end
477
-
478
448
  def lts_version? version
479
449
  tracker.config.has_gem? :'railslts-version' and
480
450
  version_between? version, "2.3.18.99", tracker.config.gem_version(:'railslts-version')
481
451
  end
482
452
 
453
+
454
+ def version_between? low_version, high_version, current_version = nil
455
+ tracker.config.version_between? low_version, high_version, current_version
456
+ end
457
+
483
458
  def gemfile_or_environment gem_name = :rails
484
459
  if gem_name and info = tracker.config.get_gem(gem_name)
485
460
  info
@@ -170,7 +170,7 @@ class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
170
170
  when version_between?("4.0.0", "4.2.7.0")
171
171
  "4.2.7.1"
172
172
  when version_between?("5.0.0", "5.0.0")
173
- "5.0.0"
173
+ "5.0.0.1"
174
174
  when (version.nil? and tracker.options[:rails3])
175
175
  "3.2.22.4"
176
176
  when (version.nil? and tracker.options[:rails4])
@@ -0,0 +1,40 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckDivideByZero < Brakeman::BaseCheck
4
+ Brakeman::Checks.add_optional self
5
+
6
+ @description = "Warns on potential division by zero"
7
+
8
+ def run_check
9
+ tracker.find_call(:method => :"/").each do |result|
10
+ check_division result
11
+ end
12
+ end
13
+
14
+ def check_division result
15
+ call = result[:call]
16
+
17
+ denominator = call.first_arg
18
+
19
+ if number? denominator and denominator.value == 0
20
+ numerator = call.target
21
+
22
+ if number? numerator
23
+ if numerator.value.is_a? Float
24
+ return # 0.0 / 0 is NaN and 1.0 / 0 is Infinity
25
+ else
26
+ confidence = :medium
27
+ end
28
+ else
29
+ confidence = :weak
30
+ end
31
+
32
+ warn :result => result,
33
+ :warning_type => "Divide by Zero",
34
+ :warning_code => :divide_by_zero,
35
+ :message => "Potential division by zero",
36
+ :confidence => confidence,
37
+ :user_input => denominator
38
+ end
39
+ end
40
+ end
@@ -47,7 +47,8 @@ class Brakeman::CheckFileAccess < Brakeman::BaseCheck
47
47
  end
48
48
  end
49
49
 
50
- if match
50
+ if match and not temp_file? match.match
51
+
51
52
  message = "#{friendly_type_of(match).capitalize} used in file name"
52
53
 
53
54
  warn :result => result,
@@ -59,4 +60,12 @@ class Brakeman::CheckFileAccess < Brakeman::BaseCheck
59
60
  :user_input => match
60
61
  end
61
62
  end
63
+
64
+ def temp_file? exp
65
+ if call? exp
66
+ return true if exp.call_chain.include? :tempfile
67
+
68
+ params? exp.target and exp.method == :path
69
+ end
70
+ end
62
71
  end
@@ -10,6 +10,8 @@ class Brakeman::CheckForgerySetting < Brakeman::BaseCheck
10
10
  @description = "Verifies that protect_from_forgery is enabled in direct subclasses of ActionController::Base"
11
11
 
12
12
  def run_check
13
+ return if tracker.config.default_protect_from_forgery?
14
+
13
15
  tracker.controllers
14
16
  .select { |_, controller| controller.parent == :"ActionController::Base" }
15
17
  .each do |name, controller|
@@ -0,0 +1,43 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckPermitAttributes < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Warn on potentially dangerous attributes whitelisted via permit"
7
+
8
+ SUSPICIOUS_KEYS = {
9
+ admin: :high,
10
+ account_id: :high,
11
+ role: :medium,
12
+ banned: :medium,
13
+ }
14
+
15
+ def run_check
16
+ tracker.find_call(:method => :permit).each do |result|
17
+ check_permit result
18
+ end
19
+ end
20
+
21
+ def check_permit result
22
+ call = result[:call]
23
+
24
+ call.each_arg do |arg|
25
+ if symbol? arg
26
+ if SUSPICIOUS_KEYS.key? arg.value
27
+ warn_on_permit_key result, arg
28
+ elsif arg.value.match /_id$/
29
+ warn_on_permit_key result, arg, :medium
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def warn_on_permit_key result, key, confidence = nil
36
+ warn :result => result,
37
+ :warning_type => "Mass Assignment",
38
+ :warning_code => :dangerous_permit_key,
39
+ :message => "Potentially dangerous key allowed for mass assignment",
40
+ :confidence => (confidence || SUSPICIOUS_KEYS[key.value]),
41
+ :user_input => key
42
+ end
43
+ end
@@ -34,10 +34,13 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
34
34
  call = result[:call]
35
35
  method = call.method
36
36
 
37
+ opt = call.first_arg
38
+
37
39
  if method == :redirect_to and
38
40
  not only_path?(call) and
39
- not explicit_host?(call.first_arg) and
40
- not slice_call?(call.first_arg) and
41
+ not explicit_host?(opt) and
42
+ not slice_call?(opt) and
43
+ not safe_permit?(opt) and
41
44
  res = include_user_input?(call)
42
45
 
43
46
  if res.type == :immediate
@@ -232,4 +235,20 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
232
235
  return unless call? exp
233
236
  exp.method == :slice
234
237
  end
238
+
239
+ DANGEROUS_KEYS = [:host, :subdomain, :domain, :port]
240
+
241
+ def safe_permit? exp
242
+ if call? exp and params? exp.target and exp.method == :permit
243
+ exp.each_arg do |opt|
244
+ if symbol? opt and DANGEROUS_KEYS.include? opt.value
245
+ return false
246
+ end
247
+ end
248
+
249
+ return true
250
+ end
251
+
252
+ false
253
+ end
235
254
  end
@@ -38,7 +38,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
38
38
  @connection_calls.concat [:add_limit!, :add_offset_limit!, :add_lock!]
39
39
  end
40
40
 
41
- @expected_targets = active_record_models.keys + [:connection, :"ActiveRecord::Base"]
41
+ @expected_targets = active_record_models.keys + [:connection, :"ActiveRecord::Base", :Arel]
42
42
 
43
43
  Brakeman.debug "Finding possible SQL calls on models"
44
44
  calls = tracker.find_call(:methods => @sql_targets, :nested => true)
@@ -53,6 +53,8 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
53
53
 
54
54
  calls.concat tracker.find_call(:targets => @expected_targets, :methods => @connection_calls, :chained => true).select { |result| connect_call? result }
55
55
 
56
+ calls.concat tracker.find_call(:target => :Arel, :method => :sql)
57
+
56
58
  Brakeman.debug "Finding calls to named_scope or scope"
57
59
  calls.concat find_scope_calls
58
60
 
@@ -194,6 +196,8 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
194
196
  check_lock_arguments call.first_arg
195
197
  when :pluck
196
198
  unsafe_sql? call.first_arg
199
+ when :sql
200
+ unsafe_sql? call.first_arg
197
201
  when :update_all, :select
198
202
  check_update_all_arguments call.args
199
203
  when *@connection_calls
@@ -0,0 +1,97 @@
1
+ require 'pathname'
2
+
3
+ module Brakeman
4
+ module Codeclimate
5
+ class EngineConfiguration
6
+
7
+ def initialize(engine_config = {})
8
+ @engine_config = engine_config
9
+ end
10
+
11
+ def options
12
+ default_options.merge(configured_options)
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :engine_config
18
+
19
+ def default_options
20
+ @default_options = {
21
+ :output_format => :codeclimate,
22
+ :quiet => true,
23
+ :pager => false,
24
+ :app_path => Dir.pwd
25
+ }
26
+ if system("test -w /dev/stdout")
27
+ @default_options[:output_files] = ["/dev/stdout"]
28
+ end
29
+ @default_options
30
+ end
31
+
32
+ def configured_options
33
+ @configured_options = {}
34
+ # ATM this gets parsed as a string instead of bool: "config":{ "debug":"true" }
35
+ if brakeman_configuration["debug"] && brakeman_configuration["debug"].to_s.downcase == "true"
36
+ @configured_options[:debug] = true
37
+ @configured_options[:report_progress] = false
38
+ end
39
+
40
+ if active_include_paths
41
+ @configured_options[:only_files] = active_include_paths
42
+ end
43
+
44
+ if brakeman_configuration["app_path"]
45
+ @configured_options[:path_prefix] = brakeman_configuration["app_path"]
46
+ path = Pathname.new(Dir.pwd) + brakeman_configuration["app_path"]
47
+ @configured_options[:app_path] = path.to_s
48
+ end
49
+ @configured_options
50
+ end
51
+
52
+ def brakeman_configuration
53
+ if engine_config["config"]
54
+ engine_config["config"]
55
+ else
56
+ {}
57
+ end
58
+ end
59
+
60
+ def active_include_paths
61
+ @active_include_paths ||=
62
+ if brakeman_configuration["app_path"]
63
+ stripped_include_paths(brakeman_configuration["app_path"])
64
+ else
65
+ engine_config["include_paths"] && engine_config["include_paths"].compact
66
+ end
67
+ end
68
+
69
+ def stripped_include_paths(prefix)
70
+ subprefixes = path_subprefixes(prefix)
71
+ engine_config["include_paths"] && engine_config["include_paths"].map do |path|
72
+ next unless path
73
+ stripped_include_path(prefix, subprefixes, path)
74
+ end.compact
75
+ end
76
+
77
+ def path_subprefixes(path)
78
+ Pathname.new(path).each_filename.inject([]) do |memo, piece|
79
+ memo <<
80
+ if memo.any?
81
+ File.join(memo.last, piece)
82
+ else
83
+ File.join(piece)
84
+ end
85
+ end
86
+ end
87
+
88
+ def stripped_include_path(prefix, subprefixes, path)
89
+ if path.start_with?(prefix)
90
+ path.sub(%r{^#{prefix}/?}, "./")
91
+ elsif subprefixes.any? { |subprefix| path =~ %r{^#{subprefix}/?$} }
92
+ "./"
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -36,9 +36,7 @@ module Brakeman
36
36
  @file_parser.file_list[:templates] << TemplateFile.new(path, ast, name, type)
37
37
  end
38
38
  rescue Racc::ParseError => e
39
- tracker.error e, "could not parse #{path}"
40
- rescue Haml::Error => e
41
- tracker.error e, ["While compiling HAML in #{path}"] << e.backtrace
39
+ tracker.error e, "Could not parse #{path}"
42
40
  rescue StandardError, LoadError => e
43
41
  tracker.error e.exception(e.message + "\nWhile processing #{path}"), e.backtrace
44
42
  end
@@ -78,6 +76,12 @@ module Brakeman
78
76
  Haml::Engine.new(text,
79
77
  :filename => path,
80
78
  :escape_html => tracker.config.escape_html?).precompiled.gsub(/([^\\])\\n/, '\1')
79
+ rescue Haml::Error => e
80
+ tracker.error e, ["While compiling HAML in #{path}"] << e.backtrace
81
+ nil
82
+ rescue Sass::SyntaxError => e
83
+ tracker.error e, "While processing #{path}"
84
+ nil
81
85
  end
82
86
 
83
87
  def parse_slim path, text
@@ -54,7 +54,7 @@ module Brakeman
54
54
  #Process a model source
55
55
  def process_model src, file_name
56
56
  result = ModelProcessor.new(@tracker).process_model src, file_name
57
- AliasProcessor.new(@tracker).process_all result if result
57
+ AliasProcessor.new(@tracker).process result if result
58
58
  end
59
59
 
60
60
  #Process either an ERB or HAML template
@@ -235,14 +235,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
235
235
  end
236
236
  when :/
237
237
  if number? target and number? first_arg
238
- if first_arg.value == 0 and not target.value.is_a? Float
239
- if @tracker
240
- location = [@current_class, @current_method, "line #{first_arg.line}"].compact.join(' ')
241
- require 'brakeman/processors/output_processor'
242
- code = Brakeman::OutputProcessor.new.format(exp)
243
- @tracker.error Exception.new("Potential divide by zero: #{code} (#{location})")
244
- end
245
- else
238
+ unless first_arg.value == 0 and not target.value.is_a? Float
246
239
  exp = Sexp.new(:lit, target.value / first_arg.value)
247
240
  end
248
241
  end
@@ -500,6 +493,12 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
500
493
  #
501
494
  # x, y = z, w
502
495
  def process_masgn exp
496
+ exp[2] = process exp[2] if sexp? exp[2]
497
+
498
+ if node_type? exp[2], :to_ary and array? exp[2][1]
499
+ exp[2] = exp[2][1]
500
+ end
501
+
503
502
  unless array? exp[1] and array? exp[2] and exp[1].length == exp[2].length
504
503
  return process_default(exp)
505
504
  end
@@ -514,9 +513,20 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
514
513
  vars.each_with_index do |var, i|
515
514
  val = vals[i]
516
515
  if val
517
- assign = var.dup
518
- assign.rhs = val
519
- process assign
516
+
517
+ # This happens with nested destructuring like
518
+ # x, (a, b) = blah
519
+ if node_type? var, :masgn
520
+ # Need to add value to masgn exp
521
+ m = var.dup
522
+ m[2] = s(:to_ary, val)
523
+
524
+ process_masgn m
525
+ else
526
+ assign = var.dup
527
+ assign.rhs = val
528
+ process assign
529
+ end
520
530
  end
521
531
  end
522
532
 
@@ -550,19 +560,26 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
550
560
  #Assignments like this
551
561
  # x[:y] ||= 1
552
562
  def process_op_asgn1 exp
553
- return process_default(exp) if exp[3] != :"||"
563
+ target_var = exp[1]
564
+ target_var &&= target_var.deep_clone
554
565
 
555
566
  target = exp[1] = process(exp[1])
556
567
  index = exp[2][1] = process(exp[2][1])
557
568
  value = exp[4] = process(exp[4])
558
569
  match = Sexp.new(:call, target, :[], index)
559
570
 
560
- unless env[match]
561
- if request_value? target
562
- env[match] = match.combine(value)
563
- else
564
- env[match] = value
571
+ if exp[3] == :"||"
572
+ unless env[match]
573
+ if request_value? target
574
+ env[match] = match.combine(value)
575
+ else
576
+ env[match] = value
577
+ end
565
578
  end
579
+ else
580
+ new_value = process s(:call, s(:call, target_var, :[], index), exp[3], value)
581
+
582
+ env[match] = new_value
566
583
  end
567
584
 
568
585
  exp
@@ -0,0 +1,110 @@
1
+ module Brakeman
2
+ class Pager
3
+ def initialize tracker, pager = :less, output = $stdout
4
+ @tracker = tracker
5
+ @pager = pager
6
+ @output = output
7
+ end
8
+
9
+ def page_report report, format
10
+ if @pager == :less
11
+ set_color
12
+ end
13
+
14
+ text = report.format(format)
15
+
16
+ if in_ci?
17
+ no_pager text
18
+ else
19
+ page_output text
20
+ end
21
+ end
22
+
23
+ def page_output text
24
+ case @pager
25
+ when :none
26
+ no_pager text
27
+ when :highline
28
+ page_via_highline text
29
+ when :less
30
+ if less_available?
31
+ page_via_less text
32
+ else
33
+ page_via_highline text
34
+ end
35
+ else
36
+ no_pager text
37
+ end
38
+ end
39
+
40
+ def no_pager text
41
+ @output.puts text
42
+ end
43
+
44
+ def page_via_highline text
45
+ Brakeman.load_brakeman_dependency 'highline'
46
+ h = ::HighLine.new($stdin, @output)
47
+ h.page_at = :auto
48
+ h.say text
49
+ end
50
+
51
+ def page_via_less text
52
+ # Adapted from https://github.com/piotrmurach/tty-pager/
53
+
54
+ write_io = open("|less #{less_options.join}", 'w')
55
+ pid = write_io.pid
56
+
57
+ write_io.write(text)
58
+ write_io.close
59
+
60
+ Process.waitpid2(pid, Process::WNOHANG)
61
+ rescue Errno::ECHILD
62
+ # on jruby 9x waiting on pid raises (per tty-pager)
63
+ true
64
+ rescue => e
65
+ warn "[Error] #{e}"
66
+ warn "[Error] Could not use pager. Set --no-pager to avoid this issue."
67
+ no_pager text
68
+ end
69
+
70
+ def in_ci?
71
+ ci = ENV["CI"]
72
+
73
+ ci.is_a? String and ci.downcase == "true"
74
+ end
75
+
76
+ def less_available?
77
+ return @less_available unless @less_available.nil?
78
+
79
+ @less_available = system("which less > /dev/null")
80
+ end
81
+
82
+ def less_options
83
+ # -R show colors
84
+ # -F exit if output fits on one screen
85
+ # -X do not clear screen after less exits
86
+
87
+ return @less_options if @less_options
88
+
89
+ @less_options = []
90
+
91
+ if system("which less > /dev/null")
92
+ less_help = `less -?`
93
+
94
+ ["-R ", "-F ", "-X "].each do |opt|
95
+ if less_help.include? opt
96
+ @less_options << opt
97
+ end
98
+ end
99
+ end
100
+
101
+ @less_options
102
+ end
103
+
104
+ def set_color
105
+ unless @tracker and less_options.include? "-R "
106
+ @tracker.options[:output_color] = false
107
+ end
108
+ end
109
+ end
110
+ end
@@ -1,5 +1,6 @@
1
1
  require "json"
2
2
  require "yaml"
3
+ require "pathname"
3
4
 
4
5
  class Brakeman::Report::CodeClimate < Brakeman::Report::Base
5
6
  DOCUMENTATION_PATH = File.expand_path("../../../../docs/warning_types", __FILE__)
@@ -24,7 +25,7 @@ class Brakeman::Report::CodeClimate < Brakeman::Report::Base
24
25
  severity: severity_level_for(warning.confidence),
25
26
  remediation_points: remediation_points_for(warning_code_name),
26
27
  location: {
27
- path: warning.relative_path,
28
+ path: file_path(warning),
28
29
  lines: {
29
30
  begin: warning.line || 1,
30
31
  end: warning.line || 1,
@@ -67,4 +68,12 @@ class Brakeman::Report::CodeClimate < Brakeman::Report::Base
67
68
 
68
69
  File.read(filename) if File.exist?(filename)
69
70
  end
71
+
72
+ def file_path(warning)
73
+ fp = Pathname.new(warning.relative_path)
74
+ if tracker.options[:path_prefix]
75
+ fp = Pathname.new(tracker.options[:path_prefix]) + fp
76
+ end
77
+ fp.to_s
78
+ end
70
79
  end
@@ -24,6 +24,20 @@ module Brakeman
24
24
  @rails[:action_controller][:allow_forgery_protection] == Sexp.new(:false)
25
25
  end
26
26
 
27
+ def default_protect_from_forgery?
28
+ if version_between? "5.2.0", "9.9.9"
29
+ if @rails[:action_controller] and
30
+ @rails[:action_controller][:default_protect_from_forgery] == Sexp.new(:false)
31
+
32
+ return false
33
+ else
34
+ return true
35
+ end
36
+ end
37
+
38
+ false
39
+ end
40
+
27
41
  def erubis?
28
42
  @erubis
29
43
  end
@@ -101,6 +115,36 @@ module Brakeman
101
115
  end
102
116
  end
103
117
 
118
+ #Returns true if low_version <= RAILS_VERSION <= high_version
119
+ #
120
+ #If the Rails version is unknown, returns false.
121
+ def version_between? low_version, high_version, current_version = nil
122
+ current_version ||= rails_version
123
+ return false unless current_version
124
+
125
+ version = current_version.split(".").map!(&:to_i)
126
+ low_version = low_version.split(".").map!(&:to_i)
127
+ high_version = high_version.split(".").map!(&:to_i)
128
+
129
+ version.each_with_index do |v, i|
130
+ if v < low_version.fetch(i, 0)
131
+ return false
132
+ elsif v > low_version.fetch(i, 0)
133
+ break
134
+ end
135
+ end
136
+
137
+ version.each_with_index do |v, i|
138
+ if v > high_version.fetch(i, 0)
139
+ return false
140
+ elsif v < high_version.fetch(i, 0)
141
+ break
142
+ end
143
+ end
144
+
145
+ true
146
+ end
147
+
104
148
  def session_settings
105
149
  @rails[:action_controller] &&
106
150
  @rails[:action_controller][:session]
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "4.0.1"
2
+ Version = "4.1.0"
3
3
  end
@@ -196,11 +196,11 @@ class Brakeman::Warning
196
196
  if @link_path.start_with? "http"
197
197
  @link = @link_path
198
198
  else
199
- @link = "http://brakemanscanner.org/docs/warning_types/#{@link_path}"
199
+ @link = "https://brakemanscanner.org/docs/warning_types/#{@link_path}"
200
200
  end
201
201
  else
202
202
  warning_path = self.warning_type.to_s.downcase.gsub(/\s+/, '_') + "/"
203
- @link = "http://brakemanscanner.org/docs/warning_types/#{warning_path}"
203
+ @link = "https://brakemanscanner.org/docs/warning_types/#{warning_path}"
204
204
  end
205
205
 
206
206
  @link
@@ -105,6 +105,8 @@ module Brakeman::WarningCodes
105
105
  :secret_in_source => 101,
106
106
  :CVE_2016_6316 => 102,
107
107
  :CVE_2016_6317 => 103,
108
+ :divide_by_zero => 104,
109
+ :dangerous_permit_key => 105,
108
110
  }
109
111
 
110
112
  def self.code name
@@ -4,6 +4,7 @@
4
4
  class Sexp
5
5
  attr_accessor :original_line, :or_depth
6
6
  ASSIGNMENT_BOOL = [:gasgn, :iasgn, :lasgn, :cvdecl, :cvasgn, :cdecl, :or, :and, :colon2, :op_asgn_or]
7
+ CALLS = [:call, :attrasgn, :safe_call, :safe_attrasgn]
7
8
 
8
9
  def method_missing name, *args
9
10
  #Brakeman does not use this functionality,
@@ -307,6 +308,21 @@ class Sexp
307
308
  end
308
309
  end
309
310
 
311
+ def call_chain
312
+ expect :call, :attrasgn, :safe_call, :safe_attrasgn
313
+
314
+ chain = []
315
+ call = self
316
+
317
+ while call.class == Sexp and CALLS.include? call.first
318
+ chain << call.method
319
+ call = call.target
320
+ end
321
+
322
+ chain.reverse!
323
+ chain
324
+ end
325
+
310
326
  #Returns condition of an if expression:
311
327
  #
312
328
  # 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: 4.0.1
4
+ version: 4.1.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: 2017-09-25 00:00:00.000000000 Z
12
+ date: 2017-12-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -90,7 +90,7 @@ executables:
90
90
  extensions: []
91
91
  extra_rdoc_files: []
92
92
  files:
93
- - CHANGES
93
+ - CHANGES.md
94
94
  - FEATURES
95
95
  - README.md
96
96
  - bin/brakeman
@@ -108,6 +108,7 @@ files:
108
108
  - lib/brakeman/checks/check_deserialize.rb
109
109
  - lib/brakeman/checks/check_detailed_exceptions.rb
110
110
  - lib/brakeman/checks/check_digest_dos.rb
111
+ - lib/brakeman/checks/check_divide_by_zero.rb
111
112
  - lib/brakeman/checks/check_dynamic_finders.rb
112
113
  - lib/brakeman/checks/check_escape_function.rb
113
114
  - lib/brakeman/checks/check_evaluation.rb
@@ -132,6 +133,7 @@ files:
132
133
  - lib/brakeman/checks/check_nested_attributes.rb
133
134
  - lib/brakeman/checks/check_nested_attributes_bypass.rb
134
135
  - lib/brakeman/checks/check_number_to_currency.rb
136
+ - lib/brakeman/checks/check_permit_attributes.rb
135
137
  - lib/brakeman/checks/check_quote_table_name.rb
136
138
  - lib/brakeman/checks/check_redirect.rb
137
139
  - lib/brakeman/checks/check_regex_dos.rb
@@ -166,6 +168,7 @@ files:
166
168
  - lib/brakeman/checks/check_without_protection.rb
167
169
  - lib/brakeman/checks/check_xml_dos.rb
168
170
  - lib/brakeman/checks/check_yaml_parsing.rb
171
+ - lib/brakeman/codeclimate/engine_configuration.rb
169
172
  - lib/brakeman/commandline.rb
170
173
  - lib/brakeman/differ.rb
171
174
  - lib/brakeman/file_parser.rb
@@ -210,6 +213,7 @@ files:
210
213
  - lib/brakeman/report/config/remediation.yml
211
214
  - lib/brakeman/report/ignore/config.rb
212
215
  - lib/brakeman/report/ignore/interactive.rb
216
+ - lib/brakeman/report/pager.rb
213
217
  - lib/brakeman/report/renderer.rb
214
218
  - lib/brakeman/report/report_base.rb
215
219
  - lib/brakeman/report/report_codeclimate.rb