contrast-agent 6.1.0 → 6.1.1

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 (179) hide show
  1. checksums.yaml +4 -4
  2. data/.simplecov +1 -1
  3. data/Rakefile +1 -1
  4. data/ext/build_funchook.rb +3 -3
  5. data/ext/cs__assess_basic_object/cs__assess_basic_object.c +5 -1
  6. data/ext/extconf_common.rb +1 -1
  7. data/lib/contrast/agent/assess/finalizers/hash.rb +2 -2
  8. data/lib/contrast/agent/assess/policy/policy.rb +9 -10
  9. data/lib/contrast/agent/assess/policy/policy_node.rb +9 -10
  10. data/lib/contrast/agent/assess/policy/propagation_method.rb +3 -3
  11. data/lib/contrast/agent/assess/policy/propagation_node.rb +2 -3
  12. data/lib/contrast/agent/assess/policy/propagator/base.rb +1 -1
  13. data/lib/contrast/agent/assess/policy/propagator/buffer.rb +2 -1
  14. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +1 -1
  15. data/lib/contrast/agent/assess/policy/propagator/splat.rb +1 -1
  16. data/lib/contrast/agent/assess/policy/propagator/split.rb +2 -2
  17. data/lib/contrast/agent/assess/policy/propagator/trim.rb +1 -1
  18. data/lib/contrast/agent/assess/policy/source_node.rb +1 -1
  19. data/lib/contrast/agent/assess/policy/trigger_method.rb +7 -7
  20. data/lib/contrast/agent/assess/policy/trigger_node.rb +16 -16
  21. data/lib/contrast/agent/assess/policy/trigger_validation/redos_validator.rb +1 -1
  22. data/lib/contrast/agent/assess/property/evented.rb +2 -2
  23. data/lib/contrast/agent/assess/property/tagged.rb +2 -2
  24. data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +6 -8
  25. data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +6 -7
  26. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +5 -5
  27. data/lib/contrast/agent/assess/rule/response/base_rule.rb +2 -3
  28. data/lib/contrast/agent/assess/rule/response/cache_control_header_rule.rb +8 -9
  29. data/lib/contrast/agent/assess/rule/response/click_jacking_header_rule.rb +4 -4
  30. data/lib/contrast/agent/assess/rule/response/csp_header_insecure_rule.rb +6 -6
  31. data/lib/contrast/agent/assess/rule/response/csp_header_missing_rule.rb +4 -4
  32. data/lib/contrast/agent/assess/rule/response/hsts_header_rule.rb +4 -4
  33. data/lib/contrast/agent/assess/rule/response/x_content_type_header_rule.rb +4 -4
  34. data/lib/contrast/agent/assess/rule/response/x_xss_protection_header_rule.rb +3 -4
  35. data/lib/contrast/agent/assess/tag.rb +13 -14
  36. data/lib/contrast/agent/at_exit_hook.rb +12 -1
  37. data/lib/contrast/agent/middleware.rb +6 -3
  38. data/lib/contrast/agent/patching/policy/after_load_patch.rb +3 -3
  39. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +2 -2
  40. data/lib/contrast/agent/patching/policy/method_policy_extend.rb +4 -4
  41. data/lib/contrast/agent/patching/policy/patch.rb +9 -9
  42. data/lib/contrast/agent/patching/policy/patch_status.rb +10 -3
  43. data/lib/contrast/agent/patching/policy/policy.rb +13 -15
  44. data/lib/contrast/agent/patching/policy/policy_node.rb +19 -21
  45. data/lib/contrast/agent/patching/policy/trigger_node.rb +1 -1
  46. data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +125 -125
  47. data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +2 -2
  48. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +1 -1
  49. data/lib/contrast/agent/protect/policy/applies_xxe_rule.rb +1 -1
  50. data/lib/contrast/agent/protect/policy/rule_applicator.rb +4 -4
  51. data/lib/contrast/agent/protect/rule/base.rb +30 -18
  52. data/lib/contrast/agent/protect/rule/base_service.rb +31 -14
  53. data/lib/contrast/agent/protect/rule/cmd_injection.rb +16 -9
  54. data/lib/contrast/agent/protect/rule/cmdi/cmdi_input_classification.rb +3 -3
  55. data/lib/contrast/agent/protect/rule/default_scanner.rb +2 -1
  56. data/lib/contrast/agent/protect/rule/deserialization.rb +18 -7
  57. data/lib/contrast/agent/protect/rule/http_method_tampering/http_method_tampering_input_classification.rb +74 -74
  58. data/lib/contrast/agent/protect/rule/http_method_tampering.rb +71 -53
  59. data/lib/contrast/agent/protect/rule/no_sqli/no_sqli_input_classification.rb +3 -3
  60. data/lib/contrast/agent/protect/rule/no_sqli.rb +15 -16
  61. data/lib/contrast/agent/protect/rule/path_traversal.rb +13 -3
  62. data/lib/contrast/agent/protect/rule/sqli/sqli_input_classification.rb +2 -2
  63. data/lib/contrast/agent/protect/rule/sqli/sqli_worth_watching.rb +1 -1
  64. data/lib/contrast/agent/protect/rule/sqli.rb +16 -23
  65. data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_input_classification.rb +61 -61
  66. data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_matcher.rb +29 -29
  67. data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +32 -32
  68. data/lib/contrast/agent/protect/rule/xss.rb +17 -0
  69. data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +14 -13
  70. data/lib/contrast/agent/protect/rule/xxe.rb +25 -3
  71. data/lib/contrast/agent/reaction_processor.rb +1 -1
  72. data/lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb +36 -36
  73. data/lib/contrast/agent/reporting/masker/masker.rb +10 -10
  74. data/lib/contrast/agent/reporting/masker/masker_utils.rb +2 -2
  75. data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +8 -10
  76. data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +53 -5
  77. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_activity.rb +25 -19
  78. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +129 -17
  79. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +20 -21
  80. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_stack.rb +22 -0
  81. data/lib/contrast/agent/reporting/reporting_events/application_defend_attacker_activity.rb +26 -12
  82. data/lib/contrast/agent/reporting/reporting_events/application_inventory.rb +5 -5
  83. data/lib/contrast/agent/reporting/reporting_events/application_inventory_activity.rb +7 -5
  84. data/lib/contrast/agent/reporting/reporting_events/application_startup.rb +4 -10
  85. data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +1 -1
  86. data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +1 -2
  87. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +6 -6
  88. data/lib/contrast/agent/reporting/reporting_utilities/response.rb +1 -1
  89. data/lib/contrast/agent/reporting/reporting_utilities/response_extractor.rb +1 -1
  90. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +7 -7
  91. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +15 -15
  92. data/lib/contrast/agent/reporting/settings/application_settings.rb +1 -1
  93. data/lib/contrast/agent/reporting/settings/assess.rb +5 -5
  94. data/lib/contrast/agent/reporting/settings/assess_server_feature.rb +3 -3
  95. data/lib/contrast/agent/reporting/settings/exclusions.rb +3 -3
  96. data/lib/contrast/agent/reporting/settings/protect.rb +20 -5
  97. data/lib/contrast/agent/reporting/settings/protect_server_feature.rb +5 -5
  98. data/lib/contrast/agent/reporting/settings/reaction.rb +3 -3
  99. data/lib/contrast/agent/reporting/settings/sensitive_data_masking.rb +2 -2
  100. data/lib/contrast/agent/reporting/settings/sensitive_data_masking_rule.rb +2 -2
  101. data/lib/contrast/agent/reporting/settings/server_features.rb +2 -2
  102. data/lib/contrast/agent/request.rb +2 -2
  103. data/lib/contrast/agent/request_context.rb +23 -19
  104. data/lib/contrast/agent/request_context_extend.rb +10 -23
  105. data/lib/contrast/agent/request_handler.rb +1 -1
  106. data/lib/contrast/agent/rule_set.rb +2 -2
  107. data/lib/contrast/agent/scope.rb +1 -1
  108. data/lib/contrast/agent/telemetry/base.rb +9 -5
  109. data/lib/contrast/agent/telemetry/events/exceptions/obfuscate.rb +119 -0
  110. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_base.rb +2 -2
  111. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception.rb +1 -1
  112. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_frame.rb +1 -1
  113. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report.rb +16 -18
  114. data/lib/contrast/agent/telemetry/events/startup_metrics_event.rb +2 -2
  115. data/lib/contrast/agent/version.rb +1 -1
  116. data/lib/contrast/api/communication/messaging_queue.rb +1 -1
  117. data/lib/contrast/api/communication/service_lifecycle.rb +1 -1
  118. data/lib/contrast/api/communication/socket.rb +1 -1
  119. data/lib/contrast/api/communication/socket_client.rb +1 -1
  120. data/lib/contrast/api/communication/speedracer.rb +2 -2
  121. data/lib/contrast/api/decorators/agent_startup.rb +10 -9
  122. data/lib/contrast/api/decorators/application_settings.rb +1 -1
  123. data/lib/contrast/api/decorators/application_startup.rb +4 -4
  124. data/lib/contrast/api/decorators/response_type.rb +4 -17
  125. data/lib/contrast/components/agent.rb +1 -1
  126. data/lib/contrast/components/base.rb +1 -1
  127. data/lib/contrast/components/config.rb +6 -6
  128. data/lib/contrast/components/contrast_service.rb +4 -1
  129. data/lib/contrast/components/sampling.rb +1 -1
  130. data/lib/contrast/components/settings.rb +52 -28
  131. data/lib/contrast/config/assess_rules_configuration.rb +1 -1
  132. data/lib/contrast/config/protect_rules_configuration.rb +1 -1
  133. data/lib/contrast/config/root_configuration.rb +1 -1
  134. data/lib/contrast/configuration.rb +4 -4
  135. data/lib/contrast/extension/assess/array.rb +1 -1
  136. data/lib/contrast/extension/assess/erb.rb +1 -1
  137. data/lib/contrast/extension/assess/marshal.rb +1 -1
  138. data/lib/contrast/extension/assess/string.rb +1 -1
  139. data/lib/contrast/extension/extension.rb +2 -2
  140. data/lib/contrast/framework/base_support.rb +8 -8
  141. data/lib/contrast/framework/grape/support.rb +3 -3
  142. data/lib/contrast/framework/manager.rb +5 -5
  143. data/lib/contrast/framework/manager_extend.rb +1 -1
  144. data/lib/contrast/framework/rack/patch/session_cookie.rb +1 -1
  145. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +14 -3
  146. data/lib/contrast/framework/rails/patch/assess_configuration.rb +3 -3
  147. data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +1 -1
  148. data/lib/contrast/framework/rails/patch/support.rb +1 -1
  149. data/lib/contrast/framework/rails/support.rb +2 -2
  150. data/lib/contrast/framework/sinatra/support.rb +1 -1
  151. data/lib/contrast/logger/aliased_logging.rb +29 -22
  152. data/lib/contrast/logger/cef_log.rb +14 -14
  153. data/lib/contrast/logger/format.rb +1 -1
  154. data/lib/contrast/logger/log.rb +8 -8
  155. data/lib/contrast/tasks/config.rb +12 -12
  156. data/lib/contrast/tasks/service.rb +2 -2
  157. data/lib/contrast/utils/assess/tracking_util.rb +4 -4
  158. data/lib/contrast/utils/class_util.rb +4 -4
  159. data/lib/contrast/utils/findings.rb +3 -3
  160. data/lib/contrast/utils/hash_digest.rb +6 -7
  161. data/lib/contrast/utils/head_dump_utils_extend.rb +1 -1
  162. data/lib/contrast/utils/invalid_configuration_util.rb +1 -1
  163. data/lib/contrast/utils/log_utils.rb +4 -4
  164. data/lib/contrast/utils/lru_cache.rb +1 -1
  165. data/lib/contrast/utils/metrics_hash.rb +1 -1
  166. data/lib/contrast/utils/middleware_utils.rb +5 -5
  167. data/lib/contrast/utils/net_http_base.rb +4 -4
  168. data/lib/contrast/utils/os.rb +1 -1
  169. data/lib/contrast/utils/patching/policy/patch_utils.rb +2 -2
  170. data/lib/contrast/utils/request_utils.rb +2 -2
  171. data/lib/contrast/utils/sha256_builder.rb +4 -4
  172. data/lib/contrast/utils/stack_trace_utils.rb +31 -13
  173. data/lib/contrast/utils/telemetry.rb +6 -9
  174. data/lib/contrast/utils/telemetry_client.rb +5 -5
  175. data/lib/contrast/utils/telemetry_hash.rb +1 -1
  176. data/lib/contrast/utils/telemetry_identifier.rb +2 -2
  177. data/lib/contrast/utils/timer.rb +1 -1
  178. data/resources/assess/policy.json +1 -1
  179. metadata +15 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 456cd00d5b3c07ec1a845a6dbcb26d6d5b2891b03a352f06d290d405ff695596
