Module: Contrast::Agent::Assess::Policy::TriggerValidation::SSRFValidator

Defined in:
lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb

Overview

Validator used to assert a SSRF finding is actually vulnerable before serializing that finding as a DTM to report to the TeamServer.

Constant Summary collapse

RULE_NAME =
'ssrf'
URL_PATTERN =

rubocop:disable Layout/LineLength

%r{(?<protocol>http|https|ftp|sftp|telnet|gopher|rtsp|rtsps|ssh|svn)://(?<host>[^/?]+)(?<path>/?[^?]*)(?<query_string>\?.*)?}i.cs__freeze
PATH_ONLY_PATCH_MARKER =

The Net::HTTP class validates host format on instantiation. Since our triggers for that class are on the instance, they already have this validation done for them. We do not need to apply the validation in this case.

'Assess:Trigger:Net::HTTP#'

Class Method Summary collapse

Class Method Details

.valid?(patcher, _object, _ret, args) ⇒ Boolean

A finding is valid for SSRF if the source of the trigger event is a valid URL in which the User controls a section prior to the querystring bitbucket.org/contrastsecurity/assess-specifications/src/master/rules/dataflow/server_side_request_forgery.md

Parameters:

  • patcher (Contrast::Agent::Patcher)

    the patcher instance

  • _object (Object)

    the object that was called

  • _ret (Object)

    the return value of the method

  • args (Array<Object>)

    the arguments passed to the method

Returns:

  • (Boolean)

    true if the finding is valid, false otherwise



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb', line 30

def self.valid? patcher, _object, _ret, args
  return true if patcher.id.to_s.start_with?(PATH_ONLY_PATCH_MARKER)

  url = args[0].to_s
  match = url.match(URL_PATTERN)
  return false unless match

  # It is dangerous for the user to control a section of the URL
  # between the start of the protocol and the beginning of the
  # querystring. If there is no path, then the entire URL is
  # dangerous for the User to control.
  start = match.begin(:protocol)
  finish = match.begin(:path)
  finish ||= url.length

  properties = Contrast::Agent::Assess::Tracker.properties(args[0])
  properties&.any_tags_between?(start, finish)
end