contrast-agent 3.16.0 → 4.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -0
  3. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +22 -10
  4. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +4 -3
  5. data/lib/contrast/agent.rb +2 -3
  6. data/lib/contrast/agent/assess/contrast_event.rb +49 -130
  7. data/lib/contrast/agent/assess/contrast_object.rb +51 -0
  8. data/lib/contrast/agent/assess/events/source_event.rb +4 -9
  9. data/lib/contrast/agent/assess/policy/patcher.rb +4 -3
  10. data/lib/contrast/agent/assess/policy/policy_node.rb +31 -59
  11. data/lib/contrast/agent/assess/policy/policy_scanner.rb +17 -6
  12. data/lib/contrast/agent/assess/policy/preshift.rb +3 -3
  13. data/lib/contrast/agent/assess/policy/propagation_method.rb +13 -19
  14. data/lib/contrast/agent/assess/policy/propagation_node.rb +12 -24
  15. data/lib/contrast/agent/assess/policy/propagator/append.rb +1 -2
  16. data/lib/contrast/agent/assess/policy/propagator/center.rb +1 -2
  17. data/lib/contrast/agent/assess/policy/propagator/custom.rb +1 -1
  18. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +1 -3
  19. data/lib/contrast/agent/assess/policy/propagator/insert.rb +1 -2
  20. data/lib/contrast/agent/assess/policy/propagator/keep.rb +1 -2
  21. data/lib/contrast/agent/assess/policy/propagator/match_data.rb +3 -2
  22. data/lib/contrast/agent/assess/policy/propagator/next.rb +1 -2
  23. data/lib/contrast/agent/assess/policy/propagator/prepend.rb +1 -2
  24. data/lib/contrast/agent/assess/policy/propagator/remove.rb +2 -4
  25. data/lib/contrast/agent/assess/policy/propagator/replace.rb +1 -2
  26. data/lib/contrast/agent/assess/policy/propagator/reverse.rb +1 -2
  27. data/lib/contrast/agent/assess/policy/propagator/select.rb +3 -4
  28. data/lib/contrast/agent/assess/policy/propagator/splat.rb +2 -4
  29. data/lib/contrast/agent/assess/policy/propagator/split.rb +73 -117
  30. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +11 -11
  31. data/lib/contrast/agent/assess/policy/propagator/trim.rb +3 -7
  32. data/lib/contrast/agent/assess/policy/source_method.rb +2 -14
  33. data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +5 -8
  34. data/lib/contrast/agent/assess/policy/trigger/xpath.rb +1 -1
  35. data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +1 -1
  36. data/lib/contrast/agent/assess/property/tagged.rb +21 -15
  37. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +3 -2
  38. data/lib/contrast/agent/assess/rule/redos.rb +1 -1
  39. data/lib/contrast/agent/assess/tracker.rb +16 -18
  40. data/lib/contrast/agent/deadzone/policy/deadzone_node.rb +7 -0
  41. data/lib/contrast/agent/inventory.rb +15 -0
  42. data/lib/contrast/agent/inventory/dependencies.rb +50 -0
  43. data/lib/contrast/agent/inventory/dependency_analysis.rb +37 -0
  44. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +104 -0
  45. data/lib/contrast/agent/inventory/gemfile_digest_cache.rb +38 -0
  46. data/lib/contrast/agent/middleware.rb +51 -3
  47. data/lib/contrast/agent/patching/policy/method_policy.rb +1 -1
  48. data/lib/contrast/agent/patching/policy/patch.rb +6 -0
  49. data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +47 -1
  50. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +4 -3
  51. data/lib/contrast/agent/protect/policy/rule_applicator.rb +53 -0
  52. data/lib/contrast/agent/protect/rule/base.rb +63 -14
  53. data/lib/contrast/agent/protect/rule/cmd_injection.rb +12 -28
  54. data/lib/contrast/agent/protect/rule/default_scanner.rb +1 -4
  55. data/lib/contrast/agent/protect/rule/deserialization.rb +4 -1
  56. data/lib/contrast/agent/protect/rule/no_sqli.rb +3 -3
  57. data/lib/contrast/agent/protect/rule/sqli.rb +3 -3
  58. data/lib/contrast/agent/protect/rule/xxe.rb +32 -11
  59. data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +10 -6
  60. data/lib/contrast/agent/reaction_processor.rb +1 -1
  61. data/lib/contrast/agent/request_handler.rb +1 -1
  62. data/lib/contrast/agent/response.rb +5 -5
  63. data/lib/contrast/agent/rewriter.rb +3 -3
  64. data/lib/contrast/agent/scope.rb +81 -55
  65. data/lib/contrast/agent/static_analysis.rb +14 -8
  66. data/lib/contrast/agent/tracepoint_hook.rb +1 -1
  67. data/lib/contrast/agent/version.rb +1 -1
  68. data/lib/contrast/api/decorators.rb +3 -0
  69. data/lib/contrast/api/decorators/address.rb +0 -1
  70. data/lib/contrast/api/decorators/application_update.rb +1 -1
  71. data/lib/contrast/api/decorators/library.rb +54 -0
  72. data/lib/contrast/api/decorators/library_usage_update.rb +31 -0
  73. data/lib/contrast/api/decorators/trace_event.rb +19 -31
  74. data/lib/contrast/api/decorators/trace_event_object.rb +11 -3
  75. data/lib/contrast/api/decorators/trace_event_signature.rb +27 -5
  76. data/lib/contrast/api/decorators/user_input.rb +2 -1
  77. data/lib/contrast/common_agent_configuration.rb +2 -1
  78. data/lib/contrast/components/agent.rb +6 -5
  79. data/lib/contrast/components/assess.rb +36 -0
  80. data/lib/contrast/components/config.rb +29 -37
  81. data/lib/contrast/components/interface.rb +30 -6
  82. data/lib/contrast/components/inventory.rb +6 -1
  83. data/lib/contrast/components/scope.rb +72 -6
  84. data/lib/contrast/components/settings.rb +6 -3
  85. data/lib/contrast/config/assess_configuration.rb +2 -1
  86. data/lib/contrast/config/inventory_configuration.rb +2 -2
  87. data/lib/contrast/extension/assess/array.rb +2 -3
  88. data/lib/contrast/extension/assess/erb.rb +1 -3
  89. data/lib/contrast/extension/assess/exec_trigger.rb +1 -4
  90. data/lib/contrast/extension/assess/fiber.rb +2 -3
  91. data/lib/contrast/extension/assess/hash.rb +4 -2
  92. data/lib/contrast/extension/assess/kernel.rb +1 -2
  93. data/lib/contrast/extension/assess/marshal.rb +34 -26
  94. data/lib/contrast/extension/assess/regexp.rb +3 -8
  95. data/lib/contrast/extension/assess/string.rb +1 -2
  96. data/lib/contrast/framework/base_support.rb +51 -53
  97. data/lib/contrast/framework/manager.rb +3 -2
  98. data/lib/contrast/framework/rack/patch/session_cookie.rb +2 -2
  99. data/lib/contrast/framework/rack/support.rb +2 -1
  100. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +1 -1
  101. data/lib/contrast/framework/rails/patch/assess_configuration.rb +1 -1
  102. data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +1 -1
  103. data/lib/contrast/framework/rails/rewrite/action_controller_railties_helper_inherited.rb +1 -1
  104. data/lib/contrast/framework/rails/rewrite/active_record_attribute_methods_read.rb +1 -1
  105. data/lib/contrast/framework/rails/rewrite/active_record_time_zone_inherited.rb +1 -1
  106. data/lib/contrast/framework/rails/support.rb +5 -1
  107. data/lib/contrast/framework/sinatra/support.rb +3 -2
  108. data/lib/contrast/logger/application.rb +1 -4
  109. data/lib/contrast/utils/duck_utils.rb +1 -1
  110. data/lib/contrast/utils/heap_dump_util.rb +1 -1
  111. data/lib/contrast/utils/inventory_util.rb +0 -7
  112. data/lib/contrast/utils/object_share.rb +3 -3
  113. data/lib/contrast/utils/preflight_util.rb +1 -1
  114. data/lib/contrast/utils/prevent_serialization.rb +1 -1
  115. data/lib/contrast/utils/resource_loader.rb +1 -1
  116. data/lib/contrast/utils/sha256_builder.rb +2 -14
  117. data/lib/contrast/utils/string_utils.rb +1 -1
  118. data/lib/contrast/utils/tag_util.rb +9 -13
  119. data/resources/assess/policy.json +9 -9
  120. data/resources/deadzone/policy.json +150 -0
  121. data/resources/protect/policy.json +12 -0
  122. data/ruby-agent.gemspec +10 -6
  123. data/service_executables/VERSION +1 -1
  124. data/service_executables/linux/contrast-service +0 -0
  125. data/service_executables/mac/contrast-service +0 -0
  126. metadata +76 -27
  127. data/lib/contrast/utils/boolean_util.rb +0 -30
  128. data/lib/contrast/utils/gemfile_reader.rb +0 -193
