brakeman 2.4.3 → 2.5.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.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NzVjZjYxZWMzOTRhYzI0YTA0M2ZlYjkxNDQyZjFkZTNlYzYxZTk4ZA==
5
+ data.tar.gz: !binary |-
6
+ MjY3ZGNkNGJkYzZlOWJmNjI2MGVkMmYxNDMzMDVkOTBkMzZlN2JkYg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ YzZiNTlkMmU2OGRjOTdiZDA1ZWFhMmEwNzUyNzcwMmI5ZmNmOTRmOGRjMjc2
10
+ NTkzZTZmOTc0MzIyYTRjN2Y2ZDBjZjJiZDJlNmQ3NDhlM2E5YTZjNTA2ZDI1
11
+ MGM2NjNkY2YxYjNhZTVmNWJjZDZmNmE4ZGViNGJkNjc2ODdlNWU=
12
+ data.tar.gz: !binary |-
13
+ MTY0ZjY2ZjIyM2VkMTUxYWNhZjFiOGI0YTAzNTUzODhjZTI5MjMyNmNkNGE5
14
+ MTI1ZmM2MGIwMTg3ZjJkNmFjZjY3Zjk5NzNlNTQzNjk2NTc1ZmNhNDU3Nzhl
15
+ NmI1NTBkZDAwNjkzNjFiMGRiMzg0ODRmMjA4MGZlN2VhOGEyM2I=
Binary file
data.tar.gz.sig CHANGED
Binary file
data/CHANGES CHANGED
@@ -1,3 +1,18 @@
1
+ # 2.5.0
2
+
3
+ * Add support for RailsLTS 2.3.18.7 and 2.3.18.8
4
+ * Add support for Rails 4 `before_actions` and friends
5
+ * Move SQLi CVE checks to `CheckSQLCVEs`
6
+ * Check for protected_attributes gem
7
+ * Fix SQLi detection in chain calls in scopes
8
+ * Add GitHub-flavored Markdown output format (Greg Ose)
9
+ * Fix false positives when sanitize() is used in SQL (Jeff Yip)
10
+ * Add String#intern and Hash#symbolize_keys DoS check (Jan Rusnacko)
11
+ * Check all arguments in Model.select for SQLi
12
+ * Fix false positive when :host is specified in redirect
13
+ * Handle more non-literals in routes
14
+ * Add check for regex denial of service (Ben Toews)
15
+
1
16
  # 2.4.3
2
17
 
3
18
  No changes. 2.4.2 gem release was unsigned, 2.4.3 is signed.
@@ -24,6 +24,7 @@ module Brakeman
24
24
  # * :config_file - configuration file
25
25
  # * :escape_html - escape HTML by default (automatic)
26
26
  # * :exit_on_warn - return false if warnings found, true otherwise. Not recommended for library use (default: false)
27
+ # * :github_repo - github repo to use for file links (user/repo[/path][@ref])
27
28
  # * :highlight_user_input - highlight user input in reported warnings (default: true)
28
29
  # * :html_style - path to CSS file
29
30
  # * :ignore_model_output - consider models safe (default: false)
@@ -77,6 +78,7 @@ module Brakeman
77
78
 
78
79
  options[:app_path] = File.expand_path(options[:app_path])
79
80
  options[:output_formats] = get_output_formats options
81
+ options[:github_url] = get_github_url options
80
82
 
81
83
  options
82
84
  end
@@ -166,6 +168,8 @@ module Brakeman
166
168
  [:to_tabs]
167
169
  when :json, :to_json
168
170
  [:to_json]
171
+ when :markdown, :to_markdown
172
+ [:to_markdown]
169
173
  else
170
174
  [:to_s]
171
175
  end
@@ -185,6 +189,8 @@ module Brakeman
185
189
  :to_tabs
186
190
  when /\.json$/i
187
191
  :to_json
192
+ when /\.md$/i
193
+ :to_markdown
188
194
  else
189
195
  :to_s
190
196
  end
@@ -192,6 +198,22 @@ module Brakeman
192
198
  end
193
199
  private_class_method :get_formats_from_output_files
194
200
 
