brakeman-lib 4.8.1 → 4.10.1
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 +39 -0
- data/README.md +5 -3
- data/lib/brakeman.rb +20 -0
- data/lib/brakeman/checks/base_check.rb +1 -1
- data/lib/brakeman/checks/check_basic_auth.rb +2 -0
- data/lib/brakeman/checks/check_csrf_token_forgery_cve.rb +28 -0
- data/lib/brakeman/checks/check_deserialize.rb +21 -1
- data/lib/brakeman/checks/check_execute.rb +1 -1
- data/lib/brakeman/checks/check_json_entity_escape.rb +38 -0
- data/lib/brakeman/checks/check_mass_assignment.rb +19 -4
- data/lib/brakeman/checks/check_model_attr_accessible.rb +1 -1
- data/lib/brakeman/checks/check_model_attributes.rb +1 -1
- data/lib/brakeman/checks/check_page_caching_cve.rb +37 -0
- data/lib/brakeman/checks/check_permit_attributes.rb +1 -1
- data/lib/brakeman/checks/check_regex_dos.rb +1 -1
- data/lib/brakeman/checks/check_skip_before_filter.rb +4 -4
- data/lib/brakeman/checks/check_sql.rb +1 -1
- data/lib/brakeman/checks/check_template_injection.rb +32 -0
- data/lib/brakeman/commandline.rb +25 -1
- data/lib/brakeman/file_parser.rb +5 -0
- data/lib/brakeman/options.rb +21 -1
- data/lib/brakeman/processors/alias_processor.rb +4 -5
- data/lib/brakeman/processors/controller_processor.rb +1 -1
- data/lib/brakeman/processors/haml_template_processor.rb +8 -1
- data/lib/brakeman/processors/lib/call_conversion_helper.rb +1 -1
- data/lib/brakeman/processors/lib/find_all_calls.rb +27 -12
- data/lib/brakeman/processors/output_processor.rb +1 -1
- data/lib/brakeman/processors/template_alias_processor.rb +5 -0
- data/lib/brakeman/report.rb +7 -0
- data/lib/brakeman/report/ignore/config.rb +4 -0
- data/lib/brakeman/report/report_sarif.rb +114 -0
- data/lib/brakeman/report/report_text.rb +37 -16
- data/lib/brakeman/scanner.rb +4 -1
- data/lib/brakeman/tracker.rb +3 -1
- data/lib/brakeman/tracker/config.rb +6 -4
- data/lib/brakeman/tracker/constants.rb +8 -7
- data/lib/brakeman/tracker/controller.rb +1 -1
- data/lib/brakeman/util.rb +18 -2
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning_codes.rb +6 -0
- data/lib/ruby_parser/bm_sexp.rb +9 -9
- metadata +38 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9433874563193068795eb4d4a90dd176132b04130cf68a9689753caff3c9df1e
|
4
|
+
data.tar.gz: 19e73894774e624624edecd48c28dd53aa4da68e7482afe272fec48398551040
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fbbd606baa82361d62752a44a0c3a095083d8e3b89c213cad7e8bdc97341a7fd09c3973c80c50d58349dc5bc9e98fe2ca390710d2419636a81f40d6dd75add6f
|
7
|
+
data.tar.gz: 89331cbf5168e088bdac777e65b3ee4cbe3244792f64f3c13db084e00db0fc3ebf792801d7c1f7fcc2b3c929cafd83e27381ecd03550d69b761cb94cf228856b
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,42 @@
|
|
1
|
+
# 4.10.1 - 2020-12-24
|
2
|
+
|
3
|
+
* Declare REXML as a dependency (Ruby 3.0 compatibility)
|
4
|
+
* Use `Sexp#sexp_body` instead of `Sexp#[..]` (Ruby 3.0 compatibility)
|
5
|
+
* Prevent render loops when template names are absolute paths
|
6
|
+
* Ensure RubyParser is passed file path as a String
|
7
|
+
* Support new Haml 5.2.0 escaping method
|
8
|
+
|
9
|
+
# 4.10.0 - 2020-09-28
|
10
|
+
|
11
|
+
* Add SARIF report format (Steve Winton)
|
12
|
+
|
13
|
+
# 4.9.1 - 2020-09-04
|
14
|
+
|
15
|
+
* Check `chomp`ed strings for SQL injection
|
16
|
+
* Use version from `active_record` for non-Rails apps (Ulysse Buonomo)
|
17
|
+
* Always set line number for joined arrays
|
18
|
+
* Avoid warning about missing `attr_accessible` if `protected_attributes` gem is used
|
19
|
+
|
20
|
+
# 4.9.0 - 2020-08-04
|
21
|
+
|
22
|
+
* Add check for CVE-2020-8166 (Jamie Finnigan)
|
23
|
+
* Avoid warning when `safe_yaml` is used via `YAML.load(..., safe: true)`
|
24
|
+
* Add check for user input in `ERB.new` (Matt Hickman)
|
25
|
+
* Add `--ensure-ignore-notes` (Eli Block)
|
26
|
+
* Remove whitelist/blacklist language, add clarifications
|
27
|
+
* Do not warn about mass assignment with `params.permit!.slice`
|
28
|
+
* Add "full call" information to call index results
|
29
|
+
* Ignore `params.permit!` in path helpers
|
30
|
+
* Treat `Dir.glob` as safe source of values in guards
|
31
|
+
* Always scan `environment.rb`
|
32
|
+
|
33
|
+
# 4.8.2 - 2020-05-12
|
34
|
+
|
35
|
+
* Add check for CVE-2020-8159
|
36
|
+
* Fix `authenticate_or_request_with_http_basic` check for passed blocks (Hugo Corbucci)
|
37
|
+
* Add `--text-fields` option
|
38
|
+
* Add check for escaping HTML entities in JSON configuration
|
39
|
+
|
1
40
|
# 4.8.1 - 2020-04-06
|
2
41
|
|
3
42
|
* Check SQL query strings using `String#strip` or `String.squish`
|
data/README.md
CHANGED
data/lib/brakeman.rb
CHANGED
@@ -20,6 +20,10 @@ module Brakeman
|
|
20
20
|
#option is set
|
21
21
|
Errors_Found_Exit_Code = 7
|
22
22
|
|
23
|
+
#Exit code returned when an ignored warning has no note and
|
24
|
+
#--ensure-ignore-notes is set
|
25
|
+
Empty_Ignore_Note_Exit_Code = 8
|
26
|
+
|
23
27
|
@debug = false
|
24
28
|
@quiet = false
|
25
29
|
@loaded_dependencies = []
|
@@ -233,6 +237,8 @@ module Brakeman
|
|
233
237
|
[:to_table]
|
234
238
|
when :junit, :to_junit
|
235
239
|
[:to_junit]
|
240
|
+
when :sarif, :to_sarif
|
241
|
+
[:to_sarif]
|
236
242
|
else
|
237
243
|
[:to_text]
|
238
244
|
end
|
@@ -262,6 +268,8 @@ module Brakeman
|
|
262
268
|
:to_table
|
263
269
|
when /\.junit$/i
|
264
270
|
:to_junit
|
271
|
+
when /\.sarif$/i
|
272
|
+
:to_sarif
|
265
273
|
else
|
266
274
|
:to_text
|
267
275
|
end
|
@@ -498,6 +506,18 @@ module Brakeman
|
|
498
506
|
end
|
499
507
|
end
|
500
508
|
|
509
|
+
# Returns an array of alert fingerprints for any ignored warnings without
|
510
|
+
# notes found in the specified ignore file (if it exists).
|
511
|
+
def self.ignore_file_entries_with_empty_notes file
|
512
|
+
return [] unless file
|
513
|
+
|
514
|
+
require 'brakeman/report/ignore/config'
|
515
|
+
|
516
|
+
config = IgnoreConfig.new(file, nil)
|
517
|
+
config.read_from_file
|
518
|
+
config.already_ignored_entries_with_empty_notes.map { |i| i[:fingerprint] }
|
519
|
+
end
|
520
|
+
|
501
521
|
def self.filter_warnings tracker, options
|
502
522
|
require 'brakeman/report/ignore/config'
|
503
523
|
|
@@ -467,7 +467,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
467
467
|
end
|
468
468
|
|
469
469
|
def gemfile_or_environment gem_name = :rails
|
470
|
-
if gem_name and info = tracker.config.get_gem(gem_name)
|
470
|
+
if gem_name and info = tracker.config.get_gem(gem_name.to_sym)
|
471
471
|
info
|
472
472
|
elsif @app_tree.exists?("Gemfile")
|
473
473
|
@app_tree.file_path "Gemfile"
|
@@ -57,6 +57,8 @@ class Brakeman::CheckBasicAuth < Brakeman::BaseCheck
|
|
57
57
|
|
58
58
|
# Check if the block of a result contains a comparison of password to string
|
59
59
|
def include_password_literal? result
|
60
|
+
return false if result[:block_args].nil?
|
61
|
+
|
60
62
|
@password_var = result[:block_args].last
|
61
63
|
@include_password = false
|
62
64
|
process result[:block]
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'brakeman/checks/base_check'
|
2
|
+
|
3
|
+
class Brakeman::CheckCSRFTokenForgeryCVE < Brakeman::BaseCheck
|
4
|
+
Brakeman::Checks.add self
|
5
|
+
|
6
|
+
@description = "Checks for versions with CSRF token forgery vulnerability (CVE-2020-8166)"
|
7
|
+
|
8
|
+
def run_check
|
9
|
+
fix_version = case
|
10
|
+
when version_between?('0.0.0', '5.2.4.2')
|
11
|
+
'5.2.4.3'
|
12
|
+
when version_between?('6.0.0', '6.0.3')
|
13
|
+
'6.0.3.1'
|
14
|
+
else
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
if fix_version
|
19
|
+
warn :warning_type => "Cross-Site Request Forgery",
|
20
|
+
:warning_code => :CVE_2020_8166,
|
21
|
+
:message => msg(msg_version(rails_version), " has a vulnerability that may allow CSRF token forgery. Upgrade to ", msg_version(fix_version), " or patch"),
|
22
|
+
:confidence => :medium,
|
23
|
+
:gem_info => gemfile_or_environment,
|
24
|
+
:link => "https://groups.google.com/g/rubyonrails-security/c/NOjKiGeXUgw"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -13,7 +13,23 @@ class Brakeman::CheckDeserialize < Brakeman::BaseCheck
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def check_yaml
|
16
|
-
check_methods :YAML, :
|
16
|
+
check_methods :YAML, :load_documents, :load_stream, :parse_documents, :parse_stream
|
17
|
+
|
18
|
+
# Check for safe_yaml gem use with YAML.load(..., safe: true)
|
19
|
+
if uses_safe_yaml?
|
20
|
+
tracker.find_call(target: :YAML, method: :load).each do |result|
|
21
|
+
call = result[:call]
|
22
|
+
options = call.second_arg
|
23
|
+
|
24
|
+
if hash? options and true? hash_access(options, :safe)
|
25
|
+
next
|
26
|
+
else
|
27
|
+
check_deserialize result, :YAML
|
28
|
+
end
|
29
|
+
end
|
30
|
+
else
|
31
|
+
check_methods :YAML, :load
|
32
|
+
end
|
17
33
|
end
|
18
34
|
|
19
35
|
def check_csv
|
@@ -102,4 +118,8 @@ class Brakeman::CheckDeserialize < Brakeman::BaseCheck
|
|
102
118
|
|
103
119
|
false
|
104
120
|
end
|
121
|
+
|
122
|
+
def uses_safe_yaml?
|
123
|
+
tracker.config.has_gem? :safe_yaml
|
124
|
+
end
|
105
125
|
end
|
@@ -208,7 +208,7 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
208
208
|
if node_type? e, :if
|
209
209
|
# If we're in a conditional, evaluate the `then` and `else` clauses to
|
210
210
|
# see if they're dangerous.
|
211
|
-
if res = dangerous?(e.
|
211
|
+
if res = dangerous?(e.sexp_body.sexp_body)
|
212
212
|
return res
|
213
213
|
end
|
214
214
|
elsif node_type? e, :or, :evstr, :dstr
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'brakeman/checks/base_check'
|
2
|
+
|
3
|
+
class Brakeman::CheckJSONEntityEscape < Brakeman::BaseCheck
|
4
|
+
Brakeman::Checks.add self
|
5
|
+
|
6
|
+
@description = "Check if HTML escaping is disabled for JSON output"
|
7
|
+
|
8
|
+
def run_check
|
9
|
+
check_config_setting
|
10
|
+
check_manual_disable
|
11
|
+
end
|
12
|
+
|
13
|
+
def check_config_setting
|
14
|
+
if false? tracker.config.rails.dig(:active_support, :escape_html_entities_in_json)
|
15
|
+
warn :warning_type => "Cross-Site Scripting",
|
16
|
+
:warning_code => :json_html_escape_config,
|
17
|
+
:message => msg("HTML entities in JSON are not escaped by default"),
|
18
|
+
:confidence => :medium,
|
19
|
+
:file => "config/environments/production.rb",
|
20
|
+
:line => 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def check_manual_disable
|
25
|
+
tracker.find_call(targets: [:ActiveSupport, :'ActiveSupport::JSON::Encoding'], method: :escape_html_entities_in_json=).each do |result|
|
26
|
+
setting = result[:call].first_arg
|
27
|
+
|
28
|
+
if false? setting
|
29
|
+
warn :result => result,
|
30
|
+
:warning_type => "Cross-Site Scripting",
|
31
|
+
:warning_code => :json_html_escape_module,
|
32
|
+
:message => msg("HTML entities in JSON are not escaped by default"),
|
33
|
+
:confidence => :medium,
|
34
|
+
:file => "config/environments/production.rb"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -160,12 +160,27 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
|
|
160
160
|
# Look for and warn about uses of Parameters#permit! for mass assignment
|
161
161
|
def check_permit!
|
162
162
|
tracker.find_call(:method => :permit!, :nested => true).each do |result|
|
163
|
-
if params? result[:call].target
|
164
|
-
|
163
|
+
if params? result[:call].target
|
164
|
+
unless inside_safe_method? result or calls_slice? result
|
165
|
+
warn_on_permit! result
|
166
|
+
end
|
165
167
|
end
|
166
168
|
end
|
167
169
|
end
|
168
170
|
|
171
|
+
# Ignore blah_some_path(params.permit!)
|
172
|
+
def inside_safe_method? result
|
173
|
+
parent_call = result.dig(:parent, :call)
|
174
|
+
|
175
|
+
call? parent_call and
|
176
|
+
parent_call.method.match(/_path$/)
|
177
|
+
end
|
178
|
+
|
179
|
+
def calls_slice? result
|
180
|
+
result[:chain].include? :slice or
|
181
|
+
(result[:full_call] and result[:full_call][:chain].include? :slice)
|
182
|
+
end
|
183
|
+
|
169
184
|
# Look for actual use of params in mass assignment to avoid
|
170
185
|
# warning about uses of Parameters#permit! without any mass assignment
|
171
186
|
# or when mass assignment is restricted by model instead.
|
@@ -191,7 +206,7 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
|
|
191
206
|
warn :result => result,
|
192
207
|
:warning_type => "Mass Assignment",
|
193
208
|
:warning_code => :mass_assign_permit!,
|
194
|
-
:message =>
|
209
|
+
:message => msg('Specify exact keys allowed for mass assignment instead of using ', msg_code('permit!'), ' which allows any keys'),
|
195
210
|
:confidence => confidence
|
196
211
|
end
|
197
212
|
|
@@ -203,7 +218,7 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
|
|
203
218
|
warn :result => result,
|
204
219
|
:warning_type => "Mass Assignment",
|
205
220
|
:warning_code => :mass_assign_permit_all,
|
206
|
-
:message =>
|
221
|
+
:message => msg('Mass assignment is globally enabled. Disable and specify exact keys using ', msg_code('params.permit'), ' instead'),
|
207
222
|
:confidence => :high
|
208
223
|
end
|
209
224
|
end
|
@@ -8,7 +8,7 @@ require 'brakeman/checks/base_check'
|
|
8
8
|
class Brakeman::CheckModelAttrAccessible < Brakeman::BaseCheck
|
9
9
|
Brakeman::Checks.add self
|
10
10
|
|
11
|
-
@description = "Reports models which have dangerous attributes defined
|
11
|
+
@description = "Reports models which have dangerous attributes defined via attr_accessible"
|
12
12
|
|
13
13
|
SUSP_ATTRS = [
|
14
14
|
[:admin, :high], # Very dangerous unless some Rails authorization used
|
@@ -8,7 +8,7 @@ class Brakeman::CheckModelAttributes < Brakeman::BaseCheck
|
|
8
8
|
@description = "Reports models which do not use attr_restricted and warns on models that use attr_protected"
|
9
9
|
|
10
10
|
def run_check
|
11
|
-
return if mass_assign_disabled?
|
11
|
+
return if mass_assign_disabled? or tracker.config.has_gem?(:protected_attributes)
|
12
12
|
|
13
13
|
#Roll warnings into one warning for all models
|
14
14
|
if tracker.options[:collapse_mass_assignment]
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'brakeman/checks/base_check'
|
2
|
+
|
3
|
+
class Brakeman::CheckPageCachingCVE < Brakeman::BaseCheck
|
4
|
+
Brakeman::Checks.add self
|
5
|
+
|
6
|
+
@description = "Check for page caching vulnerability (CVE-2020-8159)"
|
7
|
+
|
8
|
+
def run_check
|
9
|
+
gem_name = 'actionpack-page_caching'
|
10
|
+
gem_version = tracker.config.gem_version(gem_name.to_sym)
|
11
|
+
upgrade_version = '1.2.2'
|
12
|
+
cve = 'CVE-2020-8159'
|
13
|
+
|
14
|
+
return unless gem_version and version_between?('0.0.0', '1.2.1', gem_version)
|
15
|
+
|
16
|
+
message = msg("Directory traversal vulnerability in ", msg_version(gem_version, gem_name), " ", msg_cve(cve), ". Upgrade to ", msg_version(upgrade_version, gem_name))
|
17
|
+
|
18
|
+
if uses_caches_page?
|
19
|
+
confidence = :high
|
20
|
+
else
|
21
|
+
confidence = :weak
|
22
|
+
end
|
23
|
+
|
24
|
+
warn :warning_type => 'Directory Traversal',
|
25
|
+
:warning_code => :CVE_2020_8159,
|
26
|
+
:message => message,
|
27
|
+
:confidence => confidence,
|
28
|
+
:link_path => 'https://groups.google.com/d/msg/rubyonrails-security/CFRVkEytdP8/c5gmICECAgAJ',
|
29
|
+
:gem_info => gemfile_or_environment(gem_name)
|
30
|
+
end
|
31
|
+
|
32
|
+
def uses_caches_page?
|
33
|
+
tracker.controllers.any? do |name, controller|
|
34
|
+
controller.options.has_key? :caches_page
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -3,7 +3,7 @@ require 'brakeman/checks/base_check'
|
|
3
3
|
class Brakeman::CheckPermitAttributes < Brakeman::BaseCheck
|
4
4
|
Brakeman::Checks.add self
|
5
5
|
|
6
|
-
@description = "Warn on potentially dangerous attributes
|
6
|
+
@description = "Warn on potentially dangerous attributes allowed via permit"
|
7
7
|
|
8
8
|
SUSPICIOUS_KEYS = {
|
9
9
|
admin: :high,
|
@@ -4,8 +4,8 @@ require 'brakeman/checks/base_check'
|
|
4
4
|
#
|
5
5
|
# skip_before_filter :verify_authenticity_token, :except => [...]
|
6
6
|
#
|
7
|
-
#which is essentially a
|
8
|
-
#ones listed) versus a
|
7
|
+
#which is essentially a skip-by-default approach (no actions are checked EXCEPT the
|
8
|
+
#ones listed) versus a enforce-by-default approach (ONLY the actions listed will skip
|
9
9
|
#the check)
|
10
10
|
class Brakeman::CheckSkipBeforeFilter < Brakeman::BaseCheck
|
11
11
|
Brakeman::Checks.add self
|
@@ -26,7 +26,7 @@ class Brakeman::CheckSkipBeforeFilter < Brakeman::BaseCheck
|
|
26
26
|
warn :class => controller.name, #ugh this should be a controller warning, too
|
27
27
|
:warning_type => "Cross-Site Request Forgery",
|
28
28
|
:warning_code => :csrf_blacklist,
|
29
|
-
:message => msg("
|
29
|
+
:message => msg("List specific actions (", msg_code(":only => [..]"), ") when skipping CSRF check"),
|
30
30
|
:code => filter,
|
31
31
|
:confidence => :medium,
|
32
32
|
:file => controller.file
|
@@ -35,7 +35,7 @@ class Brakeman::CheckSkipBeforeFilter < Brakeman::BaseCheck
|
|
35
35
|
warn :controller => controller.name,
|
36
36
|
:warning_code => :auth_blacklist,
|
37
37
|
:warning_type => "Authentication",
|
38
|
-
:message => msg("
|
38
|
+
:message => msg("List specific actions (", msg_code(":only => [..]"), ") when skipping authentication"),
|
39
39
|
:code => filter,
|
40
40
|
:confidence => :medium,
|
41
41
|
:link_path => "authentication_whitelist",
|
@@ -393,7 +393,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
393
393
|
nil
|
394
394
|
end
|
395
395
|
|
396
|
-
TO_STRING_METHODS = [:to_s, :squish, :strip, :strip_heredoc]
|
396
|
+
TO_STRING_METHODS = [:chomp, :to_s, :squish, :strip, :strip_heredoc]
|
397
397
|
|
398
398
|
#Returns value if interpolated value is not something safe
|
399
399
|
def unsafe_string_interp? exp
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'brakeman/checks/base_check'
|
2
|
+
|
3
|
+
class Brakeman::CheckTemplateInjection < Brakeman::BaseCheck
|
4
|
+
Brakeman::Checks.add self
|
5
|
+
|
6
|
+
@description = "Searches for evaluation of user input through template injection"
|
7
|
+
|
8
|
+
#Process calls
|
9
|
+
def run_check
|
10
|
+
Brakeman.debug "Finding ERB.new calls"
|
11
|
+
erb_calls = tracker.find_call :target => :ERB, :method => :new, :nested => true
|
12
|
+
|
13
|
+
Brakeman.debug "Processing ERB.new calls"
|
14
|
+
erb_calls.each do |call|
|
15
|
+
process_result call
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
#Warns if eval includes user input
|
20
|
+
def process_result result
|
21
|
+
return unless original? result
|
22
|
+
|
23
|
+
if input = include_user_input?(result[:call].arglist)
|
24
|
+
warn :result => result,
|
25
|
+
:warning_type => "Template Injection",
|
26
|
+
:warning_code => :erb_template_injection,
|
27
|
+
:message => msg(msg_input(input), " used directly in ", msg_code("ERB"), " template, which might enable remote code execution"),
|
28
|
+
:user_input => input,
|
29
|
+
:confidence => :high
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|