@@ -36,14 +36,12 @@ module Contrast
36
36
  end
37
37
 
38
38
  splat_tags(tracked_inputs, target)
39
- Contrast::Agent::Assess::Tracker.properties(target).cleanup_tags
39
+ Contrast::Agent::Assess::Tracker.properties(target)&.cleanup_tags
40
40
  end
41
41
 
42
42
  def splat_tags tracked_inputs, target
43
43
  return if tracked_inputs.empty?
44
-
45
- properties = Contrast::Agent::Assess::Tracker.properties(target)
46
- return unless properties
44
+ return unless (properties = Contrast::Agent::Assess::Tracker.properties!(target))
47
45
 
48
46
  tracked_inputs.each do |input|
49
47
  input_properties = Contrast::Agent::Assess::Tracker.properties(input)
@@ -15,13 +15,12 @@ module Contrast
15
15
  class Split < Contrast::Agent::Assess::Policy::Propagator::Base
16
16
  include Contrast::Components::Interface
17
17
 
18
- access_component :agent, :logging
18
+ access_component :agent, :logging, :scope
19
19
 
20
20
  SPLIT_TRACKER = Contrast::Utils::ThreadTracker.new
21
+
21
22
  class << self
22
- # Propagate taint from a source as it is split into composite
23
- # sections. This method MUST return nil, otherwise it risks
24
- # changing the result of of the propagation.
23
+ # Propagate taint from a source as it is split into composite sections.
25
24
  #
