contrast-agent 3.8.5 → 3.9.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.
Files changed (153) hide show
  1. checksums.yaml +4 -4
  2. data/ext/cs__assess_array/cs__assess_array.c +1 -1
  3. data/ext/cs__assess_module/cs__assess_module.c +0 -1
  4. data/ext/cs__assess_yield_track/cs__assess_yield_track.c +34 -0
  5. data/ext/cs__assess_yield_track/cs__assess_yield_track.h +12 -0
  6. data/ext/{cs__scope → cs__assess_yield_track}/extconf.rb +0 -0
  7. data/ext/cs__common/cs__common.c +6 -6
  8. data/ext/cs__common/cs__common.h +3 -1
  9. data/ext/cs__contrast_patch/cs__contrast_patch.c +142 -119
  10. data/ext/cs__contrast_patch/cs__contrast_patch.h +3 -0
  11. data/funchook/autom4te.cache/requests +48 -48
  12. data/funchook/config.log +2 -2
  13. data/lib/contrast/agent.rb +15 -5
  14. data/lib/contrast/agent/assess.rb +0 -1
  15. data/lib/contrast/agent/assess/contrast_event.rb +9 -8
  16. data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +68 -18
  17. data/lib/contrast/agent/assess/policy/policy.rb +0 -14
  18. data/lib/contrast/agent/assess/policy/policy_scanner.rb +1 -1
  19. data/lib/contrast/agent/assess/policy/preshift.rb +1 -1
  20. data/lib/contrast/agent/assess/policy/propagation_method.rb +4 -2
  21. data/lib/contrast/agent/assess/policy/propagator/custom.rb +1 -1
  22. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +1 -1
  23. data/lib/contrast/agent/assess/policy/propagator/splat.rb +2 -2
  24. data/lib/contrast/agent/assess/policy/propagator/split.rb +166 -1
  25. data/lib/contrast/agent/assess/policy/rewriter_patch.rb +1 -0
  26. data/lib/contrast/agent/assess/policy/source_method.rb +199 -140
  27. data/lib/contrast/agent/assess/policy/source_validation/cross_site_validator.rb +30 -0
  28. data/lib/contrast/agent/assess/policy/source_validation/source_validation.rb +36 -0
  29. data/lib/contrast/agent/assess/policy/trigger_method.rb +238 -153
  30. data/lib/contrast/agent/assess/policy/trigger_node.rb +54 -9
  31. data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +13 -0
  32. data/lib/contrast/agent/assess/properties.rb +29 -0
  33. data/lib/contrast/agent/assess/rule/csrf/csrf_applicator.rb +35 -31
  34. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +1 -1
  35. data/lib/contrast/agent/class_reopener.rb +98 -55
  36. data/lib/contrast/agent/feature_state.rb +1 -1
  37. data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
  38. data/lib/contrast/agent/logger_manager.rb +2 -2
  39. data/lib/contrast/agent/middleware.rb +1 -3
  40. data/lib/contrast/agent/patching/policy/after_load_patch.rb +40 -4
  41. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +33 -8
  42. data/lib/contrast/agent/patching/policy/method_policy.rb +20 -7
  43. data/lib/contrast/agent/patching/policy/patch.rb +54 -23
  44. data/lib/contrast/agent/patching/policy/patch_status.rb +0 -2
  45. data/lib/contrast/agent/patching/policy/patcher.rb +10 -11
  46. data/lib/contrast/agent/patching/policy/policy.rb +4 -0
  47. data/lib/contrast/agent/patching/policy/policy_node.rb +14 -1
  48. data/lib/contrast/agent/patching/policy/trigger_node.rb +2 -1
  49. data/lib/contrast/agent/protect/policy/policy.rb +6 -6
  50. data/lib/contrast/agent/protect/rule/base.rb +1 -1
  51. data/lib/contrast/agent/protect/rule/deserialization.rb +3 -25
  52. data/lib/contrast/agent/protect/rule/sqli.rb +1 -1
  53. data/lib/contrast/agent/railtie.rb +11 -5
  54. data/lib/contrast/agent/request.rb +1 -19
  55. data/lib/contrast/agent/request_context.rb +1 -1
  56. data/lib/contrast/agent/rewriter.rb +4 -3
  57. data/lib/contrast/agent/scope.rb +116 -19
  58. data/lib/contrast/agent/service_heartbeat.rb +5 -2
  59. data/lib/contrast/agent/settings_state.rb +12 -8
  60. data/lib/contrast/agent/version.rb +1 -1
  61. data/lib/contrast/api.rb +1 -0
  62. data/lib/contrast/api/speedracer.rb +2 -2
  63. data/lib/contrast/components/agent.rb +26 -7
  64. data/lib/contrast/components/app_context.rb +8 -45
  65. data/lib/contrast/components/contrast_service.rb +3 -4
  66. data/lib/contrast/components/interface.rb +1 -1
  67. data/lib/contrast/components/scope.rb +56 -26
  68. data/lib/contrast/config/ruby_configuration.rb +8 -3
  69. data/lib/contrast/delegators.rb +9 -0
  70. data/lib/contrast/delegators/application_update.rb +32 -0
  71. data/lib/contrast/extensions/framework/rack/cookie.rb +24 -0
  72. data/lib/contrast/extensions/framework/rack/request.rb +24 -0
  73. data/lib/contrast/extensions/framework/rack/response.rb +23 -0
  74. data/lib/contrast/extensions/framework/rails/action_controller_railties_helper_inherited.rb +20 -0
  75. data/lib/contrast/extensions/framework/rails/active_record.rb +26 -0
  76. data/lib/contrast/extensions/framework/rails/active_record_named.rb +53 -0
  77. data/lib/contrast/extensions/framework/rails/active_record_time_zone_inherited.rb +21 -0
  78. data/lib/contrast/extensions/framework/rails/buffer.rb +28 -0
  79. data/lib/contrast/extensions/framework/rails/configuration.rb +27 -0
  80. data/lib/contrast/extensions/framework/sinatra/base.rb +59 -0
  81. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess.rb +12 -11
  82. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/array.rb +4 -3
  83. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/assess_extension.rb +0 -2
  84. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/basic_object.rb +1 -1
  85. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/erb.rb +0 -0
  86. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/exec_trigger.rb +0 -0
  87. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/fiber.rb +3 -4
  88. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/hash.rb +0 -0
  89. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/kernel.rb +1 -1
  90. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/module.rb +1 -1
  91. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/regexp.rb +0 -0
  92. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/string.rb +0 -0
  93. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/tilt_template_trigger.rb +0 -0
  94. data/lib/contrast/extensions/ruby_core/assess/xpath_library_trigger.rb +40 -0
  95. data/lib/contrast/{core_extensions → extensions/ruby_core}/delegator.rb +0 -0
  96. data/lib/contrast/{core_extensions → extensions/ruby_core}/eval_trigger.rb +1 -1
  97. data/lib/contrast/{core_extensions → extensions/ruby_core}/inventory.rb +0 -0
  98. data/lib/contrast/{core_extensions → extensions/ruby_core}/inventory/datastores.rb +1 -1
  99. data/lib/contrast/extensions/ruby_core/module.rb +17 -0
  100. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect.rb +0 -0
  101. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_command_injection_rule.rb +8 -6
  102. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_deserialization_rule.rb +7 -5
  103. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_no_sqli_rule.rb +5 -3
  104. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_path_traversal_rule.rb +31 -27
  105. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_sqli_rule.rb +5 -3
  106. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_xxe_rule.rb +9 -7
  107. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/kernel.rb +0 -0
  108. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/psych.rb +1 -1
  109. data/lib/contrast/{core_extensions → extensions/ruby_core}/thread.rb +0 -0
  110. data/lib/contrast/framework/base_support.rb +63 -0
  111. data/lib/contrast/framework/manager.rb +109 -0
  112. data/lib/contrast/framework/platform_version.rb +21 -0
  113. data/lib/contrast/framework/rails_support.rb +88 -0
  114. data/lib/contrast/framework/sinatra_application_helper.rb +49 -0
  115. data/lib/contrast/framework/sinatra_support.rb +94 -0
  116. data/lib/contrast/framework/view_technologies_descriptor.rb +20 -0
  117. data/lib/contrast/utils/assess/tracking_util.rb +2 -4
  118. data/lib/contrast/utils/class_util.rb +92 -37
  119. data/lib/contrast/utils/duck_utils.rb +59 -39
  120. data/lib/contrast/utils/environment_util.rb +5 -75
  121. data/lib/contrast/utils/freeze_util.rb +3 -7
  122. data/lib/contrast/utils/invalid_configuration_util.rb +5 -5
  123. data/lib/contrast/utils/job_servers_running.rb +39 -0
  124. data/lib/contrast/utils/ruby_ast_rewriter.rb +2 -2
  125. data/lib/contrast/utils/service_response_util.rb +0 -6
  126. data/lib/contrast/utils/sinatra_helper.rb +6 -0
  127. data/lib/contrast/utils/stack_trace_utils.rb +1 -1
  128. data/resources/assess/policy.json +74 -23
  129. data/resources/inventory/policy.json +1 -1
  130. data/resources/protect/policy.json +11 -9
  131. data/resources/rubocops/object/frozen_cop.rb +1 -1
  132. data/ruby-agent.gemspec +2 -0
  133. data/service_executables/VERSION +1 -1
  134. data/service_executables/linux/contrast-service +0 -0
  135. data/service_executables/mac/contrast-service +0 -0
  136. metadata +94 -57
  137. data/ext/cs__scope/cs__scope.c +0 -96
  138. data/ext/cs__scope/cs__scope.h +0 -33
  139. data/lib/contrast/agent/assess/class_reverter.rb +0 -82
  140. data/lib/contrast/agent/patching/policy/policy_unpatcher.rb +0 -28
  141. data/lib/contrast/core_extensions/module.rb +0 -42
  142. data/lib/contrast/core_extensions/object.rb +0 -27
  143. data/lib/contrast/rails_extensions/assess/action_controller_inheritance.rb +0 -48
  144. data/lib/contrast/rails_extensions/assess/active_record.rb +0 -32
  145. data/lib/contrast/rails_extensions/assess/active_record_named.rb +0 -61
  146. data/lib/contrast/rails_extensions/assess/configuration.rb +0 -26
  147. data/lib/contrast/rails_extensions/buffer.rb +0 -30
  148. data/lib/contrast/rails_extensions/rack.rb +0 -45
  149. data/lib/contrast/sinatra_extensions/assess/cookie.rb +0 -26
  150. data/lib/contrast/sinatra_extensions/inventory/sinatra_base.rb +0 -59
  151. data/lib/contrast/utils/operating_environment.rb +0 -38
  152. data/lib/contrast/utils/path_util.rb +0 -151
  153. data/lib/contrast/utils/scope_util.rb +0 -99
