brakeman 2.4.3 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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