26
25
  # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode]
27
26
  # the node that governs this propagation event.
@@ -29,171 +28,132 @@ module Contrast
29
28
  # of the state of the code just prior to the invocation of the
30
29
  # patched method.
31
30
  # @param target [Array, String] the target to which to propagate.
32
- # @return [nil]
31
+ # @return [nil] so as not to risk changing the result of the propagation.
32
+
33
33
  def propagate propagation_node, preshift, target
34
34
  logger.trace('Propagation detected',
35
35
  node_id: propagation_node.id,
36
36
  target_id: target.__id__)
37
- unless target.is_a?(Array)
38
- Contrast::Agent::Assess::Policy::Propagator::Keep.propagate(propagation_node, preshift, target)
39
- properties = Contrast::Agent::Assess::Tracker.properties(target)
40
- properties.build_event(propagation_node, target, object, ret, args)
41
- return
42
- end
43
37
 
44
38
  source = find_source(propagation_node.sources[0], preshift)
39
+ return unless (source_properties = Contrast::Agent::Assess::Tracker.properties(source))
45
40
 
41
+ # grapheme_clusters break the string apart based on each "user-perceived" character.
42
+ # Otherwise, the default for String#split is to use a single whitespace.
46
43
  separator_length = if propagation_node.method_name == :grapheme_clusters
47
- # grapheme_clusters break the string apart based on each "user-perceived" character
48
44
  0
49
45
  else
50
- # The default for String#split is to use a single whitespace
51
46
  preshift&.args&.first&.to_s&.length || $FIELD_SEPARATOR&.to_s&.length || 1
52
47
  end
53
48
 
54
49
  current_index = 0
55
- target.each do |elem|
56
- elem_length = elem.length
57
- range = current_index...(current_index + elem_length)
58
- elem_properties = Contrast::Agent::Assess::Tracker.properties(elem)
59
- next unless elem_properties
50
+ target.each do |target_elem|
51
+ next unless (elem_properties = Contrast::Agent::Assess::Tracker.properties!(target_elem))
60
52
 
61
- source_properties = Contrast::Agent::Assess::Tracker.properties(source)
53
+ # Get tags for element from source by element range.
54
+ range = current_index...(current_index + target_elem.length)
62
55
  tags = source_properties.tags_at_range(range)