201
+ def self.get_github_url options
202
+ if github_repo = options[:github_repo]
203
+ full_repo, ref = github_repo.split '@', 2
204
+ name, repo, path = full_repo.split '/', 3
205
+ unless name && repo && !(name.empty? || repo.empty?)
206
+ raise ArgumentError, "Invalid GitHub repository format"
207
+ end
208
+ path.chomp '/' if path
209
+ ref ||= 'master'
210
+ ['https://github.com', name, repo, 'blob', ref, path].compact.join '/'
211
+ else
212
+ nil
213
+ end
214
+ end
215
+ private_class_method :get_github_url
216
+
195
217
  #Output list of checks (for `-k` option)
196
218
  def self.list_checks
197
219
  require 'brakeman/scanner'
@@ -177,7 +177,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
177
177
  tracker.config[:rails][:active_record][:whitelist_attributes] == Sexp.new(:true)
178
178
 
179
179
  @mass_assign_disabled = true
180
- elsif version_between?("4.0.0", "4.9.9")
180
+ elsif version_between?("4.0.0", "4.9.9") and not tracker.config[:gems][:protected_attributes]
181
181
  #May need to revisit dependng on what Rails 4 actually does/has
182
182
  @mass_assign_disabled = true
183
183
  else
@@ -10,6 +10,8 @@ class Brakeman::CheckNumberToCurrency < Brakeman::BaseCheck
10
10
  version_between? "3.0.0", "3.2.16" or
11
11
  version_between? "4.0.0", "4.0.2"
12
12
 
13
+ return if lts_version? "2.3.18.8"
14
+
13
15
  check_number_helper_usage
14
16
  generic_warning unless @found_any
15
17
  end
@@ -31,7 +31,11 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
31
31
 
32
32
  method = call.method
33
33
 
34
- if method == :redirect_to and not only_path?(call) and res = include_user_input?(call)
34
+ if method == :redirect_to and
35
+ not only_path?(call) and
36
+ not explicit_host?(call) and
37
+ res = include_user_input?(call)
38
+
35
39
  add_result result
36
40
 
37
41
  if res.type == :immediate
@@ -109,6 +113,16 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
109
113
  false
110
114
  end
111
115
 
116
+ def explicit_host? call
117
+ arg = call.first_arg
118
+
119
+ if hash? arg and value = hash_access(arg, :host)
120
+ return !has_immediate_user_input?(value)
121
+ end
122
+
123
+ false
124
+ end
125
+
112
126
  #+url_for+ is only_path => true by default. This checks to see if it is
113
127
  #set to false for some reason.
114
128
  def check_url_for call
@@ -0,0 +1,69 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ #This check looks for regexes that include user input.
4
+ class Brakeman::CheckRegexDoS < Brakeman::BaseCheck
5
+ Brakeman::Checks.add self
6
+
7
+ ESCAPES = {
8
+ s(:const, :Regexp) => [
9
+ :escape,
10
+ :quote
11
+ ]
12
+ }
13
+
14
+ @description = "Searches regexes including user input"
15
+
16
+ #Process calls
17
+ def run_check
18
+ Brakeman.debug "Finding dynamic regexes"
19
+ calls = tracker.find_call :method => [:brakeman_regex_interp]
20
+
21
+ Brakeman.debug "Processing dynamic regexes"
22
+ calls.each do |call|
23
+ process_result call
24
+ end
25
+ end
26
+
27
+ #Warns if regex includes user input
28
+ def process_result result
29
+ return if duplicate? result
30
+ add_result result
31
+
32
+ call = result[:call]
33
+ components = call[1..-1]
34
+
35
+ components.any? do |component|
36
+ next unless sexp? component
37
+
38
+ if match = has_immediate_user_input?(component)
39
+ confidence = CONFIDENCE[:high]
40
+ elsif match = has_immediate_model?(component)
41
+ match = Match.new(:model, match)
42
+ confidence = CONFIDENCE[:med]
43
+ elsif match = include_user_input?(component)
44
+ confidence = CONFIDENCE[:low]
45
+ end
46
+
47
+ if match
48
+ message = "#{friendly_type_of(match).capitalize} used in regex"
49
+
50
+ warn :result => result,
51
+ :warning_type => "Denial of Service",
52
+ :warning_code => :regex_dos,
53
+ :message => message,
54
+ :confidence => confidence,
55
+ :user_input => match.match
56
+ end
57
+ end
58
+ end
59
+
60
+ def process_call(exp)
61
+ if escape_methods = ESCAPES[exp.target]
62
+ if escape_methods.include? exp.method
63
+ return exp
64
+ end
65
+ end
66
+
67
+ super
68
+ end
69
+ end
@@ -9,7 +9,9 @@ class Brakeman::CheckSelectVulnerability < Brakeman::BaseCheck
9
9
 