@@ -0,0 +1,20 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ module ActionController
5
+ module Railties
6
+ # Used to monkey patch all the inherited calls in action_pack
7
+ #
8
+ # This is the usual entry point for Rails inheritance work, so it should
9
+ # catch most of the calls to inherited.
10
+ module Helpers
11
+ alias_method :cs__patched_inherited, :inherited
12
+ def inherited klass
13
+ klass&.instance_variable_set(:@cs__defining_class, true)
14
+ cs__patched_inherited(klass)
15
+ ensure
16
+ klass&.instance_variable_set(:@cs__defining_class, false)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ module ActiveRecord
5
+ module AttributeMethods
6
+ module Read
7
+ # Rails / ActiveRecord are sneaky a.f. They define attributes of a
8
+ # class in one method, then monkey patch allocate in another and
9
+ # finally invoke module_eval in this method... but of course they use a
10
+ # '_tmp_' header for the method name and then alias it in this module
11
+ # to name it what we expect
12
+ module ClassMethods
13
+ alias_method :cs__patched_define_method_attribute, :define_method_attribute
14
+
15
+ def define_method_attribute *args, &block
16
+ ret = cs__patched_define_method_attribute(*args, &block)
17
+ method_name = args[0]
18
+ Contrast::Agent::Assess::Policy::Patcher.patch_assess_method(self, method_name)
19
+ ret
20
+ end
21
+
22
+ protected :cs__patched_define_method_attribute, :define_method_attribute
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,53 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ cs__scoped_require 'contrast/components/interface'
5
+
6
+ module ActiveRecord
7
+ module Scoping
8
+ module Named
9
+ # Our patch into the ActiveRecord::Scoping::Named::ClassMethods Module,
10
+ # allowing for the runtime rewrite of interpolation calls defined in
11
+ # methods defined dynamically during application execution.
12
+ #
13
+ # TODO: RUBY-534
14
+ module ClassMethods
15
+ include Contrast::Components::Interface
16
+ access_component :logging, :agent
17
+
18
+ def _cs__rewrite method_name, body
19
+ return body unless AGENT.rewrite_interpolation?
20
+ return body unless body.is_a?(Proc)
21
+
22
+ location = body.source_location
23
+ return body if location.nil?
24
+
25
+ # Good news, once we patch the body once, the source location
26
+ # becomes eval. We may need to fix this later though (so it may
27
+ # be bad news)
28
+ return body if location.empty? || location[0].empty? || location[0].include?('eval')
29
+
30
+ opener = Contrast::Agent::ClassReopener.new(Contrast::Agent::ModuleData.new(self))
31
+ original_source_code = opener.source_code(location, method_name)
32
+ return body unless original_source_code
33
+ return body if Contrast::Agent::Rewriter.send(:unrepeatable?, original_source_code)
34
+ return body unless Contrast::Agent::Rewriter.send(:interpolations?, original_source_code)
35
+
36
+ # the code looks like 'source :some_method_name, ->lambda_literal'
37
+ # we just need the lambda
38
+ body_start = original_source_code.index(',') + 1
39
+ original_source_code = original_source_code[body_start..-1]
40
+
41
+ new_method_source = Contrast::Agent::Rewriter.send(:rewrite_method, original_source_code)
42
+ return body unless Contrast::Agent::Rewriter.send(:valid_code?, new_method_source)
43
+
44
+ unbound_eval(cs__name, new_method_source)
45
+ rescue SyntaxError, StandardError => e
46
+ logger.debug(e, "Can't parse method source in scoped method #{ method_name }: #{ e.message }")
47
+ body
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ cs__scoped_require 'cs__assess_active_record_named/cs__assess_active_record_named'
@@ -0,0 +1,21 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ module ActiveRecord
5
+ module AttributeMethods
6
+ # Used to monkey patch all the inherited calls in action_pack
7
+ module TimeZoneConversion
8
+ module ClassMethods #:nodoc:
9
+ private
10
+
11
+ alias_method :cs__patched_inherited, :inherited
12
+ def inherited klass
13
+ klass&.instance_variable_set(:@cs__defining_class, true)
14
+ cs__patched_inherited(klass)
15
+ ensure
16
+ klass&.instance_variable_set(:@cs__defining_class, false)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ cs__scoped_require 'contrast/components/interface'
5
+
6
+ module ActionController
7
+ module Live
8
+ # This class acts as our patch into the ActionController::Live::Buffer
9
+ # class, allowing us to track the close event on streamed responses.
10
+ class Buffer
11
+ include Contrast::Components::Interface
12
+ access_component :contrast_service
13
+
14
+ # normally pre->in->post filters are applied however, in a streamed response
15
+ # we can run into a case where it's pre -> in -> post -> more infilters
16
+ # in order to submit anything found during the infilters after the response has been written we need to explicity send them
17
+ alias_method :cs__close, :close
18
+ def close
19
+ if (context = Contrast::Agent::REQUEST_TRACKER.current)
20
+ [context.server_activity, context.activity, context.observed_route].each do |msg|
21
+ CONTRAST_SERVICE.send_message msg
22
+ end
23
+ end
24
+ cs__close
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ module Rails
5
+ class Application
6
+ # Our patch into the Rails::Application::Configuration Class, allowing
7
+ # for the runtime detection of insecure configurations on individual
8
+ # ActionDispatch::Session::AbstractStore instances within the
9
+ # application.
10
+ class Configuration
11
+ include Contrast::Utils::InvalidConfigurationUtil
12
+ include Contrast::Components::Interface
13
+
14
+ # Note to self / PR reviewers / wizard people dear reader,
15
+ # including the components into Rails here may be unnecessary
16
+ # if we're not calling anything besides #analyze_session_store?
17
+ access_component :analysis, :scope
18
+
19
+ alias_method :cs__patched_session_store, :session_store
20
+ def session_store *args
21
+ ret = cs__patched_session_store(*args)
22
+ Contrast::Utils::RailsAssessConfiguration.analyze_session_store(*args)
23
+ ret
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,59 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ cs__scoped_require 'contrast/framework/sinatra_support'
5
+
6
+ module Sinatra
7
+ # Our patch into the Sinatra::Base Class, allowing for the inventory of the
8
+ # routes called by the application
9
+ class Base
10
+ alias_method :cs__patched_call!, :call!
11
+
12
+ # publicly available method for Sinatra::Base things -- unfortunately,
13
+ # getting the routes appear to require a lookup every time
14
+ def call! *args
15
+ cs__patched_map_route(*args)
16
+ cs__patched_call!(*args)
17
+ end
18
+
19
+ private
20
+
21
+ # Use logic copied from Sinatra::Base#process_route to determine which
22
+ # pattern matches the request being invoked by Sinatra::Base#call!
23
+ #
24
+ # @param args [Array<Object>] we rely on the @settings object in
25
+ # Sinatra::Base and the env variable passed in as args[0]
26
+ def cs__patched_map_route *args
27
+ context = Contrast::Agent::REQUEST_TRACKER.current
28
+ return unless context
29
+
30
+ env = args[0]
31
+ return unless env
32
+
33
+ # There isn't a Request object in the Sinatra::Base yet - it's made
34
+ # during the #call! method, which we're patching - so we need to
35
+ # access the env
36
+ method = env[Rack::REQUEST_METHOD]
37
+ route = env[Rack::PATH_INFO]
38
+ route = route.to_s
39
+
40
+ # get all potential routes for this request type
41
+ routes = settings.routes[method]
42
+ return unless routes
43
+
44
+ # Do some cleanup that matches Sinatra::Base#process_route
45
+ route = '/' if route.empty? && !settings.empty_path_info?
46
+ route = route[0..-2] if !settings.strict_paths? && route != '/' && route.end_with?('/')
47
+
48
+ # Find the route that matches this request. Since we're using
49
+ # settings, we should resolve in the same precedence as Sinatra
50
+ routes.each do |pattern, _, _| # Mustermann::Sinatra
51
+ next unless pattern.params(route)
52
+
53
+ dtm = Contrast::Framework::SinatraSupport.send(:route_to_coverage, cs__class, method, pattern)
54
+ context.append_route_coverage(dtm)
55
+ break
56
+ end
57
+ end
58
+ end
59
+ end
@@ -32,20 +32,21 @@ module Contrast
32
32
 