56
+
57
+ # Set element properties accordingly.
63
58
  elem_properties.clear_tags
64
- tags.each_pair do |key, value|
65
- elem_properties.set_tags(key, value)
66
- end
67
- elem_properties.build_event(propagation_node, elem, preshift.object, target, preshift.args, 0)
59
+ tags.each_pair { |key, value| elem_properties.set_tags(key, value) }
60
+ elem_properties.build_event(propagation_node, target_elem, preshift.object, target, preshift.args, 0)
68
61
  elem_properties.add_properties(propagation_node.properties)
69
- current_index = current_index + elem_length + separator_length
62
+
63
+ current_index = range.end + separator_length
70
64
  end
71
65
  nil
72
66
  end
73
67
 
74
- # Marks the point in which the String#split method is called.
75
- # Responsible for building the context required to propagate when
76
- # the results of #split are yielded directly to a block
68
+ # Context for block split execution.
77
69
  #
78
- # @param string [String] the String on which split is invoked
79
- # @param args [Array<Object>] the arguments passed to the
80
- # original split call
81
- def begin_split string, args
82
- save_split_depth!
83
- depth = SPLIT_TRACKER.get(:split_depth)
84
- save_split_index!(depth)
85
- save_split_value!(depth, string, args)
86
- rescue Exception => e # rubocop:disable Lint/RescueException
87
- # don't let our errors propagate and disable String#split for
88
- # this since we're in an error state
89
- logger.warn('Unable to record split context', e)
90
- end_split
91
- end
70
+ # @param string [String] the String on which split is invoked.
71
+ # @param args [Array<Object>] the arguments passed to the original split call.
72
+ def wrap_split string, args
73
+ # String#split start. Build context and yield.
74
+ begin
75
+ enter_split_scope!
76
+ save_split_index!
77
+ save_split_value!(string, args)
78
+ rescue Exception => e # rubocop:disable Lint/RescueException
79
+ logger.warn('Unable to record split context', e)
80
+ end
92
81
 
93
- # Marks the point in which the String#split method is exited.
94
- # Responsible for removing the context required to propagate when
95
- # the results of #split are yielded directly to a block
96
- def end_split
97
- depth = SPLIT_TRACKER.get(:split_depth)
98
- return unless depth
99
-
100
- depth -= 1
101
- if depth.negative?
102
- SPLIT_TRACKER.delete(:split_depth)
103
- SPLIT_TRACKER.delete(:split_index)
104
- SPLIT_TRACKER.delete(:split_value)
105
- else
106
- SPLIT_TRACKER.set(:split_depth, depth)
82
+ yield
83
+ ensure
84
+ # String#split exit. Remove propagation context.
85
+ begin
86
+ exit_split_scope!
87
+ unless in_split_scope?
88
+ SPLIT_TRACKER.delete(:split_index)
89
+ SPLIT_TRACKER.delete(:split_value)
90
+ end
91
+ rescue StandardError => e
92
+ logger.warn('Unable to remove split context', e)
107
93
  end
108
- rescue StandardError => e
109
- logger.warn('Unable to remove split context', e)
110
94
  end
111
95
 
112
- # This method is called whenever an rb_yield is called. We need
113
- # to leave it as soon as possible with as little work as
114
- # possible.
96
+ # This method is called whenever an rb_yield is called.
97
+ # We need to leave it as soon as possible with as little work as possible.
115
98
  #
116
- # @param target [String] the entity being passed to the yield
117
- # block
99
+ # @param target [String] the entity being passed to the yield block
118
100
  def propagate_yield target
119
- depth, index = nil
120
-
121
- depth = SPLIT_TRACKER.get(:split_depth)
122
- return unless depth
123
-
124
- source = SPLIT_TRACKER.get(:split_value)&.fetch(depth)
125
- return unless source
126
-
127
- index = SPLIT_TRACKER.get(:split_index)&.fetch(depth)
128
- return unless index
129
-
130
- properties = Contrast::Agent::Assess::Tracker.properties(target)
131
- return unless properties
101
+ return unless (source = SPLIT_TRACKER.get(:split_value)&.fetch(split_scope_depth))
102
+ return unless (index = SPLIT_TRACKER.get(:split_index)&.fetch(split_scope_depth))
103
+ return unless (properties = Contrast::Agent::Assess::Tracker.properties!(target))
132
104
 