4
- data.tar.gz: 06ce1572dc8403fdf57ab6cbaa9ea51d8b7e52c4090d64badda5001aabb608ac
3
+ metadata.gz: e548b3df856f888229a5125c351404c3f5b04fcd7ecb5c91937f480ce91c9d42
4
+ data.tar.gz: 00c6ee55996e75602d1b80da133a362d3205cb5ef5de0f5c1a35b214528fea2a
5
5
  SHA512:
6
- metadata.gz: 8ab067665857065d8325547faa13c3f41679e9a9a9de9a70245e310a2229b1d1097ee2198ae45ab9be5804835764c9004372ec03c8a7f2e2ce8ee3bafda332b1
7
- data.tar.gz: cda25e738349d4ba06e6ada4fbb146341f883b92a444b9179dcb8e1e21d21d5c6fcd50503a599a9a55248e40078213f521dac5bdd610480650034455dce90f03
6
+ metadata.gz: ad8d0f64dc798a22072e977cf0ff83ba47df54a3f24802386a52d2d338f365a02cac5db943868a55ecdf7641e44384f580e55e5d1b05a78522e88c5244013346
7
+ data.tar.gz: 804a464d38a9e023da53ce82009573571a6197c9f3f00642988457ac32b8ecc8631ea0a3cfd8bc678918df8afbb1cb24c51fa79dff1fe8fb278c5e966bff74e1
data/.simplecov CHANGED
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
- SimpleCov.minimum_coverage line: 95
4
+ SimpleCov.minimum_coverage(line: 94)
5
5
  SimpleCov.start do