33
33
  # classes that don't play nice w/ our standard propagation
34
34
  cs__scoped_require 'contrast/agent/assess/frozen_properties'
35
- cs__scoped_require 'contrast/core_extensions/assess/assess_extension'
35
+ cs__scoped_require 'contrast/extensions/ruby_core/assess/assess_extension'
36
36
  # this needs to come first b/c array and others work on strings and
37
37
  # expect them to be trackable
38
- cs__scoped_require 'contrast/core_extensions/assess/string'
38
+ cs__scoped_require 'contrast/extensions/ruby_core/assess/string'
39
39
 
40
- cs__scoped_require 'contrast/core_extensions/assess/array'
41
- cs__scoped_require 'contrast/core_extensions/assess/erb'
42
- cs__scoped_require 'contrast/core_extensions/assess/fiber'
43
- cs__scoped_require 'contrast/core_extensions/assess/hash'
44
- cs__scoped_require 'contrast/core_extensions/assess/kernel'
45
- cs__scoped_require 'contrast/core_extensions/assess/regexp'
46
- cs__scoped_require 'contrast/core_extensions/assess/module'
47
- cs__scoped_require 'contrast/core_extensions/assess/basic_object'
48
- cs__scoped_require 'contrast/core_extensions/assess/tilt_template_trigger'
40
+ cs__scoped_require 'contrast/extensions/ruby_core/assess/array'
41
+ cs__scoped_require 'contrast/extensions/ruby_core/assess/erb'
42
+ cs__scoped_require 'contrast/extensions/ruby_core/assess/fiber'
43
+ cs__scoped_require 'contrast/extensions/ruby_core/assess/hash'
44
+ cs__scoped_require 'contrast/extensions/ruby_core/assess/kernel'
45
+ cs__scoped_require 'contrast/extensions/ruby_core/assess/regexp'
46
+ cs__scoped_require 'contrast/extensions/ruby_core/assess/module'
47
+ cs__scoped_require 'contrast/extensions/ruby_core/assess/basic_object'
48
+ cs__scoped_require 'contrast/extensions/ruby_core/assess/tilt_template_trigger'
49
+ cs__scoped_require 'contrast/extensions/ruby_core/assess/xpath_library_trigger'
49
50
  end
