brakeman 4.10.1 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +25 -0
- data/README.md +1 -1
- data/bundle/load.rb +2 -2
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/History.rdoc +6 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/Manifest.txt +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/README.rdoc +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/compare/normalize.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/debugging.md +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/rp_extensions.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/rp_stringscanner.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby20_parser.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby20_parser.y +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby21_parser.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby21_parser.y +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby22_parser.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby22_parser.y +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby23_parser.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby23_parser.y +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby24_parser.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby24_parser.y +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby25_parser.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby25_parser.y +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby26_parser.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby26_parser.y +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby27_parser.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby27_parser.y +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby_lexer.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby_lexer.rex +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby_lexer.rex.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby_parser.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby_parser.yy +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby_parser_extras.rb +1 -1
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/tools/munge.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/tools/ripper.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/History.rdoc +6 -0
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/Manifest.txt +0 -0
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/README.rdoc +0 -0
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/composite_sexp_processor.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/pt_testcase.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/sexp.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/sexp_matcher.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/sexp_processor.rb +1 -1
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/strict_sexp.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/unique.rb +0 -0
- data/lib/brakeman.rb +6 -0
- data/lib/brakeman/app_tree.rb +36 -3
- data/lib/brakeman/checks/base_check.rb +7 -1
- data/lib/brakeman/checks/check_execute.rb +1 -0
- data/lib/brakeman/checks/check_sql.rb +1 -1
- data/lib/brakeman/checks/check_unsafe_reflection_methods.rb +68 -0
- data/lib/brakeman/checks/check_verb_confusion.rb +75 -0
- data/lib/brakeman/file_parser.rb +19 -18
- data/lib/brakeman/options.rb +5 -1
- data/lib/brakeman/parsers/template_parser.rb +2 -3
- data/lib/brakeman/processors/alias_processor.rb +18 -2
- data/lib/brakeman/processors/lib/file_type_detector.rb +64 -0
- data/lib/brakeman/processors/lib/rails3_config_processor.rb +16 -16
- data/lib/brakeman/report.rb +8 -0
- data/lib/brakeman/report/report_base.rb +0 -2
- data/lib/brakeman/report/report_csv.rb +37 -60
- data/lib/brakeman/report/report_junit.rb +2 -2
- data/lib/brakeman/report/report_sarif.rb +1 -1
- data/lib/brakeman/report/report_sonar.rb +38 -0
- data/lib/brakeman/report/report_tabs.rb +1 -1
- data/lib/brakeman/report/report_text.rb +1 -1
- data/lib/brakeman/rescanner.rb +7 -5
- data/lib/brakeman/scanner.rb +44 -18
- data/lib/brakeman/tracker.rb +6 -0
- data/lib/brakeman/tracker/config.rb +73 -0
- data/lib/brakeman/util.rb +7 -2
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +10 -2
- data/lib/brakeman/warning_codes.rb +2 -0
- metadata +48 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d660b98db2252a6aa69d39bb56c6950aa7d9713f10831807d6ab837df54657d
|
4
|
+
data.tar.gz: 6999959ba9f8380f36c1d999e04b0d79e48ea9536fd9820485c4960bce769d60
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b6738f567478a47fd36de992706968c1c42a237dd97d4527434a60fa9ddea5b7a7acb54d8b72e6bc282fd1805126953a358e399a19dab4c0c5e7fd92b4a857ed
|
7
|
+
data.tar.gz: 43f16437835dabb65a7b73981779460e7648e1fa2ba772320132e7500af55c8861effda46f3b181310bdd753dbf1c59af12b3ecdfed5844505e2cf5cbff866fa
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
# 5.0.0 - 2021-01-26
|
2
|
+
|
3
|
+
* Ignore `uuid` as a safe attribute
|
4
|
+
* Collapse `__send__` calls
|
5
|
+
* Ignore `Tempfile#path` in shell commands
|
6
|
+
* Ignore development environment
|
7
|
+
* Revamp CSV report to a CSV list of warnings
|
8
|
+
* Set Rails configuration defaults based on `load_defaults` version
|
9
|
+
* Add check for (more) unsafe method reflection
|
10
|
+
* Suggest using `--force` if no Rails application is detected
|
11
|
+
* Add Sonarqube report format (Adam England)
|
12
|
+
* Add check for potential HTTP verb confusion
|
13
|
+
* Add `--[no-]skip-vendor` option
|
14
|
+
* Scan (almost) all Ruby files in project
|
15
|
+
|
1
16
|
# 4.10.1 - 2020-12-24
|
2
17
|
|
3
18
|
* Declare REXML as a dependency (Ruby 3.0 compatibility)
|
@@ -6,6 +21,16 @@
|
|
6
21
|
* Ensure RubyParser is passed file path as a String
|
7
22
|
* Support new Haml 5.2.0 escaping method
|
8
23
|
|
24
|
+
# 5.0.0.pre1 - 2020-11-17
|
25
|
+
|
26
|
+
* Add check for (more) unsafe method reflection
|
27
|
+
* Suggest using `--force` if no Rails application is detected
|
28
|
+
* Add Sonarqube report format (Adam England)
|
29
|
+
* Add check for potential HTTP verb confusion
|
30
|
+
* Add `--[no-]skip-vendor` option
|
31
|
+
* Scan (almost) all Ruby files in project
|
32
|
+
* Add support for Haml 5.2.0
|
33
|
+
|
9
34
|
# 4.10.0 - 2020-09-28
|
10
35
|
|
11
36
|
* Add SARIF report format (Steve Winton)
|
data/README.md
CHANGED
@@ -76,7 +76,7 @@ To specify an output file for the results:
|
|
76
76
|
|
77
77
|
brakeman -o output_file
|
78
78
|
|
79
|
-
The output format is determined by the file extension or by using the `-f` option. Current options are: `text`, `html`, `tabs`, `json`, `junit`, `markdown`, `csv`, and `
|
79
|
+
The output format is determined by the file extension or by using the `-f` option. Current options are: `text`, `html`, `tabs`, `json`, `junit`, `markdown`, `csv`, `codeclimate`, and `sonar`.
|
80
80
|
|
81
81
|
Multiple output files can be specified:
|
82
82
|
|
data/bundle/load.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
path = File.expand_path('../..', __FILE__)
|
2
|
-
$:.unshift "#{path}/bundle/ruby/2.7.0/gems/ruby_parser-3.15.0/lib"
|
3
2
|
$:.unshift "#{path}/bundle/ruby/2.7.0/gems/temple-0.8.2/lib"
|
4
3
|
$:.unshift "#{path}/bundle/ruby/2.7.0/gems/unicode-display_width-1.7.0/lib"
|
5
|
-
$:.unshift "#{path}/bundle/ruby/2.7.0/gems/sexp_processor-4.15.1/lib"
|
6
4
|
$:.unshift "#{path}/bundle/ruby/2.7.0/gems/tilt-2.0.10/lib"
|
7
5
|
$:.unshift "#{path}/bundle/ruby/2.7.0/gems/slim-4.1.0/lib"
|
6
|
+
$:.unshift "#{path}/bundle/ruby/2.7.0/gems/sexp_processor-4.15.2/lib"
|
8
7
|
$:.unshift "#{path}/bundle/ruby/2.7.0/gems/highline-2.0.3/lib"
|
9
8
|
$:.unshift "#{path}/bundle/ruby/2.7.0/gems/ruby2ruby-2.4.4/lib"
|
10
9
|
$:.unshift "#{path}/bundle/ruby/2.7.0/gems/terminal-table-1.8.0/lib"
|
@@ -12,4 +11,5 @@ $:.unshift "#{path}/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib"
|
|
12
11
|
$:.unshift "#{path}/bundle/ruby/2.7.0/gems/ruby_parser-legacy-1.0.0/lib"
|
13
12
|
$:.unshift "#{path}/bundle/ruby/2.7.0/gems/erubis-2.7.0/lib"
|
14
13
|
$:.unshift "#{path}/bundle/ruby/2.7.0/gems/haml-5.2.1/lib"
|
14
|
+
$:.unshift "#{path}/bundle/ruby/2.7.0/gems/ruby_parser-3.15.1/lib"
|
15
15
|
$:.unshift "#{path}/bundle/ruby/2.7.0/gems/safe_yaml-1.0.5/lib"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/rp_stringscanner.rb
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/pt_testcase.rb
RENAMED
File without changes
|
File without changes
|
data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/sexp_matcher.rb
RENAMED
File without changes
|
data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/strict_sexp.rb
RENAMED
File without changes
|
File without changes
|
data/lib/brakeman.rb
CHANGED
@@ -66,6 +66,7 @@ module Brakeman
|
|
66
66
|
# * :run_checks - array of checks to run (run all if not specified)
|
67
67
|
# * :safe_methods - array of methods to consider safe
|
68
68
|
# * :skip_libs - do not process lib/ directory (default: false)
|
69
|
+
# * :skip_vendor - do not process vendor/ directory (default: true)
|
69
70
|
# * :skip_checks - checks not to run (run all if not specified)
|
70
71
|
# * :absolute_paths - show absolute path of each file (default: false)
|
71
72
|
# * :summary_only - only output summary section of report for plain/table (:summary_only, :no_summary, true)
|
@@ -191,6 +192,7 @@ module Brakeman
|
|
191
192
|
:report_progress => true,
|
192
193
|
:safe_methods => Set.new,
|
193
194
|
:skip_checks => Set.new,
|
195
|
+
:skip_vendor => true,
|
194
196
|
}
|
195
197
|
end
|
196
198
|
|
@@ -239,6 +241,8 @@ module Brakeman
|
|
239
241
|
[:to_junit]
|
240
242
|
when :sarif, :to_sarif
|
241
243
|
[:to_sarif]
|
244
|
+
when :sonar, :to_sonar
|
245
|
+
[:to_sonar]
|
242
246
|
else
|
243
247
|
[:to_text]
|
244
248
|
end
|
@@ -270,6 +274,8 @@ module Brakeman
|
|
270
274
|
:to_junit
|
271
275
|
when /\.sarif$/i
|
272
276
|
:to_sarif
|
277
|
+
when /\.sonar$/i
|
278
|
+
:to_sonar
|
273
279
|
else
|
274
280
|
:to_text
|
275
281
|
end
|
data/lib/brakeman/app_tree.rb
CHANGED
@@ -21,6 +21,7 @@ module Brakeman
|
|
21
21
|
end
|
22
22
|
init_options[:additional_libs_path] = options[:additional_libs_path]
|
23
23
|
init_options[:engine_paths] = options[:engine_paths]
|
24
|
+
init_options[:skip_vendor] = options[:skip_vendor]
|
24
25
|
new(root, init_options)
|
25
26
|
end
|
26
27
|
|
@@ -62,6 +63,7 @@ module Brakeman
|
|
62
63
|
@engine_paths = init_options[:engine_paths] || []
|
63
64
|
@absolute_engine_paths = @engine_paths.select { |path| path.start_with?(File::SEPARATOR) }
|
64
65
|
@relative_engine_paths = @engine_paths - @absolute_engine_paths
|
66
|
+
@skip_vendor = init_options[:skip_vendor]
|
65
67
|
@gemspec = nil
|
66
68
|
@root_search_pattern = nil
|
67
69
|
end
|
@@ -96,6 +98,10 @@ module Brakeman
|
|
96
98
|
end
|
97
99
|
end
|
98
100
|
|
101
|
+
def ruby_file_paths
|
102
|
+
find_paths(".").uniq
|
103
|
+
end
|
104
|
+
|
99
105
|
def initializer_paths
|
100
106
|
@initializer_paths ||= prioritize_concerns(find_paths("config/initializers"))
|
101
107
|
end
|
@@ -109,8 +115,8 @@ module Brakeman
|
|
109
115
|
end
|
110
116
|
|
111
117
|
def template_paths
|
112
|
-
@template_paths ||= find_paths("
|
113
|
-
|
118
|
+
@template_paths ||= find_paths(".", "*.{#{VIEW_EXTENSIONS}}") +
|
119
|
+
find_paths("**", "*.{erb,haml,slim}").reject { |path| File.basename(path).count(".") > 1 }
|
114
120
|
end
|
115
121
|
|
116
122
|
def layout_exists?(name)
|
@@ -163,7 +169,8 @@ module Brakeman
|
|
163
169
|
def select_files(paths)
|
164
170
|
paths = select_only_files(paths)
|
165
171
|
paths = reject_skipped_files(paths)
|
166
|
-
convert_to_file_paths(paths)
|
172
|
+
paths = convert_to_file_paths(paths)
|
173
|
+
reject_global_excludes(paths)
|
167
174
|
end
|
168
175
|
|
169
176
|
def select_only_files(paths)
|
@@ -182,6 +189,32 @@ module Brakeman
|
|
182
189
|
end
|
183
190
|
end
|
184
191
|
|
192
|
+
EXCLUDED_PATHS = %w[
|
193
|
+
/generators/
|
194
|
+
lib/tasks/
|
195
|
+
lib/templates/
|
196
|
+
db/
|
197
|
+
spec/
|
198
|
+
test/
|
199
|
+
tmp/
|
200
|
+
public/
|
201
|
+
log/
|
202
|
+
]
|
203
|
+
|
204
|
+
def reject_global_excludes(paths)
|
205
|
+
paths.reject do |path|
|
206
|
+
relative_path = path.relative
|
207
|
+
|
208
|
+
if @skip_vendor and relative_path.include? 'vendor/'
|
209
|
+
true
|
210
|
+
else
|
211
|
+
EXCLUDED_PATHS.any? do |excluded|
|
212
|
+
relative_path.include? excluded
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
185
218
|
def match_path files, path
|
186
219
|
absolute_path = Pathname.new(path)
|
187
220
|
# relative root never has a leading separator. But, we use a leading
|
@@ -40,7 +40,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
40
40
|
@mass_assign_disabled = nil
|
41
41
|
@has_user_input = nil
|
42
42
|
@in_array = false
|
43
|
-
@safe_input_attributes = Set[:to_i, :to_f, :arel_table, :id]
|
43
|
+
@safe_input_attributes = Set[:to_i, :to_f, :arel_table, :id, :uuid]
|
44
44
|
@comparison_ops = Set[:==, :!=, :>, :<, :>=, :<=]
|
45
45
|
end
|
46
46
|
|
@@ -151,6 +151,12 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
151
151
|
method[-1] == "?"
|
152
152
|
end
|
153
153
|
|
154
|
+
TEMP_FILE_PATH = s(:call, s(:call, s(:const, :Tempfile), :new), :path).freeze
|
155
|
+
|
156
|
+
def temp_file_path? exp
|
157
|
+
exp == TEMP_FILE_PATH
|
158
|
+
end
|
159
|
+
|
154
160
|
#Report a warning
|
155
161
|
def warn options
|
156
162
|
extra_opts = { :check => self.class.to_s }
|
@@ -204,6 +204,7 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
204
204
|
next if node_type? e, :lit, :str
|
205
205
|
next if SAFE_VALUES.include? e
|
206
206
|
next if shell_escape? e
|
207
|
+
next if temp_file_path? e
|
207
208
|
|
208
209
|
if node_type? e, :if
|
209
210
|
# If we're in a conditional, evaluate the `then` and `else` clauses to
|
@@ -576,7 +576,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
576
576
|
:sanitize_sql_for_assignment, :sanitize_sql_for_conditions, :sanitize_sql_hash,
|
577
577
|
:sanitize_sql_hash_for_assignment, :sanitize_sql_hash_for_conditions,
|
578
578
|
:to_sql, :sanitize, :primary_key, :table_name_prefix, :table_name_suffix,
|
579
|
-
:where_values_hash, :foreign_key
|
579
|
+
:where_values_hash, :foreign_key, :uuid
|
580
580
|
]
|
581
581
|
|
582
582
|
def safe_value? exp
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'brakeman/checks/base_check'
|
2
|
+
|
3
|
+
class Brakeman::CheckUnsafeReflectionMethods < Brakeman::BaseCheck
|
4
|
+
Brakeman::Checks.add self
|
5
|
+
|
6
|
+
@description = "Checks for unsafe reflection to access methods"
|
7
|
+
|
8
|
+
def run_check
|
9
|
+
check_method
|
10
|
+
check_tap
|
11
|
+
check_to_proc
|
12
|
+
end
|
13
|
+
|
14
|
+
def check_method
|
15
|
+
tracker.find_call(method: :method, nested: true).each do |result|
|
16
|
+
argument = result[:call].first_arg
|
17
|
+
|
18
|
+
if user_input = include_user_input?(argument)
|
19
|
+
warn_unsafe_reflection(result, user_input)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def check_tap
|
25
|
+
tracker.find_call(method: :tap, nested: true).each do |result|
|
26
|
+
argument = result[:call].first_arg
|
27
|
+
|
28
|
+
# Argument is passed like a.tap(&argument)
|
29
|
+
if node_type? argument, :block_pass
|
30
|
+
argument = argument.value
|
31
|
+
end
|
32
|
+
|
33
|
+
if user_input = include_user_input?(argument)
|
34
|
+
warn_unsafe_reflection(result, user_input)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def check_to_proc
|
40
|
+
tracker.find_call(method: :to_proc, nested: true).each do |result|
|
41
|
+
target = result[:call].target
|
42
|
+
|
43
|
+
if user_input = include_user_input?(target)
|
44
|
+
warn_unsafe_reflection(result, user_input)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def warn_unsafe_reflection result, input
|
50
|
+
return unless original? result
|
51
|
+
method = result[:call].method
|
52
|
+
|
53
|
+
confidence = if input.type == :params
|
54
|
+
:high
|
55
|
+
else
|
56
|
+
:medium
|
57
|
+
end
|
58
|
+
|
59
|
+
message = msg("Unsafe reflection method ", msg_code(method), " called with ", msg_input(input))
|
60
|
+
|
61
|
+
warn :result => result,
|
62
|
+
:warning_type => "Remote Code Execution",
|
63
|
+
:warning_code => :unsafe_method_reflection,
|
64
|
+
:message => message,
|
65
|
+
:user_input => input,
|
66
|
+
:confidence => confidence
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'brakeman/checks/base_check'
|
2
|
+
|
3
|
+
class Brakeman::CheckVerbConfusion < Brakeman::BaseCheck
|
4
|
+
Brakeman::Checks.add self
|
5
|
+
|
6
|
+
@description = "Check for uses of `request.get?` that might have unintentional behavior"
|
7
|
+
|
8
|
+
#Process calls
|
9
|
+
def run_check
|
10
|
+
calls = tracker.find_call(target: :request, methods: [:get?])
|
11
|
+
|
12
|
+
calls.each do |call|
|
13
|
+
process_result call
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def process_result result
|
18
|
+
@current_result = result
|
19
|
+
@matched_call = result[:call]
|
20
|
+
klass = tracker.find_class(result[:location][:class])
|
21
|
+
|
22
|
+
# TODO: abstract into tracker.find_location ?
|
23
|
+
if klass.nil?
|
24
|
+
Brakeman.debug "No class found: #{result[:location][:class]}"
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
method = klass.get_method(result[:location][:method])
|
29
|
+
|
30
|
+
if method.nil?
|
31
|
+
Brakeman.debug "No method found: #{result[:location][:method]}"
|
32
|
+
return
|
33
|
+
end
|
34
|
+
|
35
|
+
process method[:src]
|
36
|
+
end
|
37
|
+
|
38
|
+
def process_if exp
|
39
|
+
if exp.condition == @matched_call
|
40
|
+
# Found `if request.get?`
|
41
|
+
|
42
|
+
# Do not warn if there is an `elsif` clause
|
43
|
+
if node_type? exp.else_clause, :if
|
44
|
+
return exp
|
45
|
+
end
|
46
|
+
|
47
|
+
warn_about_result @current_result, exp
|
48
|
+
end
|
49
|
+
|
50
|
+
exp
|
51
|
+
end
|
52
|
+
|
53
|
+
def warn_about_result result, code
|
54
|
+
return unless original? result
|
55
|
+
|
56
|
+
confidence = :weak
|
57
|
+
message = msg('Potential HTTP verb confusion. ',
|
58
|
+
msg_code('HEAD'),
|
59
|
+
' is routed like ',
|
60
|
+
msg_code('GET'),
|
61
|
+
' but ',
|
62
|
+
msg_code('request.get?'),
|
63
|
+
' will return ',
|
64
|
+
msg_code('false')
|
65
|
+
)
|
66
|
+
|
67
|
+
warn :result => result,
|
68
|
+
:warning_type => "HTTP Verb Confusion",
|
69
|
+
:warning_code => :http_verb_confusion,
|
70
|
+
:message => message,
|
71
|
+
:code => code,
|
72
|
+
:user_input => result[:call],
|
73
|
+
:confidence => confidence
|
74
|
+
end
|
75
|
+
end
|