133
105
  true_source = source[index]
134
106
  properties.copy_from(true_source, target)
135
107
  rescue StandardError => e
136
108
  logger.warn('Unable to track within split context', e)
137
109
  ensure
138
- if depth && index
110
+ if in_split_scope? && index
139
111
  idx = SPLIT_TRACKER.get(:split_index)
140
- idx[depth] = index + 1 if defined?(idx) && idx.is_a?(Array)
112
+ idx[split_scope_depth] = index + 1 if defined?(idx) && idx.is_a?(Array)
141
113
  end
142
114
  end
143
115
 
116
+ # Load patch.
144
117
  def instrument_string_split
145
- if @_instrument_string_split.nil?
146
- @_instrument_string_split = begin
147
- require 'cs__assess_yield_track/cs__assess_yield_track' if AGENT.patch_yield? && Funchook.available?
148
- true
149
- rescue StandardError => e
150
- logger.error('Error loading split rb_yield patch', e)
151
- false
152
- end
118
+ @_instrument_string_split ||= begin
119
+ require 'cs__assess_yield_track/cs__assess_yield_track' if AGENT.patch_yield? && Funchook.available?
120
+ true
121
+ rescue StandardError => e
122
+ logger.error('Error loading split rb_yield patch', e)
123
+ false
153
124
  end
154
- @_instrument_string_split
155
125
  end
156
126
 
157
127
  private
158
128
 
159
- def save_split_depth!
160
- depth = SPLIT_TRACKER.get(:split_depth)
161
- if depth
162
- depth += 1
163
- SPLIT_TRACKER.set(:split_depth, depth)
164
- else
165
- SPLIT_TRACKER.set(:split_depth, 0)
166
- end
167
- end
168
-
169
- def save_split_index! depth
170
- split_index = SPLIT_TRACKER.get(:split_index)
171
- unless split_index
129
+ # Save index of the current split object.
130
+ # Create index tracking array as needed.
131
+ def save_split_index!
132
+ unless (split_index = SPLIT_TRACKER.get(:split_index))
172
133
  split_index = []
173
134
  SPLIT_TRACKER.set(:split_index, split_index)
174
135
  end
175
- # save the index to the ThreadLocal; not useless
176
- split_index[depth] = 0 # rubocop:disable Lint/UselessSetterCall
136
+ # save the index to the ThreadLocal; not useless.
137
+ split_index[split_scope_depth] = 0 # rubocop:disable Lint/UselessSetterCall
177
138
  end
178
139
 
179
- def save_split_value! depth, string, args
140
+ # Save value of the current split object.
141
+ # Create value tracking array as needed.
142
+ def save_split_value! string, args
180
143
  preshift = Contrast::Agent::Assess::PreShift.build_preshift(split_node, string, args)
181
144
  target = string.split
182
145
  propagate(split_node, preshift, target)
183
- split_value = SPLIT_TRACKER.get(:split_value)
184
- unless split_value
146
+ unless (split_value = SPLIT_TRACKER.get(:split_value))
185
147
  split_value = []
186
148
  SPLIT_TRACKER.set(:split_value, split_value)
187
149
  end
188
- # save the target to the ThreadLocal; not useless
189
- split_value[depth] = target # rubocop:disable Lint/UselessSetterCall
150
+ # Save the target to the ThreadLocal; not useless.
151
+ split_value[split_scope_depth] = target # rubocop:disable Lint/UselessSetterCall
190
152
  end
191
153
 
192
- # Quick hook to the String#split propagation node in our Assess
193
- # policy
154
+ # Quick hook to the String#split propagation node in our Assess policy
194
155
  #
195
- # @return [Contrast::Agent::Assess::Policy::PropagationNode]
196
- # String#split node
156
+ # @return [Contrast::Agent::Assess::Policy::PropagationNode] String#split node
197
157
  def split_node
198
158
  @_split_node ||= begin
199
159
  Contrast::Agent::Assess::Policy::Policy.instance.propagators.find do |node|
@@ -215,19 +175,15 @@ if RUBY_VERSION >= '2.6.0'
215
175
  class String