10
10
  def run_check
11
11
 
12
- if version_between? "3.0.0", "3.0.11"
12
+ if lts_version? "2.3.18.7"
13
+ return
14
+ elsif version_between? "3.0.0", "3.0.11"
13
15
  suggested_version = "3.0.12"
14
16
  elsif version_between? "3.1.0", "3.1.3"
15
17
  suggested_version = "3.1.4"
@@ -14,7 +14,7 @@ class Brakeman::CheckSkipBeforeFilter < Brakeman::BaseCheck
14
14
 
15
15
  def run_check
16
16
  tracker.controllers.each do |name, controller|
17
- filter_skips = (controller[:options][:skip_before_filter] || []) + (controller[:options][:skip_filter] || [])
17
+ filter_skips = controller[:options].values_at(:skip_before_filter, :skip_filter, :skip_before_action, :skip_action_callback).compact.flatten(1)
18
18
 
19
19
  filter_skips.each do |filter|
20
20
  process_skip_filter filter, controller
@@ -46,13 +46,8 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
46
46
  Brakeman.debug "Finding calls to named_scope or scope"
47
47
  calls.concat find_scope_calls
48
48
 
49
- Brakeman.debug "Checking version of Rails for CVE issues"
50
- check_rails_versions_against_cve_issues
51
-
52
49
  Brakeman.debug "Processing possible SQL calls"
53
50
  calls.each { |call| process_result call }
54
-
55
- check_CVE_2014_0080
56
51
  end
57
52
 
58
53
  #Find calls to named_scope() or scope() in models
@@ -65,7 +60,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
65
60
  call = make_call(nil, :named_scope, args).line(args.line)
66
61
  scope_calls << scope_call_hash(call, name, :named_scope)
67
62
  end
68
- elsif version_between?("3.1.0", "3.9.9")
63
+ elsif version_between?("3.1.0", "4.9.9")
69
64
  ar_scope_calls(:scope) do |name, args|
70
65
  second_arg = args[2]
71
66
  next unless sexp? second_arg
@@ -114,8 +109,12 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
114
109
  find_calls.process_source(block, :class => model_name, :method => scope_name)
115
110
  find_calls.calls.each { |call| process_result(call) if @sql_targets.include?(call[:method]) }
116
111
  elsif block.node_type == :call
117
- process_result :target => block.target, :method => block.method, :call => block,
118
- :location => { :type => :class, :class => model_name, :method => scope_name }
112
+ while call? block
113
+ process_result :target => block.target, :method => block.method, :call => block,
114
+ :location => { :type => :class, :class => model_name, :method => scope_name }
115
+
116
+ block = block.target
117
+ end
119
118
  end
120
119
  end
121
120
 
@@ -179,13 +178,13 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
179
178
  check_order_arguments call.arglist
180
179
  when :joins
181
180
  check_joins_arguments call.first_arg
182
- when :from, :select
181
+ when :from
183
182
  unsafe_sql? call.first_arg
184
183
  when :lock
185
184
  check_lock_arguments call.first_arg
186
185
  when :pluck
187
186
  unsafe_sql? call.first_arg
188
- when :update_all
187
+ when :update_all, :select
189
188
  check_update_all_arguments call.args
190
189
  when *@connection_calls
191
190
  check_by_sql_arguments call.first_arg
@@ -540,7 +539,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
540
539
  :sanitize_sql, :sanitize_sql_array, :sanitize_sql_for_assignment,
541
540
  :sanitize_sql_for_conditions, :sanitize_sql_hash,
542
541
  :sanitize_sql_hash_for_assignment, :sanitize_sql_hash_for_conditions,
543
- :to_sql]
542
+ :to_sql, :sanitize]
544
543
 
545
544
  def safe_value? exp
546
545
  return true unless sexp? exp
@@ -639,82 +638,4 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
639
638
  active_record_models.include? klass
640
639
  end
641
640
  end