6
6
  add_filter '/spec/'
7
7
  enable_coverage :branch
data/Rakefile CHANGED
@@ -13,7 +13,7 @@ CLOBBER << 'shared_libraries/*'
13
13
 
14
14
  Dir['ext/cs__*'].each do |extension|
15
15
  name = extension.split('/')[1]
16
- Rake::ExtensionTask.new name do |ext|
16
+ Rake::ExtensionTask.new(name) do |ext|
17
17
  ext.lib_dir = "lib/#{ name }"
18
18
  end
19
19
  end
@@ -52,13 +52,13 @@ unless find_header('funchook.h', ext_path)
52
52
 
53
53
  TARGET_PATHS.each do |target_path|
54
54
  unless File.writable?(target_path)
55
- puts "Unable to copy into #{ target_path } - directory not writable"
55
+ puts("Unable to copy into #{ target_path } - directory not writable")
56
56
  next
57
57
  end
58
- puts "Copying #{ source_file_path } into #{ target_path }"
58
+ puts("Copying #{ source_file_path } into #{ target_path }")
59
59
  FileUtils.cp(source_file_path, target_path)
60
60
  rescue StandardError
61
- puts "Error while copying #{ source_file } to #{ target_path }"
61
+ puts("Error while copying #{ source_file } to #{ target_path }")
62
62
  end
