brakeman-lib 5.0.4 → 5.2.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.
- checksums.yaml +4 -4
- data/CHANGES.md +49 -1
- data/README.md +1 -1
- data/lib/brakeman/app_tree.rb +1 -1
- data/lib/brakeman/checks/base_check.rb +10 -0
- data/lib/brakeman/checks/check_detailed_exceptions.rb +1 -1
- data/lib/brakeman/checks/check_eol_rails.rb +23 -0
- data/lib/brakeman/checks/check_eol_ruby.rb +26 -0
- data/lib/brakeman/checks/check_evaluation.rb +1 -1
- data/lib/brakeman/checks/check_execute.rb +10 -0
- data/lib/brakeman/checks/check_json_parsing.rb +1 -1
- data/lib/brakeman/checks/check_render.rb +15 -1
- data/lib/brakeman/checks/check_sql.rb +58 -7
- data/lib/brakeman/checks/check_symbol_dos.rb +1 -1
- data/lib/brakeman/checks/check_verb_confusion.rb +1 -1
- data/lib/brakeman/checks/eol_check.rb +47 -0
- data/lib/brakeman/file_parser.rb +45 -15
- data/lib/brakeman/options.rb +15 -2
- data/lib/brakeman/processors/alias_processor.rb +91 -9
- data/lib/brakeman/processors/controller_alias_processor.rb +6 -43
- data/lib/brakeman/processors/gem_processor.rb +3 -0
- data/lib/brakeman/processors/haml_template_processor.rb +9 -0
- data/lib/brakeman/processors/lib/call_conversion_helper.rb +12 -6
- data/lib/brakeman/processors/lib/rails3_route_processor.rb +2 -0
- data/lib/brakeman/processors/library_processor.rb +9 -0
- data/lib/brakeman/processors/model_processor.rb +32 -0
- data/lib/brakeman/report/ignore/config.rb +1 -1
- data/lib/brakeman/report/ignore/interactive.rb +1 -1
- data/lib/brakeman/report/report_csv.rb +1 -1
- data/lib/brakeman/report/report_github.rb +31 -0
- data/lib/brakeman/report/report_sarif.rb +22 -3
- data/lib/brakeman/report/report_text.rb +1 -1
- data/lib/brakeman/report.rb +4 -1
- data/lib/brakeman/rescanner.rb +1 -1
- data/lib/brakeman/scanner.rb +19 -14
- data/lib/brakeman/tracker/collection.rb +57 -7
- data/lib/brakeman/tracker/config.rb +8 -1
- data/lib/brakeman/tracker/method_info.rb +70 -0
- data/lib/brakeman/tracker.rb +33 -4
- data/lib/brakeman/util.rb +34 -18
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning_codes.rb +2 -0
- data/lib/brakeman.rb +8 -2
- data/lib/ruby_parser/bm_sexp.rb +24 -0
- metadata +24 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cf18736db7a992849a30cccc66f741442e05b695f9ad1bd27fe06f6bc25db849
|
|
4
|
+
data.tar.gz: a884f20cc12305c0856bcc296ddae3aea746b024c232bf11d7988d4e37bd96a3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: be93f9f9ba9d808989cbed1bfd450b29c272e806d84707ab0420a8a86b8c797f88d4338f22a1124a462be43ac7bfea605566779321a72d772e9c39d216ded8c3
|
|
7
|
+
data.tar.gz: cf9aa7f34fa5cc737b2e7bbecf625025b50f72f1b3c43ab8f346832145e3cab2245d2af79fd021584ab0aa5fdbb2f854dd41fee8f5a5c891197f1f1e8a570a65
|
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,51 @@
|
|
|
1
|
+
# 5.2.0 - 2021-12-15
|
|
2
|
+
|
|
3
|
+
* Initial Rails 7 support
|
|
4
|
+
* Require Ruby 2.5.0+
|
|
5
|
+
* Fix issue with calls to `foo.root` in routes
|
|
6
|
+
* Ignore `I18n.locale` in SQL queries
|
|
7
|
+
* Do not treat `sanitize_sql_like` as safe
|
|
8
|
+
* Add new checks for unsupported Ruby and Rails versions
|
|
9
|
+
|
|
10
|
+
# 5.1.2 - 2021-10-28
|
|
11
|
+
|
|
12
|
+
* Handle cases where enums are not symbols
|
|
13
|
+
* Support newer Haml with ::Haml::AttributeBuilder.build
|
|
14
|
+
* Fix issue where the previous output is still visible (Jason Frey)
|
|
15
|
+
* Fix warning sorting with nil line numbers
|
|
16
|
+
* Update for latest RubyParser (Ryan Davis)
|
|
17
|
+
|
|
18
|
+
# 5.1.1 - 2021-07-19
|
|
19
|
+
|
|
20
|
+
* Unrefactor IgnoreConfig's use of `Brakeman::FilePath`
|
|
21
|
+
|
|
22
|
+
# 5.1.0 - 2021-07-19
|
|
23
|
+
|
|
24
|
+
* Initial support for ActiveRecord enums
|
|
25
|
+
* Support `Hash#include?`
|
|
26
|
+
* Interprocedural dataflow from very simple class methods
|
|
27
|
+
* Fix SARIF report when checks have no description (Eli Block)
|
|
28
|
+
* Add ignored warnings to SARIF report (Eli Block)
|
|
29
|
+
* Add `--sql-safe-methods` option (Esty Scheiner)
|
|
30
|
+
* Update SQL injection check for Rails 6.0/6.1
|
|
31
|
+
* Fix false positive in command injection with `Open3.capture` (Richard Fitzgerald)
|
|
32
|
+
* Fix infinite loop on mixin self-includes (Andrew Szczepanski)
|
|
33
|
+
* Ignore dates in SQL
|
|
34
|
+
* Refactor `cookie?`/`param?` methods (Keenan Brock)
|
|
35
|
+
* Ignore renderables in dynamic render path check (Brad Parker)
|
|
36
|
+
* Support `Array#push`
|
|
37
|
+
* Better `Array#join` support
|
|
38
|
+
* Adjust copy of `--interactive` menu (Elia Schito)
|
|
39
|
+
* Support `Array#*`
|
|
40
|
+
* Better method definition tracking and lookup
|
|
41
|
+
* Support `Hash#values` and `Hash#values_at`
|
|
42
|
+
* Check for user-controlled evaluation even if it's a call target
|
|
43
|
+
* Support `Array#fetch` and `Hash#fetch`
|
|
44
|
+
* Ignore `sanitize_sql_like` in SQL
|
|
45
|
+
* Ignore method calls on numbers in SQL
|
|
46
|
+
* Add GitHub Actions format (Klaus Badelt)
|
|
47
|
+
* Read and parse files in parallel
|
|
48
|
+
|
|
1
49
|
# 5.0.4 - 2021-06-08
|
|
2
50
|
|
|
3
51
|
(brakeman gem release only)
|
|
@@ -418,7 +466,7 @@
|
|
|
418
466
|
* Delay loading vendored gems and modifying load path
|
|
419
467
|
* Avoid warning about SQL injection with `quoted_primary_key`
|
|
420
468
|
* Support more safe `&.` operations
|
|
421
|
-
* Allow
|
|
469
|
+
* Allow multiple line regex in `validates_format_of` (Dmitrij Fedorenko)
|
|
422
470
|
* Only consider `if` branches in templates
|
|
423
471
|
* Avoid overwriting instance/class methods with same name (Tim Wade)
|
|
424
472
|
* Add `--force-scan` option (Neil Matatall)
|
data/README.md
CHANGED
|
@@ -66,7 +66,7 @@ Outside of Rails root (note that the output file is relative to path/to/rails/ap
|
|
|
66
66
|
|
|
67
67
|
Brakeman should work with any version of Rails from 2.3.x to 6.x.
|
|
68
68
|
|
|
69
|
-
Brakeman can analyze code written with Ruby 1.8 syntax and newer, but requires at least Ruby 2.
|
|
69
|
+
Brakeman can analyze code written with Ruby 1.8 syntax and newer, but requires at least Ruby 2.4.0 to run.
|
|
70
70
|
|
|
71
71
|
# Basic Options
|
|
72
72
|
|
data/lib/brakeman/app_tree.rb
CHANGED
|
@@ -28,7 +28,7 @@ module Brakeman
|
|
|
28
28
|
# Accepts an array of filenames and paths with the following format and
|
|
29
29
|
# returns a Regexp to match them:
|
|
30
30
|
# * "path1/file1.rb" - Matches a specific filename in the project directory.
|
|
31
|
-
# * "path1/" - Matches any path that
|
|
31
|
+
# * "path1/" - Matches any path that contains "path1" in the project directory.
|
|
32
32
|
# * "/path1/ - Matches any path that is rooted at "path1" in the project directory.
|
|
33
33
|
#
|
|
34
34
|
def self.regex_for_paths(paths)
|
|
@@ -513,4 +513,14 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
513
513
|
string_building? exp.target or
|
|
514
514
|
string_building? exp.first_arg
|
|
515
515
|
end
|
|
516
|
+
|
|
517
|
+
I18N_CLASS = s(:const, :I18n)
|
|
518
|
+
|
|
519
|
+
def locale_call? exp
|
|
520
|
+
return unless call? exp
|
|
521
|
+
|
|
522
|
+
(exp.target == I18N_CLASS and
|
|
523
|
+
exp.method == :locale) or
|
|
524
|
+
locale_call? exp.target
|
|
525
|
+
end
|
|
516
526
|
end
|
|
@@ -26,7 +26,7 @@ class Brakeman::CheckDetailedExceptions < Brakeman::BaseCheck
|
|
|
26
26
|
def check_detailed_exceptions
|
|
27
27
|
tracker.controllers.each do |_name, controller|
|
|
28
28
|
controller.methods_public.each do |method_name, definition|
|
|
29
|
-
src = definition
|
|
29
|
+
src = definition.src
|
|
30
30
|
body = src.body.last
|
|
31
31
|
next unless body
|
|
32
32
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require_relative 'eol_check'
|
|
2
|
+
|
|
3
|
+
class Brakeman::CheckEOLRails < Brakeman::EOLCheck
|
|
4
|
+
Brakeman::Checks.add self
|
|
5
|
+
|
|
6
|
+
@description = "Checks for unsupported versions of Rails"
|
|
7
|
+
|
|
8
|
+
def run_check
|
|
9
|
+
return unless tracker.config.rails_version
|
|
10
|
+
|
|
11
|
+
check_eol_version :rails, RAILS_EOL_DATES
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
RAILS_EOL_DATES = {
|
|
15
|
+
['2.0.0', '2.3.99'] => Date.new(2013, 6, 25),
|
|
16
|
+
['3.0.0', '3.2.99'] => Date.new(2016, 6, 30),
|
|
17
|
+
['4.0.0', '4.2.99'] => Date.new(2017, 4, 27),
|
|
18
|
+
['5.0.0', '5.0.99'] => Date.new(2018, 5, 9),
|
|
19
|
+
['5.1.0', '5.1.99'] => Date.new(2019, 8, 25),
|
|
20
|
+
['5.2.0', '5.2.99'] => Date.new(2022, 6, 1),
|
|
21
|
+
['6.0.0', '6.0.99'] => Date.new(2023, 6, 1),
|
|
22
|
+
}
|
|
23
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require_relative 'eol_check'
|
|
2
|
+
|
|
3
|
+
class Brakeman::CheckEOLRuby < Brakeman::EOLCheck
|
|
4
|
+
Brakeman::Checks.add self
|
|
5
|
+
|
|
6
|
+
@description = "Checks for unsupported versions of Ruby"
|
|
7
|
+
|
|
8
|
+
def run_check
|
|
9
|
+
return unless tracker.config.ruby_version
|
|
10
|
+
|
|
11
|
+
check_eol_version :ruby, RUBY_EOL_DATES
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
RUBY_EOL_DATES = {
|
|
15
|
+
['0.0.0', '1.9.3'] => Date.new(2015, 2, 23),
|
|
16
|
+
['2.0.0', '2.0.99'] => Date.new(2016, 2, 24),
|
|
17
|
+
['2.1.0', '2.1.99'] => Date.new(2017, 3, 31),
|
|
18
|
+
['2.2.0', '2.2.99'] => Date.new(2018, 3, 31),
|
|
19
|
+
['2.3.0', '2.3.99'] => Date.new(2019, 3, 31),
|
|
20
|
+
['2.4.0', '2.4.99'] => Date.new(2020, 3, 31),
|
|
21
|
+
['2.5.0', '2.5.99'] => Date.new(2021, 3, 31),
|
|
22
|
+
['2.6.0', '2.6.99'] => Date.new(2022, 3, 31),
|
|
23
|
+
['2.7.0', '2.7.99'] => Date.new(2023, 3, 31),
|
|
24
|
+
['3.0.0', '2.8.99'] => Date.new(2024, 3, 31),
|
|
25
|
+
}
|
|
26
|
+
end
|
|
@@ -10,7 +10,7 @@ class Brakeman::CheckEvaluation < Brakeman::BaseCheck
|
|
|
10
10
|
#Process calls
|
|
11
11
|
def run_check
|
|
12
12
|
Brakeman.debug "Finding eval-like calls"
|
|
13
|
-
calls = tracker.find_call :
|
|
13
|
+
calls = tracker.find_call methods: [:eval, :instance_eval, :class_eval, :module_eval], nested: true
|
|
14
14
|
|
|
15
15
|
Brakeman.debug "Processing eval-like calls"
|
|
16
16
|
calls.each do |call|
|
|
@@ -87,6 +87,16 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
|
87
87
|
dangerous_interp?(first_arg) ||
|
|
88
88
|
dangerous_string_building?(first_arg)
|
|
89
89
|
end
|
|
90
|
+
when :capture2, :capture2e, :capture3
|
|
91
|
+
# Open3 capture methods can take a :stdin_data argument which is used as the
|
|
92
|
+
# the input to the called command so it is not succeptable to command injection.
|
|
93
|
+
# As such if the last argument is a hash (and therefore execution options) it
|
|
94
|
+
# should be ignored
|
|
95
|
+
|
|
96
|
+
args.pop if hash?(args.last) && args.length > 2
|
|
97
|
+
failure = include_user_input?(args) ||
|
|
98
|
+
dangerous_interp?(args) ||
|
|
99
|
+
dangerous_string_building?(args)
|
|
90
100
|
else
|
|
91
101
|
failure = include_user_input?(args) ||
|
|
92
102
|
dangerous_interp?(args) ||
|
|
@@ -74,7 +74,7 @@ class Brakeman::CheckJSONParsing < Brakeman::BaseCheck
|
|
|
74
74
|
warning_type = "Denial of Service"
|
|
75
75
|
confidence = :medium
|
|
76
76
|
gem_name = "#{name} gem"
|
|
77
|
-
message = msg(msg_version(version, gem_name), " has a symbol creation
|
|
77
|
+
message = msg(msg_version(version, gem_name), " has a symbol creation vulnerability. Upgrade to ")
|
|
78
78
|
|
|
79
79
|
if version >= "1.7.0"
|
|
80
80
|
confidence = :high
|
|
@@ -33,6 +33,7 @@ class Brakeman::CheckRender < Brakeman::BaseCheck
|
|
|
33
33
|
view = result[:call][2]
|
|
34
34
|
|
|
35
35
|
if sexp? view and original? result
|
|
36
|
+
return if renderable?(view)
|
|
36
37
|
|
|
37
38
|
if input = has_immediate_user_input?(view)
|
|
38
39
|
if string_interp? view
|
|
@@ -94,4 +95,17 @@ class Brakeman::CheckRender < Brakeman::BaseCheck
|
|
|
94
95
|
end
|
|
95
96
|
end
|
|
96
97
|
end
|
|
97
|
-
|
|
98
|
+
|
|
99
|
+
def renderable? exp
|
|
100
|
+
return false unless call?(exp) and constant?(exp.target)
|
|
101
|
+
|
|
102
|
+
target_class_name = class_name(exp.target)
|
|
103
|
+
known_renderable_class?(target_class_name) or tracker.find_method(:render_in, target_class_name)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def known_renderable_class? class_name
|
|
107
|
+
klass = tracker.find_class(class_name)
|
|
108
|
+
return false if klass.nil?
|
|
109
|
+
klass.ancestor? :"ViewComponent::Base"
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -22,7 +22,19 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
|
22
22
|
:find_by_sql, :maximum, :minimum, :pluck, :sum, :update_all]
|
|
23
23
|
@sql_targets.concat [:from, :group, :having, :joins, :lock, :order, :reorder, :where] if tracker.options[:rails3]
|
|
24
24
|
@sql_targets.concat [:find_by, :find_by!, :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, :not] if tracker.options[:rails4]
|
|
25
|
-
|
|
25
|
+
|
|
26
|
+
if tracker.options[:rails6]
|
|
27
|
+
@sql_targets.concat [:delete_by, :destroy_by, :rewhere, :reselect]
|
|
28
|
+
|
|
29
|
+
@sql_targets.delete :delete_all
|
|
30
|
+
@sql_targets.delete :destroy_all
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
if version_between?("6.1.0", "9.9.9")
|
|
34
|
+
@sql_targets.delete :order
|
|
35
|
+
@sql_targets.delete :reorder
|
|
36
|
+
@sql_targets.delete :pluck
|
|
37
|
+
end
|
|
26
38
|
|
|
27
39
|
if version_between?("2.0.0", "3.9.9") or tracker.config.rails_version.nil?
|
|
28
40
|
@sql_targets << :first << :last << :all
|
|
@@ -185,7 +197,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
|
185
197
|
else
|
|
186
198
|
check_find_arguments call.last_arg
|
|
187
199
|
end
|
|
188
|
-
when :where, :having, :find_by, :find_by!, :find_or_create_by, :find_or_create_by!, :find_or_initialize_by,:not, :delete_by, :destroy_by
|
|
200
|
+
when :where, :rewhere, :having, :find_by, :find_by!, :find_or_create_by, :find_or_create_by!, :find_or_initialize_by,:not, :delete_by, :destroy_by
|
|
189
201
|
check_query_arguments call.arglist
|
|
190
202
|
when :order, :group, :reorder
|
|
191
203
|
check_order_arguments call.arglist
|
|
@@ -199,7 +211,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
|
199
211
|
unsafe_sql? call.first_arg
|
|
200
212
|
when :sql
|
|
201
213
|
unsafe_sql? call.first_arg
|
|
202
|
-
when :update_all, :select
|
|
214
|
+
when :update_all, :select, :reselect
|
|
203
215
|
check_update_all_arguments call.args
|
|
204
216
|
when *@connection_calls
|
|
205
217
|
check_by_sql_arguments call.first_arg
|
|
@@ -579,6 +591,10 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
|
579
591
|
:where_values_hash, :foreign_key, :uuid
|
|
580
592
|
]
|
|
581
593
|
|
|
594
|
+
def ignore_methods_in_sql
|
|
595
|
+
@ignore_methods_in_sql ||= IGNORE_METHODS_IN_SQL + (tracker.options[:sql_safe_methods] || [])
|
|
596
|
+
end
|
|
597
|
+
|
|
582
598
|
def safe_value? exp
|
|
583
599
|
return true unless sexp? exp
|
|
584
600
|
|
|
@@ -589,10 +605,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
|
589
605
|
if exp.method == :to_s or exp.method == :to_sym
|
|
590
606
|
safe_value? exp.target
|
|
591
607
|
else
|
|
592
|
-
|
|
593
|
-
quote_call? exp or
|
|
594
|
-
arel? exp or
|
|
595
|
-
exp.method.to_s.end_with? "_id"
|
|
608
|
+
ignore_call? exp
|
|
596
609
|
end
|
|
597
610
|
when :if
|
|
598
611
|
safe_value? exp.then_clause and safe_value? exp.else_clause
|
|
@@ -607,6 +620,18 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
|
607
620
|
end
|
|
608
621
|
end
|
|
609
622
|
|
|
623
|
+
def ignore_call? exp
|
|
624
|
+
return unless call? exp
|
|
625
|
+
|
|
626
|
+
ignore_methods_in_sql.include? exp.method or
|
|
627
|
+
quote_call? exp or
|
|
628
|
+
arel? exp or
|
|
629
|
+
exp.method.to_s.end_with? "_id" or
|
|
630
|
+
number_target? exp or
|
|
631
|
+
date_target? exp or
|
|
632
|
+
locale_call? exp
|
|
633
|
+
end
|
|
634
|
+
|
|
610
635
|
QUOTE_METHODS = [:quote, :quote_column_name, :quoted_date, :quote_string, :quote_table_name]
|
|
611
636
|
|
|
612
637
|
def quote_call? exp
|
|
@@ -695,4 +720,30 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
|
695
720
|
active_record_models.include? klass
|
|
696
721
|
end
|
|
697
722
|
end
|
|
723
|
+
|
|
724
|
+
def number_target? exp
|
|
725
|
+
return unless call? exp
|
|
726
|
+
|
|
727
|
+
if number? exp.target
|
|
728
|
+
true
|
|
729
|
+
elsif call? exp.target
|
|
730
|
+
number_target? exp.target
|
|
731
|
+
else
|
|
732
|
+
false
|
|
733
|
+
end
|
|
734
|
+
end
|
|
735
|
+
|
|
736
|
+
DATE_CLASS = s(:const, :Date)
|
|
737
|
+
|
|
738
|
+
def date_target? exp
|
|
739
|
+
return unless call? exp
|
|
740
|
+
|
|
741
|
+
if exp.target == DATE_CLASS
|
|
742
|
+
true
|
|
743
|
+
elsif call? exp.target
|
|
744
|
+
date_target? exp.target
|
|
745
|
+
else
|
|
746
|
+
false
|
|
747
|
+
end
|
|
748
|
+
end
|
|
698
749
|
end
|
|
@@ -9,7 +9,7 @@ class Brakeman::CheckSymbolDoS < Brakeman::BaseCheck
|
|
|
9
9
|
|
|
10
10
|
def run_check
|
|
11
11
|
return if rails_version and rails_version >= "5.0.0"
|
|
12
|
-
return if tracker.config.ruby_version >= "2.2"
|
|
12
|
+
return if tracker.config.ruby_version and tracker.config.ruby_version >= "2.2"
|
|
13
13
|
|
|
14
14
|
tracker.find_call(:methods => UNSAFE_METHODS, :nested => true).each do |result|
|
|
15
15
|
check_unsafe_symbol_creation(result)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
require 'brakeman/checks/base_check'
|
|
3
|
+
|
|
4
|
+
# Not used directly - base check for EOLRails and EOLRuby
|
|
5
|
+
class Brakeman::EOLCheck < Brakeman::BaseCheck
|
|
6
|
+
def check_eol_version library, eol_dates
|
|
7
|
+
version = case library
|
|
8
|
+
when :rails
|
|
9
|
+
tracker.config.rails_version
|
|
10
|
+
when :ruby
|
|
11
|
+
tracker.config.ruby_version
|
|
12
|
+
else
|
|
13
|
+
raise 'Implement using tracker.config.gem_version'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
eol_dates.each do |(start_version, end_version), eol_date|
|
|
17
|
+
if version_between? start_version, end_version, version
|
|
18
|
+
case
|
|
19
|
+
when Date.today >= eol_date
|
|
20
|
+
warn_about_unsupported_version library, eol_date, version
|
|
21
|
+
when (Date.today + 30) >= eol_date
|
|
22
|
+
warn_about_soon_unsupported_version library, eol_date, version, :medium
|
|
23
|
+
when (Date.today + 60) >= eol_date
|
|
24
|
+
warn_about_soon_unsupported_version library, eol_date, version, :low
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
break
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def warn_about_soon_unsupported_version library, eol_date, version, confidence
|
|
33
|
+
warn warning_type: 'Unmaintained Dependency',
|
|
34
|
+
warning_code: :"pending_eol_#{library}",
|
|
35
|
+
message: msg("Support for ", msg_version(version, library.capitalize), " ends on #{eol_date}"),
|
|
36
|
+
confidence: confidence,
|
|
37
|
+
gem_info: gemfile_or_environment
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def warn_about_unsupported_version library, eol_date, version
|
|
41
|
+
warn warning_type: 'Unmaintained Dependency',
|
|
42
|
+
warning_code: :"eol_#{library}",
|
|
43
|
+
message: msg("Support for ", msg_version(version, library.capitalize), " ended on #{eol_date}"),
|
|
44
|
+
confidence: :high,
|
|
45
|
+
gem_info: gemfile_or_environment
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/brakeman/file_parser.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'parallel'
|
|
2
|
+
|
|
1
3
|
module Brakeman
|
|
2
4
|
ASTFile = Struct.new(:path, :ast)
|
|
3
5
|
|
|
@@ -5,29 +7,62 @@ module Brakeman
|
|
|
5
7
|
class FileParser
|
|
6
8
|
attr_reader :file_list, :errors
|
|
7
9
|
|
|
8
|
-
def initialize app_tree, timeout
|
|
10
|
+
def initialize app_tree, timeout, parallel = true
|
|
9
11
|
@app_tree = app_tree
|
|
10
12
|
@timeout = timeout
|
|
11
13
|
@file_list = []
|
|
12
14
|
@errors = []
|
|
15
|
+
@parallel = parallel
|
|
13
16
|
end
|
|
14
17
|
|
|
15
18
|
def parse_files list
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
if @parallel
|
|
20
|
+
parallel_options = {}
|
|
21
|
+
else
|
|
22
|
+
# Disable parallelism
|
|
23
|
+
parallel_options = { in_threads: 0 }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Parse the files in parallel.
|
|
27
|
+
# By default, the parsing will be in separate processes.
|
|
28
|
+
# So we map the result to ASTFiles and/or Exceptions
|
|
29
|
+
# then partition them into ASTFiles and Exceptions
|
|
30
|
+
# and add the Exceptions to @errors
|
|
31
|
+
#
|
|
32
|
+
# Basically just a funky way to deal with two possible
|
|
33
|
+
# return types that are returned from isolated processes.
|
|
34
|
+
#
|
|
35
|
+
# Note this method no longer uses read_files
|
|
36
|
+
@file_list, new_errors = Parallel.map(list, parallel_options) do |file_name|
|
|
37
|
+
file_path = @app_tree.file_path(file_name)
|
|
38
|
+
contents = file_path.read
|
|
39
|
+
|
|
40
|
+
begin
|
|
41
|
+
if ast = parse_ruby(contents, file_path.relative)
|
|
42
|
+
ASTFile.new(file_name, ast)
|
|
43
|
+
end
|
|
44
|
+
rescue Exception => e
|
|
45
|
+
e
|
|
19
46
|
end
|
|
47
|
+
end.compact.partition do |result|
|
|
48
|
+
result.is_a? ASTFile
|
|
20
49
|
end
|
|
50
|
+
|
|
51
|
+
errors.concat new_errors
|
|
21
52
|
end
|
|
22
53
|
|
|
23
54
|
def read_files list
|
|
24
55
|
list.each do |path|
|
|
25
56
|
file = @app_tree.file_path(path)
|
|
26
57
|
|
|
27
|
-
|
|
58
|
+
begin
|
|
59
|
+
result = yield file, file.read
|
|
28
60
|
|
|
29
|
-
|
|
30
|
-
|
|
61
|
+
if result
|
|
62
|
+
@file_list << result
|
|
63
|
+
end
|
|
64
|
+
rescue Exception => e
|
|
65
|
+
@errors << e
|
|
31
66
|
end
|
|
32
67
|
end
|
|
33
68
|
end
|
|
@@ -42,17 +77,12 @@ module Brakeman
|
|
|
42
77
|
Brakeman.debug "Parsing #{path}"
|
|
43
78
|
RubyParser.new.parse input, path, @timeout
|
|
44
79
|
rescue Racc::ParseError => e
|
|
45
|
-
|
|
80
|
+
raise e.exception(e.message + "\nCould not parse #{path}")
|
|
46
81
|
rescue Timeout::Error => e
|
|
47
|
-
|
|
82
|
+
raise Exception.new("Parsing #{path} took too long (> #{@timeout} seconds). Try increasing the limit with --parser-timeout")
|
|
48
83
|
rescue => e
|
|
49
|
-
|
|
84
|
+
raise e.exception(e.message + "\nWhile processing #{path}")
|
|
50
85
|
end
|
|
51
86
|
end
|
|
52
|
-
|
|
53
|
-
def error exception
|
|
54
|
-
@errors << exception
|
|
55
|
-
nil
|
|
56
|
-
end
|
|
57
87
|
end
|
|
58
88
|
end
|
data/lib/brakeman/options.rb
CHANGED
|
@@ -39,7 +39,7 @@ module Brakeman::Options
|
|
|
39
39
|
OptionParser.new do |opts|
|
|
40
40
|
opts.banner = "Usage: brakeman [options] rails/root/path"
|
|
41
41
|
|
|
42
|
-
opts.on "-n", "--no-threads", "Run checks sequentially" do
|
|
42
|
+
opts.on "-n", "--no-threads", "Run checks and file parsing sequentially" do
|
|
43
43
|
options[:parallel_checks] = false
|
|
44
44
|
end
|
|
45
45
|
|
|
@@ -93,6 +93,14 @@ module Brakeman::Options
|
|
|
93
93
|
options[:rails6] = true
|
|
94
94
|
end
|
|
95
95
|
|
|
96
|
+
opts.on "-7", "--rails7", "Force Rails 7 mode" do
|
|
97
|
+
options[:rails3] = true
|
|
98
|
+
options[:rails4] = true
|
|
99
|
+
options[:rails5] = true
|
|
100
|
+
options[:rails6] = true
|
|
101
|
+
options[:rails7] = true
|
|
102
|
+
end
|
|
103
|
+
|
|
96
104
|
opts.separator ""
|
|
97
105
|
opts.separator "Scanning options:"
|
|
98
106
|
|
|
@@ -151,6 +159,11 @@ module Brakeman::Options
|
|
|
151
159
|
options[:safe_methods].merge methods.map {|e| e.to_sym }
|
|
152
160
|
end
|
|
153
161
|
|
|
162
|
+
opts.on "--sql-safe-methods meth1,meth2,etc", Array, "Do not warn of SQL if the input is wrapped in a safe method" do |methods|
|
|
163
|
+
options[:sql_safe_methods] ||= Set.new
|
|
164
|
+
options[:sql_safe_methods].merge methods.map {|e| e.to_sym }
|
|
165
|
+
end
|
|
166
|
+
|
|
154
167
|
opts.on "--url-safe-methods method1,method2,etc", Array, "Do not warn of XSS if the link_to href parameter is wrapped in a safe method" do |methods|
|
|
155
168
|
options[:url_safe_methods] ||= Set.new
|
|
156
169
|
options[:url_safe_methods].merge methods.map {|e| e.to_sym }
|
|
@@ -233,7 +246,7 @@ module Brakeman::Options
|
|
|
233
246
|
|
|
234
247
|
opts.on "-f",
|
|
235
248
|
"--format TYPE",
|
|
236
|
-
[:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain, :table, :junit, :sarif, :sonar],
|
|
249
|
+
[:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain, :table, :junit, :sarif, :sonar, :github],
|
|
237
250
|
"Specify output formats. Default is text" do |type|
|
|
238
251
|
|
|
239
252
|
type = "s" if type == :text
|