642
-
643
- # TODO: Move all SQL CVE checks to separate class
644
- def check_CVE_2014_0080
645
- return unless version_between? "4.0.0", "4.0.2" and
646
- @tracker.config[:gems].include? :pg
647
-
648
- warn :warning_type => 'SQL Injection',
649
- :warning_code => :CVE_2014_0080,
650
- :message => "Rails #{tracker.config[:rails_version]} contains a SQL injection vulnerability (CVE-2014-0080) with PostgreSQL. Upgrade to 4.0.3",
651
- :confidence => CONFIDENCE[:high],
652
- :file => gemfile_or_environment,
653
- :link_path => "https://groups.google.com/d/msg/rubyonrails-security/Wu96YkTUR6s/pPLBMZrlwvYJ"
654
- end
655
-
656
- def upgrade_version? versions
657
- versions.each do |low, high, upgrade|
658
- return upgrade if version_between? low, high
659
- end
660
-
661
- false
662
- end
663
-
664
- def check_rails_versions_against_cve_issues
665
- issues = [
666
- {
667
- :cve => "CVE-2012-2660",
668
- :versions => [%w[2.0.0 2.3.14 2.3.17], %w[3.0.0 3.0.12 3.0.13], %w[3.1.0 3.1.4 3.1.5], %w[3.2.0 3.2.3 3.2.4]],
669
- :url => "https://groups.google.com/d/topic/rubyonrails-security/8SA-M3as7A8/discussion"
670
- },
671
- {
672
- :cve => "CVE-2012-2661",
673
- :versions => [%w[3.0.0 3.0.12 3.0.13], %w[3.1.0 3.1.4 3.1.5], %w[3.2.0 3.2.3 3.2.5]],
674
- :url => "https://groups.google.com/d/topic/rubyonrails-security/dUaiOOGWL1k/discussion"
675
- },
676
- {
677
- :cve => "CVE-2012-2695",
678
- :versions => [%w[2.0.0 2.3.14 2.3.15], %w[3.0.0 3.0.13 3.0.14], %w[3.1.0 3.1.5 3.1.6], %w[3.2.0 3.2.5 3.2.6]],
679
- :url => "https://groups.google.com/d/topic/rubyonrails-security/l4L0TEVAz1k/discussion"
680
- },
681
- {
682
- :cve => "CVE-2012-5664",
683
- :versions => [%w[2.0.0 2.3.14 2.3.15], %w[3.0.0 3.0.17 3.0.18], %w[3.1.0 3.1.8 3.1.9], %w[3.2.0 3.2.9 3.2.18]],
684
- :url => "https://groups.google.com/d/topic/rubyonrails-security/DCNTNp_qjFM/discussion"
685
- },
686
- {
687
- :cve => "CVE-2013-0155",
688
- :versions => [%w[2.0.0 2.3.15 2.3.16], %w[3.0.0 3.0.18 3.0.19], %w[3.1.0 3.1.9 3.1.10], %w[3.2.0 3.2.10 3.2.11]],
689
- :url => "https://groups.google.com/d/topic/rubyonrails-security/c7jT-EeN9eI/discussion"
690
- },
691
-
692
- ]
693
-
694
- unless lts_version? '2.3.18.6'
695
- issues << {
696
- :cve => "CVE-2013-6417",
697
- :versions => [%w[2.0.0 3.2.15 3.2.16], %w[4.0.0 4.0.1 4.0.2]],
698
- :url => "https://groups.google.com/d/msg/ruby-security-ann/niK4drpSHT4/g8JW8ZsayRkJ"
699
- }
700
- end
701
-
702
- issues.each do |cve_issue|
703
- cve_warning_for cve_issue[:versions], cve_issue[:cve], cve_issue[:url]
704
- end
705
- end
706
-
707
- def cve_warning_for versions, cve, link
708
- upgrade_version = upgrade_version? versions
709
- return unless upgrade_version
710
-
711
- code = cve.tr('-', '_').to_sym
712
-
713
- warn :warning_type => 'SQL Injection',
714
- :warning_code => code,
715
- :message => "Rails #{tracker.config[:rails_version]} contains a SQL injection vulnerability (#{cve}). Upgrade to #{upgrade_version}",
716
- :confidence => CONFIDENCE[:high],
717
- :file => gemfile_or_environment,
718
- :link_path => link
719
- end
720
641
  end
