lib/contrast/agent/assess/policy/trigger_method.rb in contrast-agent-6.14.0 vs lib/contrast/agent/assess/policy/trigger_method.rb in contrast-agent-6.15.0

- old
+ new

@@ -1,12 +1,13 @@ # Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'contrast/agent/assess/policy/trigger_validation/trigger_validation' -require 'contrast/agent/excluder' +require 'contrast/agent/excluder/excluder' require 'contrast/components/logger' require 'contrast/utils/object_share' +require 'contrast/utils/duck_utils' require 'contrast/utils/sha256_builder' require 'contrast/utils/assess/trigger_method_utils' require 'contrast/agent/assess/events/event_data' require 'contrast/agent/reporting/reporting_events/preflight' require 'contrast/agent/reporting/reporting_events/application_activity' @@ -97,10 +98,11 @@ finding = Contrast::Agent::Reporting::Finding.new(trigger_node.rule_id) finding.attach_data(trigger_node, source, object, ret, request, *args) return if excluded_by_input_and_rule?(request, finding, trigger_node.rule_id) finding.hash_code = Contrast::Utils::HashDigest.generate_event_hash(finding, source, request) + check_for_stored_xss(finding) finding rescue StandardError => e logger.error('Unable to build a finding', e, rule: trigger_node.rule_id, node_id: trigger_node.id) nil end @@ -185,9 +187,42 @@ Contrast::SETTINGS.excluder.assess_excluded_by_url_and_rule?(request, rule_id) end def excluded_by_input_and_rule? request, finding, rule_id Contrast::SETTINGS.excluder.assess_excluded_by_input_and_rule?(request, finding, rule_id) + end + + # Handles the Stored Xss rule. If a vector is stored in the database + def check_for_stored_xss finding + return unless finding && finding.rule_id == 'reflected-xss' + + # Check for database tainted event propagation: + if finding.events.select { |event| event.reportable_tags.include?('DATABASE_WRITE') }. + any? && !Contrast::ASSESS.disabled_rules.include?('stored-xss') + + # Override 'reflected-xss' => 'stored-xss' + finding.instance_variable_set(:@rule_id, 'stored-xss') + extract_dynamic_source_info(finding) + finding + end + end + + def extract_dynamic_source_info finding + return unless finding + + creation_events = finding.events.select { |e| e.action == :CREATION } + source_event_policy = creation_events[0].policy_node if creation_events.any? + properties = source_event_policy.properties if source_event_policy + # Properties example: + # => {"dynamic_source_id"=>"Assess:Source:Comment#message", + # "dynamic_source_name"=>"Comment.message", + # "readTable"=>"Comment", + # "readColumn"=>:message, + # "writeDateTimeUtc"=>1675087341948, + # "writeRequestUrl"=>"/comments"} + return if Contrast::Utils::DuckUtils.empty_duck?(properties) + + finding.instance_variable_set(:@properties, finding.properties.merge(properties)) end end end end end