brakeman-lib 4.4.0 → 4.7.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 +63 -0
- data/README.md +6 -7
- data/lib/brakeman.rb +7 -0
- data/lib/brakeman/app_tree.rb +34 -22
- data/lib/brakeman/call_index.rb +54 -15
- data/lib/brakeman/checks.rb +7 -7
- data/lib/brakeman/checks/base_check.rb +75 -56
- data/lib/brakeman/checks/check_content_tag.rb +12 -0
- data/lib/brakeman/checks/check_cookie_serialization.rb +22 -0
- data/lib/brakeman/checks/check_cross_site_scripting.rb +15 -10
- data/lib/brakeman/checks/check_default_routes.rb +5 -0
- data/lib/brakeman/checks/check_deserialize.rb +49 -0
- data/lib/brakeman/checks/check_dynamic_finders.rb +1 -1
- data/lib/brakeman/checks/check_evaluation.rb +0 -1
- data/lib/brakeman/checks/check_execute.rb +44 -1
- data/lib/brakeman/checks/check_file_access.rb +7 -1
- data/lib/brakeman/checks/check_force_ssl.rb +27 -0
- data/lib/brakeman/checks/check_header_dos.rb +2 -2
- data/lib/brakeman/checks/check_i18n_xss.rb +2 -2
- data/lib/brakeman/checks/check_jruby_xml.rb +2 -2
- data/lib/brakeman/checks/check_json_parsing.rb +7 -2
- data/lib/brakeman/checks/check_link_to_href.rb +6 -1
- data/lib/brakeman/checks/check_mail_to.rb +1 -1
- data/lib/brakeman/checks/check_mime_type_dos.rb +2 -2
- data/lib/brakeman/checks/check_model_attr_accessible.rb +1 -1
- data/lib/brakeman/checks/check_model_attributes.rb +12 -50
- data/lib/brakeman/checks/check_model_serialize.rb +1 -1
- data/lib/brakeman/checks/check_nested_attributes_bypass.rb +4 -4
- data/lib/brakeman/checks/check_reverse_tabnabbing.rb +54 -0
- data/lib/brakeman/checks/check_sanitize_methods.rb +2 -2
- data/lib/brakeman/checks/check_secrets.rb +1 -1
- data/lib/brakeman/checks/check_send.rb +0 -1
- data/lib/brakeman/checks/check_session_manipulation.rb +0 -1
- data/lib/brakeman/checks/check_session_settings.rb +15 -12
- data/lib/brakeman/checks/check_simple_format.rb +5 -0
- data/lib/brakeman/checks/check_skip_before_filter.rb +1 -1
- data/lib/brakeman/checks/check_sql.rb +27 -20
- data/lib/brakeman/checks/check_validation_regex.rb +1 -1
- data/lib/brakeman/checks/check_xml_dos.rb +2 -2
- data/lib/brakeman/checks/check_yaml_parsing.rb +10 -18
- data/lib/brakeman/differ.rb +16 -28
- data/lib/brakeman/file_parser.rb +6 -8
- data/lib/brakeman/file_path.rb +85 -0
- data/lib/brakeman/options.rb +7 -0
- data/lib/brakeman/parsers/haml_embedded.rb +44 -0
- data/lib/brakeman/parsers/slim_embedded.rb +44 -0
- data/lib/brakeman/parsers/template_parser.rb +8 -8
- data/lib/brakeman/processor.rb +4 -5
- data/lib/brakeman/processors/alias_processor.rb +49 -7
- data/lib/brakeman/processors/base_processor.rb +10 -7
- data/lib/brakeman/processors/controller_alias_processor.rb +10 -7
- data/lib/brakeman/processors/controller_processor.rb +9 -13
- data/lib/brakeman/processors/gem_processor.rb +10 -2
- data/lib/brakeman/processors/haml_template_processor.rb +92 -123
- data/lib/brakeman/processors/lib/call_conversion_helper.rb +4 -0
- data/lib/brakeman/processors/lib/find_all_calls.rb +27 -4
- data/lib/brakeman/processors/lib/find_call.rb +3 -64
- data/lib/brakeman/processors/lib/module_helper.rb +8 -8
- data/lib/brakeman/processors/lib/processor_helper.rb +3 -3
- data/lib/brakeman/processors/lib/rails2_config_processor.rb +4 -4
- data/lib/brakeman/processors/lib/rails2_route_processor.rb +2 -2
- data/lib/brakeman/processors/lib/rails3_config_processor.rb +3 -3
- data/lib/brakeman/processors/lib/rails3_route_processor.rb +2 -2
- data/lib/brakeman/processors/lib/render_helper.rb +2 -2
- data/lib/brakeman/processors/lib/render_path.rb +18 -1
- data/lib/brakeman/processors/library_processor.rb +5 -5
- data/lib/brakeman/processors/model_processor.rb +4 -5
- data/lib/brakeman/processors/output_processor.rb +5 -0
- data/lib/brakeman/processors/slim_template_processor.rb +16 -0
- data/lib/brakeman/processors/template_alias_processor.rb +32 -5
- data/lib/brakeman/processors/template_processor.rb +14 -10
- data/lib/brakeman/report.rb +3 -3
- data/lib/brakeman/report/ignore/config.rb +2 -3
- data/lib/brakeman/report/ignore/interactive.rb +2 -2
- data/lib/brakeman/report/pager.rb +1 -0
- data/lib/brakeman/report/report_base.rb +51 -6
- data/lib/brakeman/report/report_codeclimate.rb +3 -3
- data/lib/brakeman/report/report_hash.rb +1 -1
- data/lib/brakeman/report/report_html.rb +2 -2
- data/lib/brakeman/report/report_json.rb +1 -24
- data/lib/brakeman/report/report_table.rb +20 -4
- data/lib/brakeman/report/report_tabs.rb +1 -1
- data/lib/brakeman/report/report_text.rb +2 -2
- data/lib/brakeman/rescanner.rb +13 -12
- data/lib/brakeman/scanner.rb +24 -18
- data/lib/brakeman/tracker.rb +35 -7
- data/lib/brakeman/tracker/collection.rb +4 -3
- data/lib/brakeman/tracker/config.rb +44 -48
- data/lib/brakeman/tracker/constants.rb +2 -1
- data/lib/brakeman/util.rb +18 -147
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +27 -13
- data/lib/brakeman/warning_codes.rb +4 -0
- data/lib/ruby_parser/bm_sexp.rb +1 -1
- data/lib/ruby_parser/bm_sexp_processor.rb +1 -0
- metadata +58 -43
@@ -54,7 +54,7 @@ class Brakeman::CheckModelSerialize < Brakeman::BaseCheck
|
|
54
54
|
confidence = :high
|
55
55
|
end
|
56
56
|
|
57
|
-
warn :model => model
|
57
|
+
warn :model => model,
|
58
58
|
:warning_type => "Remote Code Execution",
|
59
59
|
:warning_code => :CVE_2013_0277,
|
60
60
|
:message => msg("Serialized attributes are vulnerable in ", msg_version(rails_version), ", upgrade to ", msg_version(@upgrade_version), " or patch"),
|
@@ -22,17 +22,17 @@ class Brakeman::CheckNestedAttributesBypass < Brakeman::BaseCheck
|
|
22
22
|
if opts = model.options[:accepts_nested_attributes_for]
|
23
23
|
opts.each do |args|
|
24
24
|
if args.any? { |a| allow_destroy? a } and args.any? { |a| reject_if? a }
|
25
|
-
warn_about_nested_attributes
|
25
|
+
warn_about_nested_attributes model, args
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
def warn_about_nested_attributes
|
32
|
+
def warn_about_nested_attributes model, args
|
33
33
|
message = msg(msg_version(rails_version), " does not call ", msg_code(":reject_if"), " option when ", msg_code(":allow_destroy"), " is ", msg_code("false"), " ", msg_cve("CVE-2015-7577"))
|
34
34
|
|
35
|
-
warn :model =>
|
35
|
+
warn :model => model,
|
36
36
|
:warning_type => "Nested Attributes",
|
37
37
|
:warning_code => :CVE_2015_7577,
|
38
38
|
:message => message,
|
@@ -53,6 +53,6 @@ class Brakeman::CheckNestedAttributesBypass < Brakeman::BaseCheck
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def workaround?
|
56
|
-
tracker.
|
56
|
+
tracker.find_call(method: :will_be_destroyed?).any?
|
57
57
|
end
|
58
58
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'brakeman/checks/base_check'
|
2
|
+
|
3
|
+
class Brakeman::CheckReverseTabnabbing < Brakeman::BaseCheck
|
4
|
+
Brakeman::Checks.add_optional self
|
5
|
+
|
6
|
+
@description = "Checks for reverse tabnabbing cases on 'link_to' calls"
|
7
|
+
|
8
|
+
def run_check
|
9
|
+
calls = tracker.find_call :methods => :link_to
|
10
|
+
calls.each do |call|
|
11
|
+
process_result call
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def process_result result
|
16
|
+
return unless original? result and result[:call].last_arg
|
17
|
+
|
18
|
+
html_opts = result[:call].last_arg
|
19
|
+
return unless hash? html_opts
|
20
|
+
|
21
|
+
target = hash_access html_opts, :target
|
22
|
+
return unless target && string?(target) && target.value == "_blank"
|
23
|
+
|
24
|
+
target_url = result[:block] ? result[:call].first_arg : result[:call].second_arg
|
25
|
+
|
26
|
+
# `url_for` and `_path` calls lead to urls on to the same origin.
|
27
|
+
# That means that an adversary would need to run javascript on
|
28
|
+
# the victim application's domain. If that is the case, the adversary
|
29
|
+
# already has the ability to redirect the victim user anywhere.
|
30
|
+
# Also statically provided URLs (interpolated or otherwise) are also
|
31
|
+
# ignored as they produce many false positives.
|
32
|
+
return if !call?(target_url) || target_url.method.match(/^url_for$|_path$/)
|
33
|
+
|
34
|
+
rel = hash_access html_opts, :rel
|
35
|
+
confidence = :medium
|
36
|
+
|
37
|
+
if rel && string?(rel) then
|
38
|
+
rel_opt = rel.value
|
39
|
+
return if rel_opt.include?("noopener") && rel_opt.include?("noreferrer")
|
40
|
+
|
41
|
+
if rel_opt.include?("noopener") ^ rel_opt.include?("noreferrer") then
|
42
|
+
confidence = :weak
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
warn :result => result,
|
47
|
+
:warning_type => "Reverse Tabnabbing",
|
48
|
+
:warning_code => :reverse_tabnabbing,
|
49
|
+
:message => msg("When opening a link in a new tab without setting ", msg_code('rel: "noopener noreferrer"'),
|
50
|
+
", the new tab can control the parent tab's location. For example, an attacker could redirect to a phishing page."),
|
51
|
+
:confidence => confidence,
|
52
|
+
:user_input => rel
|
53
|
+
end
|
54
|
+
end
|
@@ -70,7 +70,7 @@ class Brakeman::CheckSanitizeMethods < Brakeman::BaseCheck
|
|
70
70
|
|
71
71
|
def check_cve_2018_8048
|
72
72
|
if loofah_vulnerable_cve_2018_8048?
|
73
|
-
message = msg(msg_version(tracker.config.gem_version(:loofah), "loofah gem"), " is vulnerable (CVE-2018-8048). Upgrade to 2.1
|
73
|
+
message = msg(msg_version(tracker.config.gem_version(:loofah), "loofah gem"), " is vulnerable (CVE-2018-8048). Upgrade to 2.2.1")
|
74
74
|
|
75
75
|
if tracker.find_call(:target => false, :method => :sanitize).any?
|
76
76
|
confidence = :high
|
@@ -90,7 +90,7 @@ class Brakeman::CheckSanitizeMethods < Brakeman::BaseCheck
|
|
90
90
|
def loofah_vulnerable_cve_2018_8048?
|
91
91
|
loofah_version = tracker.config.gem_version(:loofah)
|
92
92
|
|
93
|
-
loofah_version and loofah_version < "2.1
|
93
|
+
loofah_version and loofah_version < "2.2.1"
|
94
94
|
end
|
95
95
|
|
96
96
|
def warn_sanitizer_cve cve, link, upgrade_version
|
@@ -35,6 +35,6 @@ class Brakeman::CheckSecrets < Brakeman::BaseCheck
|
|
35
35
|
|
36
36
|
def looks_like_secret? name
|
37
37
|
# REST_AUTH_SITE_KEY is the pepper in Devise
|
38
|
-
name.match
|
38
|
+
name.match(/password|secret|(rest_auth_site|api)_key$/i)
|
39
39
|
end
|
40
40
|
end
|
@@ -27,7 +27,6 @@ class Brakeman::CheckSessionManipulation < Brakeman::BaseCheck
|
|
27
27
|
:warning_type => "Session Manipulation",
|
28
28
|
:warning_code => :session_key_manipulation,
|
29
29
|
:message => msg(msg_input(input), " used as key in session hash"),
|
30
|
-
:code => result[:call],
|
31
30
|
:user_input => input,
|
32
31
|
:confidence => confidence
|
33
32
|
end
|
@@ -19,10 +19,13 @@ class Brakeman::CheckSessionSettings < Brakeman::BaseCheck
|
|
19
19
|
def run_check
|
20
20
|
settings = tracker.config.session_settings
|
21
21
|
|
22
|
-
check_for_issues settings, @app_tree.
|
22
|
+
check_for_issues settings, @app_tree.file_path("config/environment.rb")
|
23
23
|
|
24
|
-
|
25
|
-
|
24
|
+
session_store = @app_tree.file_path("config/initializers/session_store.rb")
|
25
|
+
secret_token = @app_tree.file_path("config/initializers/secret_token.rb")
|
26
|
+
|
27
|
+
[session_store, secret_token].each do |file|
|
28
|
+
if tracker.initializers[file] and not ignored? file.basename
|
26
29
|
process tracker.initializers[file]
|
27
30
|
end
|
28
31
|
end
|
@@ -42,13 +45,13 @@ class Brakeman::CheckSessionSettings < Brakeman::BaseCheck
|
|
42
45
|
#in Rails 4.x apps
|
43
46
|
def process_attrasgn exp
|
44
47
|
if not tracker.options[:rails3] and exp.target == @session_settings and exp.method == :session=
|
45
|
-
check_for_issues exp.first_arg, @app_tree.
|
48
|
+
check_for_issues exp.first_arg, @app_tree.file_path("config/initializers/session_store.rb")
|
46
49
|
end
|
47
50
|
|
48
51
|
if tracker.options[:rails3] and settings_target?(exp.target) and
|
49
52
|
(exp.method == :secret_token= or exp.method == :secret_key_base=) and string? exp.first_arg
|
50
53
|
|
51
|
-
warn_about_secret_token exp.line, @app_tree.
|
54
|
+
warn_about_secret_token exp.line, @app_tree.file_path("config/initializers/secret_token.rb")
|
52
55
|
end
|
53
56
|
|
54
57
|
exp
|
@@ -58,7 +61,7 @@ class Brakeman::CheckSessionSettings < Brakeman::BaseCheck
|
|
58
61
|
#in Rails 3.x apps
|
59
62
|
def process_call exp
|
60
63
|
if tracker.options[:rails3] and settings_target?(exp.target) and exp.method == :session_store
|
61
|
-
check_for_rails3_issues exp.second_arg, @app_tree.
|
64
|
+
check_for_rails3_issues exp.second_arg, @app_tree.file_path("config/initializers/session_store.rb")
|
62
65
|
end
|
63
66
|
|
64
67
|
exp
|
@@ -109,10 +112,10 @@ class Brakeman::CheckSessionSettings < Brakeman::BaseCheck
|
|
109
112
|
end
|
110
113
|
|
111
114
|
def check_secrets_yaml
|
112
|
-
secrets_file = "config/secrets.yml"
|
115
|
+
secrets_file = @app_tree.file_path("config/secrets.yml")
|
113
116
|
|
114
|
-
if
|
115
|
-
yaml =
|
117
|
+
if secrets_file.exists? and not ignored? "secrets.yml" and not ignored? "config/*.yml"
|
118
|
+
yaml = secrets_file.read
|
116
119
|
require 'date' # https://github.com/dtao/safe_yaml/issues/80
|
117
120
|
require 'safe_yaml/load'
|
118
121
|
begin
|
@@ -127,7 +130,7 @@ class Brakeman::CheckSessionSettings < Brakeman::BaseCheck
|
|
127
130
|
unless secret.include? "<%="
|
128
131
|
line = yaml.lines.find_index { |l| l.include? secret } + 1
|
129
132
|
|
130
|
-
warn_about_secret_token line, @app_tree.
|
133
|
+
warn_about_secret_token line, @app_tree.file_path(secrets_file)
|
131
134
|
end
|
132
135
|
end
|
133
136
|
end
|
@@ -163,9 +166,9 @@ class Brakeman::CheckSessionSettings < Brakeman::BaseCheck
|
|
163
166
|
|
164
167
|
def ignored? file
|
165
168
|
[".", "config", "config/initializers"].each do |dir|
|
166
|
-
ignore_file = "#{dir}/.gitignore"
|
169
|
+
ignore_file = @app_tree.file_path("#{dir}/.gitignore")
|
167
170
|
if @app_tree.exists? ignore_file
|
168
|
-
input =
|
171
|
+
input = ignore_file.read
|
169
172
|
|
170
173
|
return true if input.include? file
|
171
174
|
end
|
@@ -5,6 +5,11 @@ class Brakeman::CheckSimpleFormat < Brakeman::CheckCrossSiteScripting
|
|
5
5
|
|
6
6
|
@description = "Checks for simple_format XSS vulnerability (CVE-2013-6416) in certain versions"
|
7
7
|
|
8
|
+
def initialize *args
|
9
|
+
super
|
10
|
+
@found_any = false
|
11
|
+
end
|
12
|
+
|
8
13
|
def run_check
|
9
14
|
if version_between? "4.0.0", "4.0.1"
|
10
15
|
@inspect_arguments = true
|
@@ -38,7 +38,7 @@ class Brakeman::CheckSkipBeforeFilter < Brakeman::BaseCheck
|
|
38
38
|
:message => msg("Use whitelist (", msg_code(":only => [..]"), ") when skipping authentication"),
|
39
39
|
:code => filter,
|
40
40
|
:confidence => :medium,
|
41
|
-
:
|
41
|
+
:link_path => "authentication_whitelist",
|
42
42
|
:file => controller.file
|
43
43
|
end
|
44
44
|
end
|
@@ -14,12 +14,15 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
14
14
|
@description = "Check for SQL injection"
|
15
15
|
|
16
16
|
def run_check
|
17
|
-
|
17
|
+
# Avoid reporting `user_input` on silly values when generating warning.
|
18
|
+
# Note that we retroactively find `user_input` inside the "dangerous" value.
|
19
|
+
@safe_input_attributes.merge IGNORE_METHODS_IN_SQL
|
18
20
|
|
19
21
|
@sql_targets = [:average, :calculate, :count, :count_by_sql, :delete_all, :destroy_all,
|
20
22
|
:find_by_sql, :maximum, :minimum, :pluck, :sum, :update_all]
|
21
23
|
@sql_targets.concat [:from, :group, :having, :joins, :lock, :order, :reorder, :where] if tracker.options[:rails3]
|
22
|
-
@sql_targets
|
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
|
+
@sql_targets << :delete_by << :destroy_by if tracker.options[:rails6]
|
23
26
|
|
24
27
|
if version_between?("2.0.0", "3.9.9") or tracker.config.rails_version.nil?
|
25
28
|
@sql_targets << :first << :last << :all
|
@@ -43,6 +46,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
43
46
|
Brakeman.debug "Finding possible SQL calls on models"
|
44
47
|
calls = tracker.find_call(:methods => @sql_targets, :nested => true)
|
45
48
|
|
49
|
+
narrow_targets = [:exists?, :select]
|
46
50
|
calls.concat tracker.find_call(:targets => active_record_models.keys, :methods => narrow_targets, :chained => true)
|
47
51
|
|
48
52
|
Brakeman.debug "Finding possible SQL calls with no target"
|
@@ -68,23 +72,23 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
68
72
|
scope_calls = []
|
69
73
|
|
70
74
|
if version_between?("2.1.0", "3.0.9")
|
71
|
-
ar_scope_calls(:named_scope) do |
|
75
|
+
ar_scope_calls(:named_scope) do |model, args|
|
72
76
|
call = make_call(nil, :named_scope, args).line(args.line)
|
73
|
-
scope_calls << scope_call_hash(call,
|
77
|
+
scope_calls << scope_call_hash(call, model, :named_scope)
|
74
78
|
end
|
75
79
|
elsif version_between?("3.1.0", "9.9.9")
|
76
|
-
ar_scope_calls(:scope) do |
|
80
|
+
ar_scope_calls(:scope) do |model, args|
|
77
81
|
second_arg = args[2]
|
78
82
|
next unless sexp? second_arg
|
79
83
|
|
80
84
|
if second_arg.node_type == :iter and node_type? second_arg.block, :block, :call, :safe_call
|
81
|
-
process_scope_with_block(
|
85
|
+
process_scope_with_block(model, args)
|
82
86
|
elsif call? second_arg
|
83
87
|
call = second_arg
|
84
|
-
scope_calls << scope_call_hash(call,
|
88
|
+
scope_calls << scope_call_hash(call, model, call.method)
|
85
89
|
else
|
86
90
|
call = make_call(nil, :scope, args).line(args.line)
|
87
|
-
scope_calls << scope_call_hash(call,
|
91
|
+
scope_calls << scope_call_hash(call, model, :scope)
|
88
92
|
end
|
89
93
|
end
|
90
94
|
end
|
@@ -93,37 +97,34 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
93
97
|
end
|
94
98
|
|
95
99
|
def ar_scope_calls(symbol_name = :named_scope, &block)
|
96
|
-
return_array = []
|
97
100
|
active_record_models.each do |name, model|
|
98
101
|
model_args = model.options[symbol_name]
|
99
102
|
if model_args
|
100
103
|
model_args.each do |args|
|
101
|
-
yield
|
102
|
-
return_array << [name, args]
|
104
|
+
yield model, args
|
103
105
|
end
|
104
106
|
end
|
105
107
|
end
|
106
|
-
return_array
|
107
108
|
end
|
108
109
|
|
109
|
-
def scope_call_hash(call,
|
110
|
-
{ :call => call, :location => { :type => :class, :class => name }, :method => :named_scope }
|
110
|
+
def scope_call_hash(call, model, method)
|
111
|
+
{ :call => call, :location => { :type => :class, :class => model.name, :file => model.file }, :method => :named_scope }
|
111
112
|
end
|
112
113
|
|
113
114
|
|
114
|
-
def process_scope_with_block
|
115
|
+
def process_scope_with_block model, args
|
115
116
|
scope_name = args[1][1]
|
116
117
|
block = args[-1][-1]
|
117
118
|
|
118
119
|
# Search lambda for calls to query methods
|
119
120
|
if block.node_type == :block
|
120
121
|
find_calls = Brakeman::FindAllCalls.new(tracker)
|
121
|
-
find_calls.process_source(block, :class =>
|
122
|
+
find_calls.process_source(block, :class => model.name, :method => scope_name, :file => model.file)
|
122
123
|
find_calls.calls.each { |call| process_result(call) if @sql_targets.include?(call[:method]) }
|
123
124
|
elsif call? block
|
124
125
|
while call? block
|
125
126
|
process_result :target => block.target, :method => block.method, :call => block,
|
126
|
-
|
127
|
+
:location => { :type => :class, :class => model.name, :method => scope_name, :file => model.file }
|
127
128
|
|
128
129
|
block = block.target
|
129
130
|
end
|
@@ -184,7 +185,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
184
185
|
else
|
185
186
|
check_find_arguments call.last_arg
|
186
187
|
end
|
187
|
-
when :where, :having, :find_by, :find_by!, :not
|
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
|
188
189
|
check_query_arguments call.arglist
|
189
190
|
when :order, :group, :reorder
|
190
191
|
check_order_arguments call.arglist
|
@@ -294,7 +295,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
294
295
|
# Model.where(params[:where])
|
295
296
|
arg
|
296
297
|
end
|
297
|
-
elsif hash? arg
|
298
|
+
elsif hash? arg and not kwsplat? arg
|
298
299
|
#This is generally going to be a hash of column names and values, which
|
299
300
|
#would escape the values. But the keys _could_ be user input.
|
300
301
|
check_hash_keys arg
|
@@ -452,7 +453,13 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
452
453
|
when :dstr
|
453
454
|
check_string_interp exp
|
454
455
|
when :hash
|
455
|
-
|
456
|
+
if kwsplat? exp and has_immediate_user_input? exp
|
457
|
+
exp
|
458
|
+
elsif not ignore_hash
|
459
|
+
check_hash_values exp
|
460
|
+
else
|
461
|
+
nil
|
462
|
+
end
|
456
463
|
when :if
|
457
464
|
unsafe_sql? exp.then_clause or unsafe_sql? exp.else_clause
|
458
465
|
when :call
|
@@ -17,7 +17,7 @@ class Brakeman::CheckValidationRegex < Brakeman::BaseCheck
|
|
17
17
|
|
18
18
|
def run_check
|
19
19
|
active_record_models.each do |name, model|
|
20
|
-
@current_model =
|
20
|
+
@current_model = model
|
21
21
|
format_validations = model.options[:validates_format_of]
|
22
22
|
|
23
23
|
if format_validations
|
@@ -34,8 +34,8 @@ class Brakeman::CheckXMLDoS < Brakeman::BaseCheck
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def has_workaround?
|
37
|
-
tracker.
|
38
|
-
arg = match
|
37
|
+
tracker.find_call(target: :"ActiveSupport::XmlMini", method: :backend=).any? do |match|
|
38
|
+
arg = match[:call].first_arg
|
39
39
|
if string? arg
|
40
40
|
value = arg.value
|
41
41
|
value == 'Nokogiri' or value == 'LibXML'
|
@@ -48,21 +48,17 @@ class Brakeman::CheckYAMLParsing < Brakeman::BaseCheck
|
|
48
48
|
def disabled_xml_parser?
|
49
49
|
if version_between? "0.0.0", "2.3.14"
|
50
50
|
#Look for ActionController::Base.param_parsers.delete(Mime::XML)
|
51
|
-
|
52
|
-
s(:colon2, s(:const, :ActionController), :Base),
|
53
|
-
:param_parsers)
|
54
|
-
|
55
|
-
matches = tracker.check_initializers(params_parser, :delete)
|
51
|
+
matches = tracker.find_call(target: :"ActionController::Base.param_parsers", method: :delete)
|
56
52
|
else
|
57
53
|
#Look for ActionDispatch::ParamsParser::DEFAULT_PARSERS.delete(Mime::XML)
|
58
|
-
matches = tracker.
|
54
|
+
matches = tracker.find_call(target: :"ActionDispatch::ParamsParser::DEFAULT_PARSERS", method: :delete)
|
59
55
|
end
|
60
56
|
|
61
57
|
unless matches.empty?
|
62
58
|
mime_xml = s(:colon2, s(:const, :Mime), :XML)
|
63
59
|
|
64
60
|
matches.each do |result|
|
65
|
-
if result
|
61
|
+
if result[:call].first_arg == mime_xml
|
66
62
|
return true
|
67
63
|
end
|
68
64
|
end
|
@@ -74,18 +70,14 @@ class Brakeman::CheckYAMLParsing < Brakeman::BaseCheck
|
|
74
70
|
#Look for ActionController::Base.param_parsers[Mime::YAML] = :yaml
|
75
71
|
#in Rails 2.x apps
|
76
72
|
def enabled_yaml_parser?
|
77
|
-
|
78
|
-
s(:colon2, s(:const, :ActionController), :Base),
|
79
|
-
:param_parsers)
|
80
|
-
|
81
|
-
matches = tracker.check_initializers(param_parsers, :[]=)
|
73
|
+
matches = tracker.find_call(target: :'ActionController::Base.param_parsers', method: :[]=)
|
82
74
|
|
83
75
|
mime_yaml = s(:colon2, s(:const, :Mime), :YAML)
|
84
76
|
|
85
77
|
matches.each do |result|
|
86
|
-
if result
|
87
|
-
symbol? result
|
88
|
-
result
|
78
|
+
if result[:call].first_arg == mime_yaml and
|
79
|
+
symbol? result[:call].second_arg and
|
80
|
+
result[:call].second_arg.value == :yaml
|
89
81
|
|
90
82
|
return true
|
91
83
|
end
|
@@ -96,16 +88,16 @@ class Brakeman::CheckYAMLParsing < Brakeman::BaseCheck
|
|
96
88
|
|
97
89
|
def disabled_xml_dangerous_types?
|
98
90
|
if version_between? "0.0.0", "2.3.14"
|
99
|
-
matches = tracker.
|
91
|
+
matches = tracker.find_call(target: :"ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING", method: :delete)
|
100
92
|
else
|
101
|
-
matches = tracker.
|
93
|
+
matches = tracker.find_call(target: :"ActiveSupport::XmlMini::PARSING", method: :delete)
|
102
94
|
end
|
103
95
|
|
104
96
|
symbols_off = false
|
105
97
|
yaml_off = false
|
106
98
|
|
107
99
|
matches.each do |result|
|
108
|
-
arg = result
|
100
|
+
arg = result[:call].first_arg
|
109
101
|
|
110
102
|
if string? arg
|
111
103
|
if arg.value == "yaml"
|