50
51
  end
51
52
  end
@@ -1,6 +1,7 @@
1
1
  # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
+ cs__scoped_require 'contrast/agent/patching/policy/patch'
4
5
  cs__scoped_require 'contrast/agent/patching/policy/patcher'
5
6
  cs__scoped_require 'contrast/components/interface'
6
7
 
@@ -21,7 +22,7 @@ class Array
21
22
  'source' => 'O',
22
23
  'target' => 'R',
23
24
  'patch_class' => 'NOOP',
24
- 'patch_method' => '__cs_track_join'
25
+ 'patch_method' => 'cs__track_join'
25
26
  }.cs__freeze
26
27
  ARRAY_JOIN_NODE = Contrast::Agent::Assess::Policy::PropagationNode.new(ARRAY_JOIN_HASH)
27
28
 
@@ -29,8 +30,8 @@ class Array
29
30
  # Multiple Strings are appended with the #join method. Because that
30
31
  # operation happens in C, we have to do it here rather than rely on the
31
32
  # patch of our String append or concat methods.
32
- def __cs_track_join separator, ret
33
- return ret if Contrast::Agent::Patching::Policy::Patcher.skip_assess_analysis?
33
+ def cs__track_join separator, ret
34
+ return ret if Contrast::Agent::Patching::Policy::Patch.skip_assess_analysis?
34
35
 