216
176
  alias_method :cs__patched_string_split_special, :split
217
177
 
218
- # override of the the standard split method to handle the 2.6 direct
219
- # yield case.
178
+ # Override of the the standard split method to handle the 2.6 direct yield case.
220
179
  #
221
180
  # Note: because this patch is applied before our standard propagation, this
222
- # call wrapped in it. As such, any call here happens in scope, so there is
181
+ # call is wrapped in it. As such, any call here happens in scope, so there is
223
182
  # no need to manage it on our own.
224
183
  def split *args, &block
225
184
  if block
226
- Contrast::Agent::Assess::Policy::Propagator::Split.begin_split(self, args)
227
- begin
185
+ Contrast::Agent::Assess::Policy::Propagator::Split.wrap_split(self, args) do
228
186
  cs__patched_string_split_special(*args, &block)
229
- ensure
230
- Contrast::Agent::Assess::Policy::Propagator::Split.end_split
231
187
  end
232
188
  else
233
189
  cs__patched_string_split_special(*args, &block)
@@ -92,8 +92,7 @@ module Contrast
92
92
  end
93
93
 
94
94
  def string_sub parent_events, self_tracked, preshift, ret, incoming, incoming_tracked, global
95
- properties = Contrast::Agent::Assess::Tracker.properties(ret)
96
- return unless properties
95
+ return unless (properties = Contrast::Agent::Assess::Tracker.properties!(ret))
97
96
 
98
97
  incoming_properties = Contrast::Agent::Assess::Tracker.properties(incoming)
99
98
  parent_event = incoming_properties&.event
@@ -141,22 +140,23 @@ module Contrast
141
140
  end
142
141
 
143
142
  def block_sub self_tracked, source, ret
144
- properties = Contrast::Agent::Assess::Tracker.properties(ret)
145
- properties&.splat_from(source, ret) if self_tracked
143
+ return unless self_tracked
144
+
145
+ properties = Contrast::Agent::Assess::Tracker.properties!(ret)
146
+ properties&.splat_from(source, ret)
146
147
  end
147
148
 
148
149
  def hash_sub self_tracked, source, ret
149
- properties = Contrast::Agent::Assess::Tracker.properties(ret)
150
- properties&.splat_from(source, ret) if self_tracked
150
+ return unless self_tracked
151
+
152
+ properties = Contrast::Agent::Assess::Tracker.properties!(ret)
153
+ properties&.splat_from(source, ret)
151
154
  end
152
155
 
153
156
  def pattern_gsub parent_events, preshift, ret
154
- properties = Contrast::Agent::Assess::Tracker.properties(ret)
155
- return unless properties
156
-
157
157
  source = preshift.object
158
- source_properties = Contrast::Agent::Assess::Tracker.properties(source)
159
- return unless source_properties
158
+ return unless (source_properties = Contrast::Agent::Assess::Tracker.properties(source))
159
+ return unless (properties = Contrast::Agent::Assess::Tracker.properties!(ret))
160
160
 
161
161
  source_properties.tag_keys.each do |key|
162
162
  properties.add_tag(key, 0...1)
@@ -11,13 +11,11 @@ module Contrast
11
11
  # Disclaimer: there may be a better way, but we're
12
12
  # in a 'get it work' state. hopefully, we'll be in
13
13
  # a 'get it right' state soon.
14
- class Trim
14
+ module Trim
15
15
  class << self
16
16
  def tr_tagger patcher, preshift, ret, _block
17
17
  return ret unless ret && !ret.empty?
18
-
19
- properties = Contrast::Agent::Assess::Tracker.properties(ret)
20
- return unless properties
18
+ return ret unless (properties = Contrast::Agent::Assess::Tracker.properties!(ret))
21
19
 
22
20
  source = preshift.object
23
21
  args = preshift.args
@@ -59,9 +57,7 @@ module Contrast
59
57
 
60
58
  def tr_s_tagger patcher, preshift, ret, _block
61
59
  return unless ret && !ret.empty?
62
-
63
- properties = Contrast::Agent::Assess::Tracker.properties(ret)
64
- return unless properties
60
+ return unless (properties = Contrast::Agent::Assess::Tracker.properties!(ret))
65
61
 
66
62
  source = preshift.object
67
63
  args = preshift.args