63
63
  end
64
64
  end
@@ -17,6 +17,10 @@
17
17
  * }
18
18
  */
19
19
 
20
+ VALUE contrast_check_and_register_instance_patch(
21
+ const char *module_name, const char *method_name,
22
+ VALUE(c_fn)(const int, VALUE *, const VALUE));
23
+
20
24
  void contrast_assess_instance_eval_trigger_check(VALUE self, VALUE source,
21
25
  VALUE ret) {
22
26
  rb_funcall(basic_eval_trigger, instance_trigger_check_method, 3, self,
@@ -61,6 +65,6 @@ void Init_cs__assess_basic_object(void) {
61
65
  * but if someone else patched BasicObject#instance_eval,
62
66
  * IDK if this is intentional... noting it. -ajm
63
67
  */
64
- contrast_register_patch("BasicObject", "instance_eval",
68
+ contrast_check_and_register_instance_patch("BasicObject", "instance_eval",
65
69
  contrast_assess_basic_object_instance_eval);
66
70
  }
@@ -5,7 +5,7 @@ require 'mkmf'
5
5
  require_relative '../lib/contrast/agent/version'
6
6
 
7
7
  def make!
8
- create_makefile "#{ $TO_MAKE }/#{ $TO_MAKE }"
8
+ create_makefile("#{ $TO_MAKE }/#{ $TO_MAKE }")
9
9
  end
10
10
 
11
11
  def ext_path
@@ -22,11 +22,11 @@ module Contrast
22
22
  else
23
23
  ObjectSpace.define_finalizer(key, finalizing_proc)
24
24
  end
25
- super key.__id__, obj
25
+ super(key.__id__, obj)
26
26
  end
27
27
 
28
28
  def [] key
29
- super key.__id__
29
+ super(key.__id__)
30
30
  end
31
31
 
32
32
  # Something is trackable if it is not a collection and either not frozen or it was frozen after we put a
@@ -18,11 +18,20 @@ module Contrast
18
18
  # This is just a holder for our policy. Takes the policy JSON and
19
19
  # converts it into hashes that we can access nicely
20
20
  class Policy < Contrast::Agent::Patching::Policy::Policy
21
+ PROVIDER_CLASSES = [
22
+ Contrast::Agent::Assess::Rule::Provider::HardcodedKey,
23
+ Contrast::Agent::Assess::Rule::Provider::HardcodedPassword
24
+ ].cs__freeze
21
25
  # Indicates the folder in `resources` where this policy lives.
22
26
  def self.policy_folder
23
27
  'assess'
24
28
  end
25
29
 
30
+ def initialize
31
+ super
32
+ load_providers
33
+ end
34
+
26
35
  # Indicates is this feature has been disabled by the configuration,
27
36
  # read at startup, and therefore can never be enabled.
28
37
  def disabled_globally?
@@ -33,11 +42,6 @@ module Contrast
33
42
  Contrast::Agent::Assess::Policy::TriggerNode
34
43
  end
35
44
 
36
- def initialize
37
- super
38
- load_providers
39
- end
40
-
41
45
  # Our policy for dataflow rules is a 'dope ass' JSON file. Rather than
42
46
  # hard code in a bunch of things to monkey patch, we let the JSON file
43
47
  # define the conditions in which sources, propagators, and triggers are
@@ -88,11 +92,6 @@ module Contrast
88
92
  providers[instance.rule_id] = instance
89
93
  end
90
94
  end
91
-
92
- PROVIDER_CLASSES = [
93
- Contrast::Agent::Assess::Rule::Provider::HardcodedKey,
94
- Contrast::Agent::Assess::Rule::Provider::HardcodedPassword
95
- ].cs__freeze
96
95
  end
97
96
  end
98
97
  end
@@ -14,6 +14,14 @@ module Contrast
14
14
  # Ruby object, allowing for dynamic patching over hardcoded patching.
15
15
  class PolicyNode < Contrast::Agent::Patching::Policy::PolicyNode
16
16
  include PolicyNodeUtils
17
+ JSON_TAGS = 'tags'
18
+ JSON_DATAFLOW = 'dataflow'
19
+ # The keys used to read from policy.json to create the individual
20
+ # policy nodes. These are common across node types
21
+ JSON_SOURCE = 'source'
22
+ ALL_TYPE = 'A'
23
+ JSON_TARGET = 'target'
24
+ TO_MARKER = '2'
17
25
 
18
26
  attr_accessor :tags, :type
19
27
  attr_reader :sources, :targets, :source_string, :target_string
@@ -45,7 +53,7 @@ module Contrast
45
53
  @sources = convert_policy_markers(source_string)
46
54
  @targets = convert_policy_markers(target_string)
47
55
  @_use_original_object = ORIGINAL_OBJECT_METHODS.include?(@method_name)
48
- @_use_original_on_bang_method = assign_on_bang_check policy_hash
56
+ @_use_original_on_bang_method = assign_on_bang_check(policy_hash)
49
57
  end
50
58
 
51
59
  def assign_on_bang_check policy_hash
@@ -116,8 +124,6 @@ module Contrast
116
124
  end
117
125
  end
118
126
 
119
- ALL_TYPE = 'A'
120
- TO_MARKER = '2'
121
127
  # Convert our action, built from our source and target, into
122
128
  # the TS appropriate action. That's a single source to single
123
129
  # target marker (A,O,P,R)
@@ -149,13 +155,6 @@ module Contrast
149
155
  @event_action
150
156
  end
151
157
 
152
- # The keys used to read from policy.json to create the individual
153
- # policy nodes. These are common across node types
154
- JSON_SOURCE = 'source'
155
- JSON_TARGET = 'target'
156
- JSON_TAGS = 'tags'
157
- JSON_DATAFLOW = 'dataflow'
158
-
159
158
  # This method will check if a method is fit to use it's original object and
160
159
  # that the method is without bang - it does not change the source, but rather
161
160
  # creates a copy of it.
@@ -216,8 +216,8 @@ module Contrast
216
216
  # If we are using the original object tracking, the preshift object is not created.
217
217
  # Instead identify the source as the original object itself and propagate with it.
218
218
  source = propagation_node.use_original_object? ? propagation_data.object : preshift
219
- handle_propagation propagation_class, propagation_node, source, target
220
- update_properties restore_frozen_state, propagation_node, target, propagation_data, ret
219
+ handle_propagation(propagation_class, propagation_node, source, target)
220
+ update_properties(restore_frozen_state, propagation_node, target, propagation_data, ret)
221
221
  end
222
222
 
223
223
  def handle_propagation propagation_class, propagation_node, source, target
@@ -230,7 +230,7 @@ module Contrast
230
230
 
231
231
  def update_properties restore_frozen_state, propagation_node, target, propagation_data, ret
232
232
  if propagation_node.use_original_on_bang_method?
233
- properties = use_original_object_properties propagation_data
233
+ properties = use_original_object_properties(propagation_data)
234
234
 
235
235
  return unless properties
236
236
  else
@@ -22,6 +22,8 @@ module Contrast
22
22
  attr_reader :untags, :patch_method
23
23
  attr_accessor :action, :patch_class
24
24
 
25
+ TAGGER = 'Tagger'
26
+ PROPAGATOR = 'Propagator'
25
27
  # Most things here carry over from PolicyNode.
26
28
  # A couple things are new / have new rules
27
29
  #
@@ -41,9 +43,6 @@ module Contrast
41
43
  validate
42
44
  end
43
45
 
44
- TAGGER = 'Tagger'
45
- PROPAGATOR = 'Propagator'
46
-
47
46
  def node_class
48
47
  @_node_class ||= tagger? ? TAGGER : PROPAGATOR
49
48
  end
@@ -26,7 +26,7 @@ module Contrast
26
26
  end
27
27
 
28
28
  def propagate _propagation_node, _preshift, _target
29
- raise NoMethodError("Expected Base propagator subclass: #{ cs__class } to implement #propagate")
29
+ raise(NoMethodError("Expected Base propagator subclass: #{ cs__class } to implement #propagate"))
30
30
  end
31
31
  end
32
32
  end
@@ -106,7 +106,8 @@ module Contrast
106
106
  ret
107
107
  else
108
108
  # SELECT
109
- Contrast::Agent::Assess::Policy::Propagator::Select.select_tagger propagation_node, preshift, ret, nil
109
+ Contrast::Agent::Assess::Policy::Propagator::Select.select_tagger(propagation_node, preshift, ret,
110
+ nil)
110
111
  end
111
112
  end
112
113
  end
@@ -31,7 +31,7 @@ module Contrast
31
31
  ::Contrast::ASSESS.tainted_columns[class_name] = tainted_columns.keys
32
32
  end
33
33
 
34
- Contrast::Agent::Assess::Policy::DynamicSourceFactory.create_sources class_type, tainted_columns
34
+ Contrast::Agent::Assess::Policy::DynamicSourceFactory.create_sources(class_type, tainted_columns)
35
35
  end
36
36
 
37
37
  private
@@ -51,7 +51,7 @@ module Contrast
51
51
  if arg.is_a?(String) || arg.is_a?(File)
52
52
  tracked_inputs << arg if tracked_value?(arg)
53
53
  else
54
- iterable_arg tracked_inputs, arg
54
+ iterable_arg(tracked_inputs, arg)
55
55
  end
56
56
  end
57
57
 
@@ -41,7 +41,7 @@ module Contrast
41
41
  source = find_source(propagation_node.sources[0], preshift)
42
42
  return unless (source_properties = Contrast::Agent::Assess::Tracker.properties(source))
43
43
 
44
- update_element_properties propagation_node, target, preshift, source_properties
44
+ update_element_properties(propagation_node, target, preshift, source_properties)
45
45
  nil
46
46
  end
47
47
 
@@ -97,7 +97,7 @@ module Contrast
97
97
  def instrument_string_split
98
98
  @_instrument_string_split ||= begin
99
99
  if ::Contrast::AGENT.patch_yield? && Funchook.available?
100
- require 'cs__assess_yield_track/cs__assess_yield_track'
100
+ require('cs__assess_yield_track/cs__assess_yield_track')
101
101
  end
102
102
  true
103
103
  rescue StandardError => e
@@ -40,7 +40,7 @@ module Contrast
40
40
  source = preshift.object
41
41
  args = preshift.args
42
42
  properties.splat_from(source, ret)
43
- event_data = Contrast::Agent::Assess::Events::EventData.new patcher, ret, source, ret, args
43
+ event_data = Contrast::Agent::Assess::Events::EventData.new(patcher, ret, source, ret, args)
44
44
  properties.build_event(event_data)
45
45
  ret
46
46
  end
@@ -15,13 +15,13 @@ module Contrast
15
15
 
16
16
  JSON_TYPE = 'type'
17
17
  SOURCE_TAG = 'UNTRUSTED'
18
+ SOURCE = 'Source'
18
19
  def initialize source_hash = {}
19
20
  super(source_hash)
20
21
  @type = source_hash[JSON_TYPE]
21
22
  @tags << SOURCE_TAG
22
23
  end
23
24
 
24
- SOURCE = 'Source'
25
25
  def node_class
26
26
  SOURCE
27
27
  end
@@ -93,7 +93,7 @@ module Contrast
93
93
  content_type = Contrast::Agent::REQUEST_TRACKER.current&.response&.content_type
94
94
 
95
95
  if content_type.nil? && trigger_node.collectable?
96
- Contrast::Agent::FINDINGS.collect_finding trigger_node, source, object, ret, *args
96
+ Contrast::Agent::FINDINGS.collect_finding(trigger_node, source, object, ret, *args)
97
97
  return
98
98
  end
99
99
 
@@ -106,8 +106,8 @@ module Contrast
106
106
  handle_new_finding(trigger_node, source, object, ret, request, *args)
107
107
  else # TODO: RUBY-1438 -- remove
108
108
  finding = Contrast::Api::Dtm::Finding.new
109
- event_data = Contrast::Agent::Assess::Events::EventData.new trigger_node, source, object, ret, args
110
- append_to_finding finding, event_data, request
109
+ event_data = Contrast::Agent::Assess::Events::EventData.new(trigger_node, source, object, ret, args)
110
+ append_to_finding(finding, event_data, request)
111
111
  logger.trace('Finding created', node_id: trigger_node.id, source_id: source.__id__,
112
112
  rule: trigger_node.rule_id)
113
113
  report_finding(finding, request)
@@ -143,14 +143,14 @@ module Contrast
143
143
 
144
144
  # If we're out of request context, then we need to report this finding ourselves,
145
145
  # so we'll send it in the one-off activity we created.
146
- Contrast::Agent.messaging_queue.send_event_eventually(activity)
146
+ Contrast::Agent.messaging_queue&.send_event_eventually(activity)
147
147
  end
148
148
 
149
149
  def handle_new_finding trigger_node, source, object, ret, request, *args
150
150
  # sent to reporter
151
151
  # here we will generate new type of finding
152
- ruby_finding = Contrast::Agent::Reporting::Finding.new trigger_node.rule_id
153
- ruby_finding.attach_data trigger_node, source, object, ret, request, *args
152
+ ruby_finding = Contrast::Agent::Reporting::Finding.new(trigger_node.rule_id)
153
+ ruby_finding.attach_data(trigger_node, source, object, ret, request, *args)
154
154
  hash_code = Contrast::Utils::HashDigest.generate_event_hash(ruby_finding, source, request)
155
155
  ruby_finding.hash_code = hash_code
156
156
 
@@ -209,7 +209,7 @@ module Contrast
209
209
  properties = Contrast::Agent::Assess::Tracker.properties(source)
210
210
  return unless properties
211
211
 
212
- build_events finding, properties.event if properties.event
212
+ build_events(finding, properties.event) if properties.event
213
213
 
214
214
  # Google::Protobuf::Map doesn't support merge!, so we have to do this long form
215
215
  source_props = properties.properties
@@ -28,6 +28,21 @@ module Contrast
28
28
 
29
29
  attr_reader :rule_id, :required_tags, :disallowed_tags, :good_value, :bad_value
30
30
 
31
+ ENCODER_START = 'CUSTOM_ENCODED_'
32
+ # By default, any rule will be triggered if the source
33
+ # of the rule event has an untrusted tag range that is
34
+ # not covered by one of its disallowed tags.
35
+ UNTRUSTED = 'UNTRUSTED'
36
+ TRIGGER = 'Trigger'
37
+ VALIDATOR_START = 'CUSTOM_VALIDATED_'
38
+ # If a level 1 rule comes from TeamServer, it will have the
39
+ # tag 'custom-encoder-#{ name }' or 'custom-validator-#{ name }'.
40
+ # All rules should take this into account.
41
+ # Additionally, if something is marked 'limited-chars' it means
42
+ # it has been properly vetted to not contain dangerous input.
43
+ LIMITED_CHARS = 'LIMITED_CHARS'
44
+ CUSTOM_ENCODED = 'CUSTOM_ENCODED'
45
+ CUSTOM_VALIDATED = 'CUSTOM_VALIDATED'
31
46
  def initialize trigger_hash = {}, rule_hash = {}
32
47
  super(trigger_hash)
33
48
  good_value = trigger_hash[JSON_GOOD_VALUE]
@@ -46,7 +61,6 @@ module Contrast
46
61
  validate
47
62
  end
48
63
 
49
- TRIGGER = 'Trigger'
50
64
  def node_class
51
65
  TRIGGER
52
66
  end
@@ -138,10 +152,6 @@ module Contrast
138
152
 
139
153
  private
140
154
 
141
- # By default, any rule will be triggered if the source
142
- # of the rule event has an untrusted tag range that is
143
- # not covered by one of its disallowed tags.
144
- UNTRUSTED = 'UNTRUSTED'
145
155
  def populate_tags required_tags
146
156
  return unless dataflow?
147
157
 
@@ -150,16 +160,6 @@ module Contrast
150
160
  @required_tags << UNTRUSTED
151
161
  end
152
162
 
153
- ENCODER_START = 'CUSTOM_ENCODED_'
154
- VALIDATOR_START = 'CUSTOM_VALIDATED_'
155
- # If a level 1 rule comes from TeamServer, it will have the
156
- # tag 'custom-encoder-#{ name }' or 'custom-validator-#{ name }'.
157
- # All rules should take this into account.
158
- # Additionally, if something is marked 'limited-chars' it means
159
- # it has been properly vetted to not contain dangerous input.
160
- LIMITED_CHARS = 'LIMITED_CHARS'
161
- CUSTOM_ENCODED = 'CUSTOM_ENCODED'
162
- CUSTOM_VALIDATED = 'CUSTOM_VALIDATED'
163
163
  def populate_disallowed disallowed_tags
164
164
  return unless dataflow?
165
165
 
@@ -195,7 +195,7 @@ module Contrast
195
195
  chunking = false
196
196
  ranges = []
197
197
  # find the start and end range of required tags:
198
- search_ranges = find_required_ranges properties, required_tags
198
+ search_ranges = find_required_ranges(properties, required_tags)
199
199
  start_range = search_ranges.first
200
200
  end_range = search_ranges.last + 1
201
201
 
@@ -49,7 +49,7 @@ module Contrast
49
49
 
50
50
  # Use #match? because it doesn't fill out global variables
51
51
  # in the way match or =~ do.
52
- VULNERABLE_PATTERN.match? regexp.source
52
+ VULNERABLE_PATTERN.match?(regexp.source)
53
53
  end
54
54
  end
55
55
  end
@@ -42,8 +42,8 @@ module Contrast
42
42
  return unless event.source_type
43
43
  return unless (current_request = Contrast::Agent::REQUEST_TRACKER.current)
44
44
 
45
- append_to_dtm current_request, event
46
- append_to_ruby_object current_request, event
45
+ append_to_dtm(current_request, event)
46
+ append_to_ruby_object(current_request, event)
47
47
  end
48
48
 
49
49
  def append_to_dtm current_request, event
@@ -91,7 +91,7 @@ module Contrast
91
91
  value.each do |tag|
92
92
  comparison = tag.compare_range(range.begin, range.end)
93
93
  # ABOVE and BELOW are not affected by this check
94
- tags_remove_comparison comparison, tag, remove, add, range
94
+ tags_remove_comparison(comparison, tag, remove, add, range)
95
95
  end
96
96
  value.delete_if { |tag| remove.include?(tag) }
97
97
  Contrast::Utils::TagUtil.ordered_merge(value, add)
@@ -166,7 +166,7 @@ module Contrast
166
166
  comparison = tag.compare_range(range.begin, range.end)
167
167
  length = range.end - range.begin
168
168
  # BELOW is not affected by this check
169
- shift_tags_comparison comparison, add, tag, length, range
169
+ shift_tags_comparison(comparison, add, tag, length, range)
170
170
  end
171
171
  Contrast::Utils::TagUtil.ordered_merge(value, add)
172
172
  end
@@ -12,28 +12,27 @@ module Contrast
12
12
  # 2) the value is a non-empty array of only Fixnums
13
13
  class HardcodedKey
14
14
  include Contrast::Agent::Assess::Rule::Provider::HardcodedValueRule
15
-
15
+ REDACTED_MARKER = ' = [**REDACTED**]'
16
16
  NAME = 'hardcoded-key'
17
- def rule_id
18
- NAME
19
- end
20
-
21
17
  # These are names, determined by the security team (Matt & Ar), that
22
18
  # indicate a field is likely to be a password or secret token of some
23
19
  # sort.
24
20
  KEY_FIELD_NAMES = %w[KEY AES DES IV SECRET].cs__freeze
25
-
26
21
  # These are markers whose presence indicates that a field is more
27
22
  # likely to be a descriptor or requirement than an actual key.
28
23
  # We should ignore fields that contain them.
29
24
  NON_KEY_PARTIAL_NAMES = %w[CONTENT_CODES RESPONSE_CODES ERROR_CODES].cs__freeze
25
+ BYTE_HOLDERS = %i[ARRAY LIST].cs__freeze
26
+
27
+ def rule_id
28
+ NAME
29
+ end
30
30
 
31
31
  def name_passes? constant_string
32
32
  KEY_FIELD_NAMES.any? { |name| constant_string.index(name) } &&
33
33
  NON_KEY_PARTIAL_NAMES.none? { |name| constant_string.index(name) }
34
34
  end
35
35
 
36
- BYTE_HOLDERS = %i[ARRAY LIST].cs__freeze
37
36
  # Determine if the given value node violates the hardcode key rule
38
37
  # @param value_node [RubyVM::AbstractSyntaxTree::Node] the node to
39
38
  # evaluate
@@ -66,7 +65,6 @@ module Contrast
66
65
  true
67
66
  end
68
67
 
69
- REDACTED_MARKER = ' = [**REDACTED**]'
70
68
  def redacted_marker
71
69
  REDACTED_MARKER
72
70
  end
@@ -15,12 +15,9 @@ module Contrast
15
15
  # mixing the characters counts as a violation of this rule
16
16
  class HardcodedPassword
17
17
  include Contrast::Agent::Assess::Rule::Provider::HardcodedValueRule
18
-
19
18
  NAME = 'hardcoded-password'
20
- def rule_id
21
- NAME
22
- end
23
-
19
+ REDACTED_MARKER = ' = "**REDACTED**"'
20
+ PROPERTY_NAME_PATTERN = /^[a-z]+[._][._a-z]*[a-z]+$/.cs__freeze
24
21
  # These are names, determined by the security team (Matt & Ar), that
25
22
  # indicate a field is likely to be a password or secret token of some
26
23
  # sort.
@@ -34,6 +31,10 @@ module Contrast
34
31
  URI
35
32
  ].cs__freeze
36
33
 
34
+ def rule_id
35
+ NAME
36
+ end
37
+
37
38
  # If the constant looks like a password and it doesn't look like a
38
39
  # password descriptor, it passes for this rule
39
40
  def name_passes? constant_string
@@ -62,12 +63,10 @@ module Contrast
62
63
  # characters are probably more likely to appear together in a
63
64
  # default placeholder than in a password. Note this is opposite of
64
65
  # the behavior in Java
65
- PROPERTY_NAME_PATTERN = /^[a-z]+[._][._a-z]*[a-z]+$/.cs__freeze
66
66
  def probably_property_name? value
67
67
  value.match?(PROPERTY_NAME_PATTERN)
68
68
  end
69
69
 
70
- REDACTED_MARKER = ' = "**REDACTED**"'
71
70
  def redacted_marker
72
71
  REDACTED_MARKER
73
72
  end
@@ -86,9 +86,9 @@ module Contrast
86
86
  return unless value_node_passes?(value)
87
87
 
88
88
  if Contrast::Agent::Reporter.enabled?
89
- new_finding_and_reporting mod, name
89
+ new_finding_and_reporting(mod, name)
90
90
  else # TODO: RUBY-1438 -- remove
91
- build_finding mod, name
91
+ build_finding(mod, name)
92
92
  end
93
93
  end
94
94
 
@@ -112,7 +112,7 @@ module Contrast
112
112
  def build_finding clazz, constant_string
113
113
  class_name = clazz.cs__name
114
114
 
115
- finding = assign_finding class_name, constant_string
115
+ finding = assign_finding(class_name, constant_string)
116
116
  activity = Contrast::Api::Dtm::Activity.new
117
117
  activity.findings << finding
118
118
  Contrast::Agent.messaging_queue.send_event_eventually(activity, force: true)
@@ -153,12 +153,12 @@ module Contrast
153
153
 
154
154
  # extract to new method
155
155
  # here we will generate new type of finding
156
- ruby_finding = Contrast::Agent::Reporting::Finding.new rule_id
156
+ ruby_finding = Contrast::Agent::Reporting::Finding.new(rule_id)
157
157
  ruby_finding.hash_code = hash
158
158
  ruby_finding.properties[SOURCE_KEY] = clazz.cs__name
159
159
  ruby_finding.properties[CONSTANT_NAME_KEY] = constant_string
160
160
  ruby_finding.properties[CODE_SOURCE_KEY] = constant_string + redacted_marker
161
- save_and_report_finding ruby_finding, new_preflight
161
+ save_and_report_finding(ruby_finding, new_preflight)
162
162
  end
163
163
 
164
164
  def save_and_report_finding ruby_finding, new_preflight
@@ -17,6 +17,7 @@ module Contrast
17
17
  # These rules check the content of the HTTP Response to determine if something was set incorrectly or
18
18
  # insecurely in it.
19
19
  class BaseRule
20
+ DATA = 'data'.cs__freeze
20
21
  # Analyze a given application response to determine if it violates the rule
21
22
  #
22
23
  # TODO: RUBY-999999 either extract the response's body or memoize it to some degree so that it's not
@@ -47,8 +48,6 @@ module Contrast
47
48
 
48
49
  protected
49
50
 
50
- DATA = 'data'.cs__freeze
51
-
52
51
  # Rules discern which responses they can/should analyze.
53
52
  #
54
53
  # @param response [Contrast::Agent::Response] the response of the application
@@ -82,7 +81,7 @@ module Contrast
82
81
  finding.rule_id = rule_id
83
82
  context = Contrast::Agent::REQUEST_TRACKER.current
84
83
  finding.routes << context.route if context&.route
85
- build_evidence evidence, finding
84
+ build_evidence(evidence, finding)
86
85
  hash = Contrast::Utils::HashDigest.generate_config_hash(finding)
87
86
  finding.hash_code = Contrast::Utils::StringUtils.force_utf8(hash)
88
87
  finding.preflight = Contrast::Utils::PreflightUtil.create_preflight(finding)