35
36
  with_contrast_scope do
36
37
  shift = 0
@@ -14,8 +14,6 @@ module Contrast
14
14
  # dataflow features should be sent
15
15
  # 'include Contrast::CoreExtensions::Assess::AssessExtension'
16
16
  module AssessExtension
17
- include Contrast::Utils::ScopeUtil
18
-
19
17
  # Lazily build properties object. Only objects that have been tracked
20
18
  # will have the @_cs__properties, but all will respond to the
21
19
  # cs__properties method call. You should only call this method if you
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
- cs__scoped_require 'contrast/core_extensions/eval_trigger'
4
+ cs__scoped_require 'contrast/extensions/ruby_core/eval_trigger'
5
5
  cs__scoped_require 'contrast/agent/patching/policy/patcher'
6
6
 
7
7
  # Our patch into the BasicObject class, allowing us to track calls to the eval
@@ -50,13 +50,12 @@ class Fiber
50
50
  def track_rb_fiber_yield fiber, _method, results
51
51
  # results will be nil if StopIteration was raised,
52
52
  # otherwise an Array of the yielded arguments
53
- return if results.nil?
54
-
53
+ return unless results.cs__is_a?(Array)
55
54
  return unless ASSESS.enabled?
56
55
 
57
56
  with_contrast_scope do