@@ -178,8 +178,8 @@ module Contrast
178
178
  # don't apply second source -- probably needs tuning later if we
179
179
  # use more than 'UNTRUSTED' in our sources
180
180
  return if Contrast::Agent::Assess::Tracker.tracked?(target)
181
+ return unless (properties = Contrast::Agent::Assess::Tracker.properties!(target))
181
182
 
182
- properties = Contrast::Agent::Assess::Tracker.properties(target)
183
183
  # otherwise for each tag this source_node applies, create a tag range
184
184
  # on the target object
185
185
  # I realize this looping is counter-intuitive from the above
@@ -243,19 +243,7 @@ module Contrast
243
243
  when Contrast::Utils::ObjectShare::OBJECT_KEY
244
244
  object
245
245
  else
246
- if source_target.is_a?(Integer)
247
- args[source_target]
248
- # If this isn't an index param, it's a named one. R.I.P.
249
- else
250
- arg = nil
251
- args.each do |search|
252
- next unless search.is_a?(Hash)
253
-
254
- arg = search[source_target]
255
- break if arg
256
- end
257
- arg
258
- end
246
+ args[source_target]
259
247
  end
260
248
  end
261
249
 
@@ -25,14 +25,13 @@ module Contrast
25
25
  TEMPLATE_PROPAGATION_NODE = Contrast::Agent::Assess::Policy::PropagationNode.new(NODE_HASH)
26
26
 
27
27
  def xss_tilt_trigger context, trigger_node, _source, object, ret, *args
28
- properties = Contrast::Agent::Assess::Tracker.properties(ret)
29
- return unless properties
28
+ return unless (properties = Contrast::Agent::Assess::Tracker.properties!(ret))
30
29
 
31
30
  scope = args[0]
32
31
  erb_template_prerender = object.instance_variable_get(:@data)
33
32
  interpolated_inputs = []
34
- handle_binding_variables(scope, erb_template_prerender, ret, interpolated_inputs)
35
- handle_local_variables(args, erb_template_prerender, ret, interpolated_inputs)
33
+ handle_binding_variables(scope, erb_template_prerender, ret, properties, interpolated_inputs)
34
+ handle_local_variables(args, erb_template_prerender, ret, properties, interpolated_inputs)
36
35
  properties.build_event(TEMPLATE_PROPAGATION_NODE, ret, erb_template_prerender, ret, interpolated_inputs)
37
36
  unless interpolated_inputs.empty?
38
37
  current_event = properties.event
@@ -53,8 +52,7 @@ module Contrast
53
52
 
54
53
  private
55
54
 
56
- def handle_binding_variables scope, erb_template_prerender, ret, interpolated_inputs
57
- properties = Contrast::Agent::Assess::Tracker.properties(ret)
55
+ def handle_binding_variables scope, erb_template_prerender, ret, properties, interpolated_inputs
58
56
  binding_variables = scope.instance_variables
59
57
 
60
58
  binding_variables.each do |bound_variable_sym|
@@ -71,8 +69,7 @@ module Contrast
71
69
  end
72
70
  end
73
71
 
74
- def handle_local_variables args, erb_template_prerender, ret, interpolated_inputs
75
- properties = Contrast::Agent::Assess::Tracker.properties(ret)
72
+ def handle_local_variables args, erb_template_prerender, ret, properties, interpolated_inputs
76
73
  locals = args[1]
77
74
  locals.each do |local_name, local_value|
78
75
  next unless Contrast::Agent::Assess::Tracker.tracked?(local_value)
@@ -43,7 +43,7 @@ module Contrast
43
43
  next unless trigger_node.violated?(arg)
44
44
 
45
45
  Contrast::Agent::Assess::Policy::TriggerMethod.build_finding(
46
- context, trigger_node, arg, object, ret, args)
46
+ context, trigger_node, arg, object, ret, *args)
47
47
  end
48
48
 
49
49
  ret
@@ -39,7 +39,7 @@ module Contrast
39
39
  finish ||= url.length
40
40
 
41
41
  properties = Contrast::Agent::Assess::Tracker.properties(args[0])
42
- properties.any_tags_between?(start, finish)
42
+ properties&.any_tags_between?(start, finish)
43
43
  end
44
44
  end
45
45
  end