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.
- checksums.yaml +4 -4
- data/ext/cs__assess_array/cs__assess_array.c +1 -1
- data/ext/cs__assess_module/cs__assess_module.c +0 -1
- data/ext/cs__assess_yield_track/cs__assess_yield_track.c +34 -0
- data/ext/cs__assess_yield_track/cs__assess_yield_track.h +12 -0
- data/ext/{cs__scope → cs__assess_yield_track}/extconf.rb +0 -0
- data/ext/cs__common/cs__common.c +6 -6
- data/ext/cs__common/cs__common.h +3 -1
- data/ext/cs__contrast_patch/cs__contrast_patch.c +142 -119
- data/ext/cs__contrast_patch/cs__contrast_patch.h +3 -0
- data/funchook/autom4te.cache/requests +48 -48
- data/funchook/config.log +2 -2
- data/lib/contrast/agent.rb +15 -5
- data/lib/contrast/agent/assess.rb +0 -1
- data/lib/contrast/agent/assess/contrast_event.rb +9 -8
- data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +68 -18
- data/lib/contrast/agent/assess/policy/policy.rb +0 -14
- data/lib/contrast/agent/assess/policy/policy_scanner.rb +1 -1
- data/lib/contrast/agent/assess/policy/preshift.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagation_method.rb +4 -2
- data/lib/contrast/agent/assess/policy/propagator/custom.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/splat.rb +2 -2
- data/lib/contrast/agent/assess/policy/propagator/split.rb +166 -1
- data/lib/contrast/agent/assess/policy/rewriter_patch.rb +1 -0
- data/lib/contrast/agent/assess/policy/source_method.rb +199 -140
- data/lib/contrast/agent/assess/policy/source_validation/cross_site_validator.rb +30 -0
- data/lib/contrast/agent/assess/policy/source_validation/source_validation.rb +36 -0
- data/lib/contrast/agent/assess/policy/trigger_method.rb +238 -153
- data/lib/contrast/agent/assess/policy/trigger_node.rb +54 -9
- data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +13 -0
- data/lib/contrast/agent/assess/properties.rb +29 -0
- data/lib/contrast/agent/assess/rule/csrf/csrf_applicator.rb +35 -31
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +1 -1
- data/lib/contrast/agent/class_reopener.rb +98 -55
- data/lib/contrast/agent/feature_state.rb +1 -1
- data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
- data/lib/contrast/agent/logger_manager.rb +2 -2
- data/lib/contrast/agent/middleware.rb +1 -3
- data/lib/contrast/agent/patching/policy/after_load_patch.rb +40 -4
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +33 -8
- data/lib/contrast/agent/patching/policy/method_policy.rb +20 -7
- data/lib/contrast/agent/patching/policy/patch.rb +54 -23
- data/lib/contrast/agent/patching/policy/patch_status.rb +0 -2
- data/lib/contrast/agent/patching/policy/patcher.rb +10 -11
- data/lib/contrast/agent/patching/policy/policy.rb +4 -0
- data/lib/contrast/agent/patching/policy/policy_node.rb +14 -1
- data/lib/contrast/agent/patching/policy/trigger_node.rb +2 -1
- data/lib/contrast/agent/protect/policy/policy.rb +6 -6
- data/lib/contrast/agent/protect/rule/base.rb +1 -1
- data/lib/contrast/agent/protect/rule/deserialization.rb +3 -25
- data/lib/contrast/agent/protect/rule/sqli.rb +1 -1
- data/lib/contrast/agent/railtie.rb +11 -5
- data/lib/contrast/agent/request.rb +1 -19
- data/lib/contrast/agent/request_context.rb +1 -1
- data/lib/contrast/agent/rewriter.rb +4 -3
- data/lib/contrast/agent/scope.rb +116 -19
- data/lib/contrast/agent/service_heartbeat.rb +5 -2
- data/lib/contrast/agent/settings_state.rb +12 -8
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/api.rb +1 -0
- data/lib/contrast/api/speedracer.rb +2 -2
- data/lib/contrast/components/agent.rb +26 -7
- data/lib/contrast/components/app_context.rb +8 -45
- data/lib/contrast/components/contrast_service.rb +3 -4
- data/lib/contrast/components/interface.rb +1 -1
- data/lib/contrast/components/scope.rb +56 -26
- data/lib/contrast/config/ruby_configuration.rb +8 -3
- data/lib/contrast/delegators.rb +9 -0
- data/lib/contrast/delegators/application_update.rb +32 -0
- data/lib/contrast/extensions/framework/rack/cookie.rb +24 -0
- data/lib/contrast/extensions/framework/rack/request.rb +24 -0
- data/lib/contrast/extensions/framework/rack/response.rb +23 -0
- data/lib/contrast/extensions/framework/rails/action_controller_railties_helper_inherited.rb +20 -0
- data/lib/contrast/extensions/framework/rails/active_record.rb +26 -0
- data/lib/contrast/extensions/framework/rails/active_record_named.rb +53 -0
- data/lib/contrast/extensions/framework/rails/active_record_time_zone_inherited.rb +21 -0
- data/lib/contrast/extensions/framework/rails/buffer.rb +28 -0
- data/lib/contrast/extensions/framework/rails/configuration.rb +27 -0
- data/lib/contrast/extensions/framework/sinatra/base.rb +59 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess.rb +12 -11
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/array.rb +4 -3
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/assess_extension.rb +0 -2
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/basic_object.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/erb.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/exec_trigger.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/fiber.rb +3 -4
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/hash.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/kernel.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/module.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/regexp.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/string.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/tilt_template_trigger.rb +0 -0
- data/lib/contrast/extensions/ruby_core/assess/xpath_library_trigger.rb +40 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/delegator.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/eval_trigger.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/inventory.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/inventory/datastores.rb +1 -1
- data/lib/contrast/extensions/ruby_core/module.rb +17 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_command_injection_rule.rb +8 -6
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_deserialization_rule.rb +7 -5
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_no_sqli_rule.rb +5 -3
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_path_traversal_rule.rb +31 -27
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_sqli_rule.rb +5 -3
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_xxe_rule.rb +9 -7
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/kernel.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/psych.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/thread.rb +0 -0
- data/lib/contrast/framework/base_support.rb +63 -0
- data/lib/contrast/framework/manager.rb +109 -0
- data/lib/contrast/framework/platform_version.rb +21 -0
- data/lib/contrast/framework/rails_support.rb +88 -0
- data/lib/contrast/framework/sinatra_application_helper.rb +49 -0
- data/lib/contrast/framework/sinatra_support.rb +94 -0
- data/lib/contrast/framework/view_technologies_descriptor.rb +20 -0
- data/lib/contrast/utils/assess/tracking_util.rb +2 -4
- data/lib/contrast/utils/class_util.rb +92 -37
- data/lib/contrast/utils/duck_utils.rb +59 -39
- data/lib/contrast/utils/environment_util.rb +5 -75
- data/lib/contrast/utils/freeze_util.rb +3 -7
- data/lib/contrast/utils/invalid_configuration_util.rb +5 -5
- data/lib/contrast/utils/job_servers_running.rb +39 -0
- data/lib/contrast/utils/ruby_ast_rewriter.rb +2 -2
- data/lib/contrast/utils/service_response_util.rb +0 -6
- data/lib/contrast/utils/sinatra_helper.rb +6 -0
- data/lib/contrast/utils/stack_trace_utils.rb +1 -1
- data/resources/assess/policy.json +74 -23
- data/resources/inventory/policy.json +1 -1
- data/resources/protect/policy.json +11 -9
- data/resources/rubocops/object/frozen_cop.rb +1 -1
- data/ruby-agent.gemspec +2 -0
- data/service_executables/VERSION +1 -1
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- metadata +94 -57
- data/ext/cs__scope/cs__scope.c +0 -96
- data/ext/cs__scope/cs__scope.h +0 -33
- data/lib/contrast/agent/assess/class_reverter.rb +0 -82
- data/lib/contrast/agent/patching/policy/policy_unpatcher.rb +0 -28
- data/lib/contrast/core_extensions/module.rb +0 -42
- data/lib/contrast/core_extensions/object.rb +0 -27
- data/lib/contrast/rails_extensions/assess/action_controller_inheritance.rb +0 -48
- data/lib/contrast/rails_extensions/assess/active_record.rb +0 -32
- data/lib/contrast/rails_extensions/assess/active_record_named.rb +0 -61
- data/lib/contrast/rails_extensions/assess/configuration.rb +0 -26
- data/lib/contrast/rails_extensions/buffer.rb +0 -30
- data/lib/contrast/rails_extensions/rack.rb +0 -45
- data/lib/contrast/sinatra_extensions/assess/cookie.rb +0 -26
- data/lib/contrast/sinatra_extensions/inventory/sinatra_base.rb +0 -59
- data/lib/contrast/utils/operating_environment.rb +0 -38
- data/lib/contrast/utils/path_util.rb +0 -151
- 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/
|
|
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/
|
|
38
|
+
cs__scoped_require 'contrast/extensions/ruby_core/assess/string'
|
|
39
39
|
|
|
40
|
-
cs__scoped_require 'contrast/
|
|
41
|
-
cs__scoped_require 'contrast/
|
|
42
|
-
cs__scoped_require 'contrast/
|
|
43
|
-
cs__scoped_require 'contrast/
|
|
44
|
-
cs__scoped_require 'contrast/
|
|
45
|
-
cs__scoped_require 'contrast/
|
|
46
|
-
cs__scoped_require 'contrast/
|
|
47
|
-
cs__scoped_require 'contrast/
|
|
48
|
-
cs__scoped_require 'contrast/
|
|
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' => '
|
|
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
|
|
33
|
-
return ret if Contrast::Agent::Patching::Policy::
|
|
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/
|
|
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
|
|
File without changes
|
|
File without changes
|
|
@@ -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
|
|
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.
|
|
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.
|
|
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?
|
|
File without changes
|
|
@@ -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/
|
|
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/
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -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
|
|
File without changes
|
|
@@ -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.
|
|
31
|
+
Contrast::Agent::Assess::Policy::TriggerMethod.apply_eval_trigger(
|
|
32
32
|
current_context,
|
|
33
33
|
trigger_node(clazz, method),
|
|
34
34
|
source,
|
|
File without changes
|
|
@@ -20,7 +20,7 @@ module Contrast
|
|
|
20
20
|
# report.
|
|
21
21
|
DATA_STORE_MARKER = 'data_store'
|
|
22
22
|
|
|
23
|
-
def
|
|
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]
|