58
57
  results.each do |result|
59
- next unless Contrast::Utils::DuckUtils.quacks_like_cs_patched?(result)
58
+ next unless Contrast::Utils::DuckUtils.trackable?(result)
60
59
  next if result.cs__frozen?
61
60
 
62
61
  cs__splat_tags(result, fiber)
@@ -71,7 +70,7 @@ class Fiber
71
70
  end
72
71
 
73
72
  def track_rb_fiber_new fiber, _enum, _enum_method, underlying, _underlying_method
74
- return unless Contrast::Utils::DuckUtils.quacks_like_cs_patched?(underlying)
73
+ return unless Contrast::Utils::DuckUtils.trackable?(underlying)
75
74
  return unless underlying.is_a?(String) && !underlying.empty?
76
75
 
77
76
  return unless ASSESS.enabled?
@@ -2,7 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  cs__scoped_require 'contrast/components/interface'
5
- cs__scoped_require 'contrast/core_extensions/assess/exec_trigger'
5
+ cs__scoped_require 'contrast/extensions/ruby_core/assess/exec_trigger'
6
6
 
7
7
  # This module provides us with a way to invoke Kernel propagation for those
8
8
  # methods which are too complex to fit into one of the standard
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
- cs__scoped_require 'contrast/core_extensions/eval_trigger'
4
+ cs__scoped_require 'contrast/extensions/ruby_core/eval_trigger'
5
5
 
