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
@@ -45,6 +45,16 @@ class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
|
|
45
45
|
def process_result result
|
46
46
|
return if duplicate? result
|
47
47
|
|
48
|
+
case result[:location][:type]
|
49
|
+
when :template
|
50
|
+
@current_template = result[:location][:template]
|
51
|
+
when :class
|
52
|
+
@current_class = result[:location][:class]
|
53
|
+
@current_method = result[:location][:method]
|
54
|
+
end
|
55
|
+
|
56
|
+
@current_file = result[:location][:file]
|
57
|
+
|
48
58
|
call = result[:call] = result[:call].dup
|
49
59
|
|
50
60
|
args = call.arglist
|
@@ -85,6 +95,8 @@ class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
|
|
85
95
|
end
|
86
96
|
end
|
87
97
|
end
|
98
|
+
ensure
|
99
|
+
@current_template = @current_class = @current_method = @current_file = nil
|
88
100
|
end
|
89
101
|
|
90
102
|
def check_argument result, exp
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'brakeman/checks/base_check'
|
2
|
+
|
3
|
+
class Brakeman::CheckCookieSerialization < Brakeman::BaseCheck
|
4
|
+
Brakeman::Checks.add self
|
5
|
+
|
6
|
+
@description = "Check for use of Marshal for cookie serialization"
|
7
|
+
|
8
|
+
def run_check
|
9
|
+
tracker.find_call(target: :'Rails.application.config.action_dispatch', method: :cookies_serializer=).each do |result|
|
10
|
+
setting = result[:call].first_arg
|
11
|
+
|
12
|
+
if symbol? setting and [:marshal, :hybrid].include? setting.value
|
13
|
+
warn :result => result,
|
14
|
+
:warning_type => "Remote Code Execution",
|
15
|
+
:warning_code => :unsafe_cookie_serialization,
|
16
|
+
:message => msg("Use of unsafe cookie serialization strategy ", msg_code(setting.value.inspect), " might lead to remote code execution"),
|
17
|
+
:confidence => :medium,
|
18
|
+
:link_path => "unsafe_deserialization"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -33,6 +33,11 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
33
33
|
|
34
34
|
FORM_BUILDER = Sexp.new(:call, Sexp.new(:const, :FormBuilder), :new)
|
35
35
|
|
36
|
+
def initialize *args
|
37
|
+
super
|
38
|
+
@matched = @mark = false
|
39
|
+
end
|
40
|
+
|
36
41
|
#Run check
|
37
42
|
def run_check
|
38
43
|
setup
|
@@ -57,12 +62,12 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
57
62
|
|
58
63
|
if exp.node_type == :output
|
59
64
|
out = exp.value
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
65
|
+
end
|
66
|
+
|
67
|
+
if raw_call? exp
|
68
|
+
out = exp.value.first_arg
|
69
|
+
elsif html_safe_call? exp
|
70
|
+
out = exp.value.target
|
66
71
|
end
|
67
72
|
|
68
73
|
return if call? out and ignore_call? out.target, out.method
|
@@ -282,7 +287,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
282
287
|
|
283
288
|
def setup
|
284
289
|
@ignore_methods = Set[:==, :!=, :button_to, :check_box, :content_tag, :escapeHTML, :escape_once,
|
285
|
-
:field_field, :fields_for, :h, :hidden_field,
|
290
|
+
:field_field, :fields_for, :form_for, :h, :hidden_field,
|
286
291
|
:hidden_field, :hidden_field_tag, :image_tag, :label,
|
287
292
|
:link_to, :mail_to, :radio_button, :select,
|
288
293
|
:submit_tag, :text_area, :text_field,
|
@@ -311,11 +316,11 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
311
316
|
end
|
312
317
|
|
313
318
|
json_escape_on = false
|
314
|
-
initializers = tracker.
|
315
|
-
initializers.each {|result| json_escape_on = true?(result
|
319
|
+
initializers = tracker.find_call(target: :ActiveSupport, method: :escape_html_entities_in_json=)
|
320
|
+
initializers.each {|result| json_escape_on = true?(result[:call].first_arg) }
|
316
321
|
|
317
322
|
if tracker.config.escape_html_entities_in_json?
|
318
|
-
|
323
|
+
json_escape_on = true
|
319
324
|
elsif version_between? "4.0.0", "9.9.9"
|
320
325
|
json_escape_on = true
|
321
326
|
end
|
@@ -6,6 +6,11 @@ class Brakeman::CheckDefaultRoutes < Brakeman::BaseCheck
|
|
6
6
|
|
7
7
|
@description = "Checks for default routes"
|
8
8
|
|
9
|
+
def initialize *args
|
10
|
+
super
|
11
|
+
@actions_allowed_on_controller = nil
|
12
|
+
end
|
13
|
+
|
9
14
|
#Checks for :allow_all_actions globally and for individual routes
|
10
15
|
#if it is not enabled globally.
|
11
16
|
def run_check
|
@@ -9,6 +9,7 @@ class Brakeman::CheckDeserialize < Brakeman::BaseCheck
|
|
9
9
|
check_yaml
|
10
10
|
check_csv
|
11
11
|
check_marshal
|
12
|
+
check_oj
|
12
13
|
end
|
13
14
|
|
14
15
|
def check_yaml
|
@@ -23,6 +24,26 @@ class Brakeman::CheckDeserialize < Brakeman::BaseCheck
|
|
23
24
|
check_methods :Marshal, :load, :restore
|
24
25
|
end
|
25
26
|
|
27
|
+
def check_oj
|
28
|
+
check_methods :Oj, :object_load # Always unsafe, regardless of mode
|
29
|
+
|
30
|
+
unsafe_mode = :object
|
31
|
+
safe_default = oj_safe_default?
|
32
|
+
|
33
|
+
tracker.find_call(:target => :Oj, :method => :load).each do |result|
|
34
|
+
call = result[:call]
|
35
|
+
options = call.second_arg
|
36
|
+
|
37
|
+
if options and hash? options and mode = hash_access(options, :mode)
|
38
|
+
if symbol? mode and mode.value == unsafe_mode
|
39
|
+
check_deserialize result, :Oj
|
40
|
+
end
|
41
|
+
elsif not safe_default
|
42
|
+
check_deserialize result, :Oj
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
26
47
|
def check_methods target, *methods
|
27
48
|
tracker.find_call(:target => target, :methods => methods ).each do |result|
|
28
49
|
check_deserialize result, target
|
@@ -53,4 +74,32 @@ class Brakeman::CheckDeserialize < Brakeman::BaseCheck
|
|
53
74
|
:link_path => "unsafe_deserialization"
|
54
75
|
end
|
55
76
|
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def oj_safe_default?
|
81
|
+
safe_default = false
|
82
|
+
|
83
|
+
if tracker.find_call(target: :Oj, method: :mimic_JSON).any?
|
84
|
+
safe_default = true
|
85
|
+
elsif result = tracker.find_call(target: :Oj, method: :default_options=).first
|
86
|
+
options = result[:call].first_arg
|
87
|
+
|
88
|
+
if oj_safe_mode? options
|
89
|
+
safe_default = true
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
safe_default
|
94
|
+
end
|
95
|
+
|
96
|
+
def oj_safe_mode? options
|
97
|
+
if hash? options and mode = hash_access(options, :mode)
|
98
|
+
if symbol? mode and mode != :object
|
99
|
+
return true
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
false
|
104
|
+
end
|
56
105
|
end
|
@@ -43,6 +43,6 @@ class Brakeman::CheckDynamicFinders < Brakeman::BaseCheck
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def potentially_dangerous? method_name
|
46
|
-
method_name.match
|
46
|
+
method_name.match(/^find_by_.*(token|guid|password|api_key|activation|code|private|reset)/)
|
47
47
|
end
|
48
48
|
end
|
@@ -21,6 +21,10 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
21
21
|
SHELL_ESCAPE_MODULE_METHODS = Set[:escape, :join, :shellescape, :shelljoin]
|
22
22
|
SHELL_ESCAPE_MIXIN_METHODS = Set[:shellescape, :shelljoin]
|
23
23
|
|
24
|
+
# These are common shells that are known to allow the execution of commands
|
25
|
+
# via a -c flag. See dash_c_shell_command? for more info.
|
26
|
+
KNOWN_SHELL_COMMANDS = Set["sh", "bash", "ksh", "csh", "tcsh", "zsh"]
|
27
|
+
|
24
28
|
SHELLWORDS = s(:const, :Shellwords)
|
25
29
|
|
26
30
|
#Check models, controllers, and views for command injection.
|
@@ -42,6 +46,8 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
42
46
|
end
|
43
47
|
end
|
44
48
|
|
49
|
+
private
|
50
|
+
|
45
51
|
#Processes results from Tracker#find_call.
|
46
52
|
def process_result result
|
47
53
|
call = result[:call]
|
@@ -54,7 +60,17 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
54
60
|
failure = include_user_input?(args) || dangerous_interp?(args)
|
55
61
|
end
|
56
62
|
when :system, :exec
|
57
|
-
|
63
|
+
# Normally, if we're in a `system` or `exec` call, we only are worried
|
64
|
+
# about shell injection when there's a single argument, because comma-
|
65
|
+
# separated arguments are always escaped by Ruby. However, an exception is
|
66
|
+
# when the first two arguments are something like "bash -c" because then
|
67
|
+
# the third argument is effectively the command being run and might be
|
68
|
+
# a malicious executable if it comes (partially or fully) from user input.
|
69
|
+
if dash_c_shell_command?(first_arg, call.second_arg)
|
70
|
+
failure = include_user_input?(args[3]) || dangerous_interp?(args[3])
|
71
|
+
else
|
72
|
+
failure = include_user_input?(first_arg) || dangerous_interp?(first_arg)
|
73
|
+
end
|
58
74
|
else
|
59
75
|
failure = include_user_input?(args) || dangerous_interp?(args)
|
60
76
|
end
|
@@ -77,6 +93,15 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
77
93
|
end
|
78
94
|
end
|
79
95
|
|
96
|
+
# @return [Boolean] true iff the command given by `first_arg`, `second_arg`
|
97
|
+
# invokes a new shell process via `<shell_command> -c` (like `bash -c`)
|
98
|
+
def dash_c_shell_command?(first_arg, second_arg)
|
99
|
+
string?(first_arg) &&
|
100
|
+
KNOWN_SHELL_COMMANDS.include?(first_arg.value) &&
|
101
|
+
string?(second_arg) &&
|
102
|
+
second_arg.value == "-c"
|
103
|
+
end
|
104
|
+
|
80
105
|
def check_open_calls
|
81
106
|
tracker.find_call(:targets => [nil, :Kernel], :method => :open).each do |result|
|
82
107
|
if match = dangerous_open_arg?(result[:call].first_arg)
|
@@ -90,6 +115,24 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
90
115
|
end
|
91
116
|
end
|
92
117
|
|
118
|
+
def include_user_input? exp
|
119
|
+
if node_type? exp, :arglist, :dstr, :evstr, :dxstr
|
120
|
+
exp.each_sexp do |e|
|
121
|
+
if res = include_user_input?(e)
|
122
|
+
return res
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
false
|
127
|
+
else
|
128
|
+
if shell_escape? exp
|
129
|
+
false
|
130
|
+
else
|
131
|
+
super exp
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
93
136
|
def dangerous_open_arg? exp
|
94
137
|
if string_interp? exp
|
95
138
|
# Check for input at start of string
|
@@ -32,7 +32,7 @@ class Brakeman::CheckFileAccess < Brakeman::BaseCheck
|
|
32
32
|
|
33
33
|
file_name = call.first_arg
|
34
34
|
|
35
|
-
return if called_on_tempfile?(file_name)
|
35
|
+
return if called_on_tempfile?(file_name) || sanitized?(file_name)
|
36
36
|
|
37
37
|
if match = has_immediate_user_input?(file_name)
|
38
38
|
confidence = :high
|
@@ -71,6 +71,12 @@ class Brakeman::CheckFileAccess < Brakeman::BaseCheck
|
|
71
71
|
call?(file_name) && file_name.target == s(:const, :Tempfile)
|
72
72
|
end
|
73
73
|
|
74
|
+
def sanitized? file
|
75
|
+
call?(file) &&
|
76
|
+
call?(file.target) &&
|
77
|
+
class_name(file.target.target) == :"ActiveStorage::Filename"
|
78
|
+
end
|
79
|
+
|
74
80
|
def temp_file_method? exp
|
75
81
|
if call? exp
|
76
82
|
return true if exp.call_chain.include? :tempfile
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Brakeman::CheckForceSSL < Brakeman::BaseCheck
|
2
|
+
Brakeman::Checks.add_optional self
|
3
|
+
|
4
|
+
@description = "Check that force_ssl setting is enabled in production"
|
5
|
+
|
6
|
+
def run_check
|
7
|
+
return if tracker.config.rails.empty? or tracker.config.rails_version.nil?
|
8
|
+
return if tracker.config.rails_version < "3.1.0"
|
9
|
+
|
10
|
+
force_ssl = tracker.config.rails[:force_ssl]
|
11
|
+
|
12
|
+
if false? force_ssl or force_ssl.nil?
|
13
|
+
line = if sexp? force_ssl
|
14
|
+
force_ssl.line
|
15
|
+
else
|
16
|
+
1
|
17
|
+
end
|
18
|
+
|
19
|
+
warn :warning_type => "Missing Encryption",
|
20
|
+
:warning_code => :force_ssl_disabled,
|
21
|
+
:message => msg("The application does not force use of HTTPS: ", msg_code("config.force_ssl"), " is not enabled"),
|
22
|
+
:confidence => :high,
|
23
|
+
:file => "config/environments/production.rb",
|
24
|
+
:line => line
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -25,7 +25,7 @@ class Brakeman::CheckHeaderDoS < Brakeman::BaseCheck
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def has_workaround?
|
28
|
-
tracker.
|
29
|
-
|
28
|
+
tracker.find_call(target: :ActiveSupport, method: :on_load).any? and
|
29
|
+
tracker.find_call(target: :"ActionView::LookupContext::DetailsKey", method: :class_eval).any?
|
30
30
|
end
|
31
31
|
end
|
@@ -41,8 +41,8 @@ class Brakeman::CheckI18nXSS < Brakeman::BaseCheck
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def has_workaround?
|
44
|
-
tracker.
|
45
|
-
match.
|
44
|
+
tracker.find_call(target: :I18n, method: :const_defined?, chained: true).any? do |match|
|
45
|
+
match[:call].first_arg == s(:lit, :MissingTranslation)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -20,8 +20,8 @@ class Brakeman::CheckJRubyXML < Brakeman::BaseCheck
|
|
20
20
|
end
|
21
21
|
|
22
22
|
#Check for workaround
|
23
|
-
tracker.
|
24
|
-
arg = result
|
23
|
+
tracker.find_call(target: :"ActiveSupport::XmlMini", method: :backend=, chained: true).each do |result|
|
24
|
+
arg = result[:call].first_arg
|
25
25
|
|
26
26
|
return if string? arg and arg.value == "REXML"
|
27
27
|
end
|
@@ -5,6 +5,11 @@ class Brakeman::CheckJSONParsing < Brakeman::BaseCheck
|
|
5
5
|
|
6
6
|
@description = "Checks for JSON parsing vulnerabilities CVE-2013-0333 and CVE-2013-0269"
|
7
7
|
|
8
|
+
def initialize *args
|
9
|
+
super
|
10
|
+
@uses_json_parse = nil
|
11
|
+
end
|
12
|
+
|
8
13
|
def run_check
|
9
14
|
check_cve_2013_0333
|
10
15
|
check_cve_2013_0269
|
@@ -39,13 +44,13 @@ class Brakeman::CheckJSONParsing < Brakeman::BaseCheck
|
|
39
44
|
|
40
45
|
#Check for `ActiveSupport::JSON.backend = "JSONGem"`
|
41
46
|
def uses_gem_backend?
|
42
|
-
matches = tracker.
|
47
|
+
matches = tracker.find_call(target: :'ActiveSupport::JSON', method: :backend=, chained: true)
|
43
48
|
|
44
49
|
unless matches.empty?
|
45
50
|
json_gem = s(:str, "JSONGem")
|
46
51
|
|
47
52
|
matches.each do |result|
|
48
|
-
if result
|
53
|
+
if result[:call].first_arg == json_gem
|
49
54
|
return true
|
50
55
|
end
|
51
56
|
end
|
@@ -34,7 +34,12 @@ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
|
|
34
34
|
#an ignored method call by the code above.
|
35
35
|
call = result[:call] = result[:call].dup
|
36
36
|
@matched = false
|
37
|
-
|
37
|
+
|
38
|
+
url_arg = if result[:block]
|
39
|
+
process call.first_arg
|
40
|
+
else
|
41
|
+
process call.second_arg
|
42
|
+
end
|
38
43
|
|
39
44
|
if check_argument? url_arg
|
40
45
|
url_arg = url_arg.first_arg
|
@@ -24,7 +24,7 @@ class Brakeman::CheckMailTo < Brakeman::BaseCheck
|
|
24
24
|
:warning_code => :CVE_2011_0446,
|
25
25
|
:message => message,
|
26
26
|
:confidence => :high,
|
27
|
-
:gem_info => gemfile_or_environment,
|
27
|
+
:gem_info => gemfile_or_environment, # Probably ignored now
|
28
28
|
:link_path => "https://groups.google.com/d/topic/rubyonrails-security/8CpI7egxX4E/discussion"
|
29
29
|
end
|
30
30
|
end
|
@@ -30,8 +30,8 @@ class Brakeman::CheckMimeTypeDoS < Brakeman::BaseCheck
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def has_workaround?
|
33
|
-
tracker.
|
34
|
-
arg = match
|
33
|
+
tracker.find_call(target: :Mime, method: :const_set).any? do |match|
|
34
|
+
arg = match[:call].first_arg
|
35
35
|
|
36
36
|
symbol? arg and arg.value == :LOOKUP
|
37
37
|
end
|
@@ -25,7 +25,7 @@ class Brakeman::CheckModelAttrAccessible < Brakeman::BaseCheck
|
|
25
25
|
|
26
26
|
SUSP_ATTRS.each do |susp_attr, confidence|
|
27
27
|
if susp_attr.is_a?(Regexp) and susp_attr =~ attribute.to_s or susp_attr == attribute
|
28
|
-
warn :model =>
|
28
|
+
warn :model => model,
|
29
29
|
:file => model.file,
|
30
30
|
:warning_type => "Mass Assignment",
|
31
31
|
:warning_code => :dangerous_attr_accessible,
|
@@ -2,9 +2,6 @@ require 'brakeman/checks/base_check'
|
|
2
2
|
|
3
3
|
#Check if mass assignment is used with models
|
4
4
|
#which inherit from ActiveRecord::Base.
|
5
|
-
#
|
6
|
-
#If tracker.options[:collapse_mass_assignment] is +true+ (default), all models
|
7
|
-
#which do not use attr_accessible will be reported in a single warning
|
8
5
|
class Brakeman::CheckModelAttributes < Brakeman::BaseCheck
|
9
6
|
Brakeman::Checks.add self
|
10
7
|
|
@@ -15,26 +12,19 @@ class Brakeman::CheckModelAttributes < Brakeman::BaseCheck
|
|
15
12
|
|
16
13
|
#Roll warnings into one warning for all models
|
17
14
|
if tracker.options[:collapse_mass_assignment]
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
check_models do |name, model|
|
22
|
-
if model.attr_protected.nil?
|
23
|
-
no_accessible_names << name.to_s
|
24
|
-
elsif not tracker.options[:ignore_attr_protected]
|
25
|
-
protected_names << name.to_s
|
26
|
-
end
|
27
|
-
end
|
15
|
+
Brakeman.notify "[Notice] The `collapse_mass_assignment` option has been removed."
|
16
|
+
end
|
28
17
|
|
29
|
-
|
30
|
-
|
18
|
+
check_models do |name, model|
|
19
|
+
if model.attr_protected.nil?
|
20
|
+
warn :model => model,
|
21
|
+
:file => model.file,
|
22
|
+
:line => model.top_line,
|
31
23
|
:warning_type => "Attribute Restriction",
|
32
24
|
:warning_code => :no_attr_accessible,
|
33
25
|
:message => msg("Mass assignment is not restricted using ", msg_code("attr_accessible")),
|
34
26
|
:confidence => :high
|
35
|
-
|
36
|
-
|
37
|
-
unless protected_names.empty?
|
27
|
+
elsif not tracker.options[:ignore_attr_protected]
|
38
28
|
message, confidence, link = check_for_attr_protected_bypass
|
39
29
|
|
40
30
|
if link
|
@@ -43,41 +33,13 @@ class Brakeman::CheckModelAttributes < Brakeman::BaseCheck
|
|
43
33
|
warning_code = :attr_protected_used
|
44
34
|
end
|
45
35
|
|
46
|
-
warn :model =>
|
36
|
+
warn :model => model,
|
37
|
+
:file => model.file,
|
38
|
+
:line => model.attr_protected.first.line,
|
47
39
|
:warning_type => "Attribute Restriction",
|
48
40
|
:warning_code => warning_code,
|
49
41
|
:message => message,
|
50
|
-
:confidence => confidence
|
51
|
-
:link => link
|
52
|
-
end
|
53
|
-
else #Output one warning per model
|
54
|
-
|
55
|
-
check_models do |name, model|
|
56
|
-
if model.attr_protected.nil?
|
57
|
-
warn :model => name,
|
58
|
-
:file => model.file,
|
59
|
-
:line => model.top_line,
|
60
|
-
:warning_type => "Attribute Restriction",
|
61
|
-
:warning_code => :no_attr_accessible,
|
62
|
-
:message => msg("Mass assignment is not restricted using ", msg_code("attr_accessible")),
|
63
|
-
:confidence => :high
|
64
|
-
elsif not tracker.options[:ignore_attr_protected]
|
65
|
-
message, confidence, link = check_for_attr_protected_bypass
|
66
|
-
|
67
|
-
if link
|
68
|
-
warning_code = :CVE_2013_0276
|
69
|
-
else
|
70
|
-
warning_code = :attr_protected_used
|
71
|
-
end
|
72
|
-
|
73
|
-
warn :model => name,
|
74
|
-
:file => model.file,
|
75
|
-
:line => model.attr_protected.first.line,
|
76
|
-
:warning_type => "Attribute Restriction",
|
77
|
-
:warning_code => warning_code,
|
78
|
-
:message => message,
|
79
|
-
:confidence => confidence
|
80
|
-
end
|
42
|
+
:confidence => confidence
|
81
43
|
end
|
82
44
|
end
|
83
45
|
end
|