@@ -0,0 +1,89 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckSQLCVEs < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Checks for several SQL CVEs"
7
+
8
+ def run_check
9
+ check_rails_versions_against_cve_issues
10
+ check_cve_2014_0080
11
+ end
12
+
13
+ def check_rails_versions_against_cve_issues
14
+ issues = [
15
+ {
16
+ :cve => "CVE-2012-2660",
17
+ :versions => [%w[2.0.0 2.3.14 2.3.17], %w[3.0.0 3.0.12 3.0.13], %w[3.1.0 3.1.4 3.1.5], %w[3.2.0 3.2.3 3.2.4]],
18
+ :url => "https://groups.google.com/d/topic/rubyonrails-security/8SA-M3as7A8/discussion"
19
+ },
20
+ {
21
+ :cve => "CVE-2012-2661",
22
+ :versions => [%w[3.0.0 3.0.12 3.0.13], %w[3.1.0 3.1.4 3.1.5], %w[3.2.0 3.2.3 3.2.5]],
23
+ :url => "https://groups.google.com/d/topic/rubyonrails-security/dUaiOOGWL1k/discussion"
24
+ },
25
+ {
26
+ :cve => "CVE-2012-2695",
27
+ :versions => [%w[2.0.0 2.3.14 2.3.15], %w[3.0.0 3.0.13 3.0.14], %w[3.1.0 3.1.5 3.1.6], %w[3.2.0 3.2.5 3.2.6]],
28
+ :url => "https://groups.google.com/d/topic/rubyonrails-security/l4L0TEVAz1k/discussion"
29
+ },
30
+ {
31
+ :cve => "CVE-2012-5664",
32
+ :versions => [%w[2.0.0 2.3.14 2.3.15], %w[3.0.0 3.0.17 3.0.18], %w[3.1.0 3.1.8 3.1.9], %w[3.2.0 3.2.9 3.2.18]],
33
+ :url => "https://groups.google.com/d/topic/rubyonrails-security/DCNTNp_qjFM/discussion"
34
+ },
35
+ {
36
+ :cve => "CVE-2013-0155",
37
+ :versions => [%w[2.0.0 2.3.15 2.3.16], %w[3.0.0 3.0.18 3.0.19], %w[3.1.0 3.1.9 3.1.10], %w[3.2.0 3.2.10 3.2.11]],
38
+ :url => "https://groups.google.com/d/topic/rubyonrails-security/c7jT-EeN9eI/discussion"
39
+ },
40
+
41
+ ]
42
+
43
+ unless lts_version? '2.3.18.6'
44
+ issues << {
45
+ :cve => "CVE-2013-6417",
46
+ :versions => [%w[2.0.0 3.2.15 3.2.16], %w[4.0.0 4.0.1 4.0.2]],
47
+ :url => "https://groups.google.com/d/msg/ruby-security-ann/niK4drpSHT4/g8JW8ZsayRkJ"
48
+ }
49
+ end
50
+
51
+ issues.each do |cve_issue|
52
+ cve_warning_for cve_issue[:versions], cve_issue[:cve], cve_issue[:url]
53
+ end
54
+ end
55
+
56
+ def cve_warning_for versions, cve, link
57
+ upgrade_version = upgrade_version? versions
58
+ return unless upgrade_version
59
+
60
+ code = cve.tr('-', '_').to_sym
61
+
62
+ warn :warning_type => 'SQL Injection',
63
+ :warning_code => code,
64
+ :message => "Rails #{tracker.config[:rails_version]} contains a SQL injection vulnerability (#{cve}). Upgrade to #{upgrade_version}",
65
+ :confidence => CONFIDENCE[:high],
66
+ :file => gemfile_or_environment,
67
+ :link_path => link
68
+ end
69
+
70
+ def upgrade_version? versions
71
+ versions.each do |low, high, upgrade|
72
+ return upgrade if version_between? low, high
73
+ end
74
+
75
+ false
76
+ end
77
+
78
+ def check_cve_2014_0080
79
+ return unless version_between? "4.0.0", "4.0.2" and
80
+ @tracker.config[:gems].include? :pg
81
+
82
+ warn :warning_type => 'SQL Injection',
83
+ :warning_code => :CVE_2014_0080,
84
+ :message => "Rails #{tracker.config[:rails_version]} contains a SQL injection vulnerability (CVE-2014-0080) with PostgreSQL. Upgrade to 4.0.3",
85
+ :confidence => CONFIDENCE[:high],
86
+ :file => gemfile_or_environment,
87
+ :link_path => "https://groups.google.com/d/msg/rubyonrails-security/Wu96YkTUR6s/pPLBMZrlwvYJ"
88
+ end
89
+ end