6
6
  # Our patch into the Module class, allowing us to track calls to the eval
7
7
  # method
@@ -0,0 +1,40 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ cs__scoped_require 'contrast/components/interface'
5
+ # This module acts a trigger to handle the special cases of the XPath library gem
6
+ # and the Oga gem. Untrusted data may come into either of the trigger methods from
7
+ # these classes as an array or hash, respectively. Since untrusted user input comes
8
+ # into these triggers as a splat argument or an options hash, we need to iterate
9
+ # thorugh these objects to see if we were tracking on any of them and report a finding
10
+ # if so.
11
+ module XPathLibraryTrigger
12
+ include Contrast::Components::Interface
13
+
14
+ class << self
15
+ def xpath_trigger_check context, trigger_node, _source, object, ret, invoked, *args
16
+ return ret unless args
17
+
18
+ # convert the options arg in Oga::XML::CharacterNode#initialize into an
19
+ # array of its values so we can check if any are unsafe
20
+ args = args.first.values if oga_defined? && object.cs__is_a?(Oga::XML::CharacterNode) && args.first.cs__is_a?(Hash)
21
+
22
+ args.each do |arg|
23
+ next unless arg.cs__is_a?(String) || arg.cs__is_a?(Symbol)
24
+ next unless arg.cs__tracked?
25
+ next unless trigger_node.violated?(arg)
26
+
27
+ Contrast::Agent::Assess::Policy::TriggerMethod.build_finding(
28
+ context, trigger_node, arg, object, ret, invoked + 1, args)
29
+ end
30
+
31
+ ret
32
+ end
33
+
34
+ private
35
+
36
+ def oga_defined?
37
+ @_oga_defined ||= defined?(Oga::XML::CharacterNode)
38
+ end
39
+ end
40
+ end
@@ -28,7 +28,7 @@ module Contrast
28
28
  # source might not be all the args passed in, but it is the one we care
29
29
  # about. we could pass in all the args in the last param here if it
30
30
  # becomes an issue in rendering on TS
31
- Contrast::Agent::Assess::Policy::TriggerMethod.cs__apply_trigger(
31
+ Contrast::Agent::Assess::Policy::TriggerMethod.apply_eval_trigger(
32
32
  current_context,
33
33
  trigger_node(clazz, method),
34
34
  source,
@@ -20,7 +20,7 @@ module Contrast
20
20
  # report.
21
21
  DATA_STORE_MARKER = 'data_store'
22
22
 
23
- def cs__patched_report_data_store _method, _exception, properties, object, _args
23
+ def patched_report_data_store _method, _exception, properties, object, _args
24
24
  return unless INVENTORY.enabled?
25
25
 
26
26
  marker = properties[DATA_STORE_MARKER]