contrast-agent 6.2.0 → 6.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/ext/cs__assess_basic_object/cs__assess_basic_object.c +7 -5
  3. data/ext/cs__assess_kernel/cs__assess_kernel.c +14 -3
  4. data/ext/cs__assess_kernel/cs__assess_kernel.h +2 -0
  5. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +10 -3
  6. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +2 -1
  7. data/ext/cs__assess_regexp/cs__assess_regexp.c +9 -7
  8. data/ext/{cs__assess_string_interpolation26/cs__assess_string_interpolation26.c → cs__assess_string_interpolation/cs__assess_string_interpolation.c} +14 -3
  9. data/ext/{cs__assess_string_interpolation26/cs__assess_string_interpolation26.h → cs__assess_string_interpolation/cs__assess_string_interpolation.h} +1 -1
  10. data/ext/{cs__assess_string_interpolation26 → cs__assess_string_interpolation}/extconf.rb +0 -0
  11. data/ext/cs__common/cs__common.c +5 -4
  12. data/ext/cs__contrast_patch/cs__contrast_patch.c +3 -10
  13. data/lib/contrast/agent/assess/events/source_event.rb +16 -12
  14. data/lib/contrast/agent/assess/policy/policy_node.rb +6 -0
  15. data/lib/contrast/agent/assess/policy/propagation_method.rb +3 -39
  16. data/lib/contrast/agent/assess/policy/propagation_node.rb +8 -0
  17. data/lib/contrast/agent/assess/policy/propagator/base.rb +2 -0
  18. data/lib/contrast/agent/assess/policy/source_method.rb +2 -47
  19. data/lib/contrast/agent/assess/policy/source_node.rb +1 -0
  20. data/lib/contrast/agent/assess/policy/trigger_node.rb +8 -0
  21. data/lib/contrast/agent/assess/property/evented.rb +4 -18
  22. data/lib/contrast/agent/assess/tag.rb +19 -0
  23. data/lib/contrast/agent/at_exit_hook.rb +8 -8
  24. data/lib/contrast/agent/inventory/database_config.rb +6 -3
  25. data/lib/contrast/agent/inventory/dependency_analysis.rb +3 -2
  26. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +10 -10
  27. data/lib/contrast/agent/middleware.rb +4 -0
  28. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +27 -2
  29. data/lib/contrast/agent/patching/policy/policy.rb +5 -0
  30. data/lib/contrast/agent/patching/policy/policy_node.rb +6 -0
  31. data/lib/contrast/agent/patching/policy/trigger_node.rb +3 -0
  32. data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +3 -4
  33. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +1 -0
  34. data/lib/contrast/agent/protect/policy/rule_applicator.rb +2 -2
  35. data/lib/contrast/agent/protect/rule/base.rb +1 -0
  36. data/lib/contrast/agent/protect/rule/no_sqli.rb +2 -0
  37. data/lib/contrast/agent/reporting/reporter.rb +32 -7
  38. data/lib/contrast/agent/reporting/reporter_heartbeat.rb +21 -15
  39. data/lib/contrast/agent/reporting/reporting_events/application_update.rb +5 -24
  40. data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +8 -1
  41. data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +8 -1
  42. data/lib/contrast/agent/reporting/reporting_events/finding.rb +7 -1
  43. data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +10 -1
  44. data/lib/contrast/agent/reporting/reporting_events/finding_event_object.rb +11 -1
  45. data/lib/contrast/agent/reporting/reporting_events/finding_event_parent_object.rb +11 -1
  46. data/lib/contrast/agent/reporting/reporting_events/finding_event_property.rb +12 -1
  47. data/lib/contrast/agent/reporting/reporting_events/finding_event_signature.rb +10 -1
  48. data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +11 -1
  49. data/lib/contrast/agent/reporting/reporting_events/finding_event_stack.rb +11 -1
  50. data/lib/contrast/agent/reporting/reporting_events/finding_event_taint_range.rb +11 -1
  51. data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +11 -1
  52. data/lib/contrast/agent/reporting/reporting_events/library_discovery.rb +29 -32
  53. data/lib/contrast/agent/reporting/reporting_events/library_usage_observation.rb +13 -1
  54. data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +11 -8
  55. data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +12 -5
  56. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +8 -1
  57. data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +9 -1
  58. data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +10 -1
  59. data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +11 -4
  60. data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +0 -8
  61. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +1 -4
  62. data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +0 -22
  63. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -3
  64. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +1 -11
  65. data/lib/contrast/agent/request.rb +5 -7
  66. data/lib/contrast/agent/request_context.rb +8 -17
  67. data/lib/contrast/agent/request_context_extend.rb +8 -9
  68. data/lib/contrast/agent/request_handler.rb +9 -38
  69. data/lib/contrast/agent/rule_set.rb +4 -0
  70. data/lib/contrast/agent/service_heartbeat.rb +1 -1
  71. data/lib/contrast/agent/static_analysis.rb +6 -11
  72. data/lib/contrast/agent/telemetry/base.rb +35 -35
  73. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_base.rb +2 -0
  74. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_event.rb +2 -0
  75. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message.rb +5 -2
  76. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception.rb +3 -0
  77. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_frame.rb +3 -0
  78. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions.rb +0 -1
  79. data/lib/contrast/agent/thread_watcher.rb +1 -4
  80. data/lib/contrast/agent/version.rb +1 -1
  81. data/lib/contrast/api/communication/socket.rb +1 -0
  82. data/lib/contrast/api/decorators/message.rb +0 -6
  83. data/lib/contrast/api/decorators.rb +0 -2
  84. data/lib/contrast/components/assess.rb +0 -6
  85. data/lib/contrast/components/config.rb +18 -2
  86. data/lib/contrast/config/base_configuration.rb +0 -13
  87. data/lib/contrast/config/root_configuration.rb +1 -0
  88. data/lib/contrast/config/ruby_configuration.rb +2 -9
  89. data/lib/contrast/configuration.rb +0 -2
  90. data/lib/contrast/extension/assess/eval_trigger.rb +0 -4
  91. data/lib/contrast/extension/assess/hash.rb +3 -2
  92. data/lib/contrast/extension/assess/kernel.rb +22 -0
  93. data/lib/contrast/extension/assess/marshal.rb +16 -0
  94. data/lib/contrast/extension/assess/string.rb +21 -20
  95. data/lib/contrast/framework/base_support.rb +8 -0
  96. data/lib/contrast/framework/manager.rb +6 -20
  97. data/lib/contrast/framework/manager_extend.rb +0 -1
  98. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +11 -16
  99. data/lib/contrast/logger/aliased_logging.rb +2 -0
  100. data/lib/contrast/utils/assess/source_method_utils.rb +0 -9
  101. data/lib/contrast/utils/lru_cache.rb +3 -0
  102. data/lib/contrast/utils/middleware_utils.rb +2 -0
  103. data/lib/contrast/utils/telemetry_client.rb +7 -7
  104. data/resources/assess/policy.json +2 -11
  105. data/ruby-agent.gemspec +1 -1
  106. metadata +22 -20
  107. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report.rb +0 -30
  108. data/lib/contrast/api/decorators/application_update.rb +0 -44
  109. data/lib/contrast/api/decorators/library.rb +0 -56
  110. data/lib/contrast/framework/platform_version.rb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b285299c51379c206ff8c7a64426ef5207594391d59c1ce284bae3a899d6d56f
4
- data.tar.gz: f7847b7523600ebad30ba380cd338d36f6ed2e8136e86d2fdb71f4c7953f530a
3
+ metadata.gz: 3b7fbfe09d8f01268274ec60a3861fc4377278e0e33aafadd29a13aec59348bb
4
+ data.tar.gz: caf12a68dca338f4e1ed0e04483857cd7c55140d8698f1aa55b82c6f85d210c6
5
5
  SHA512:
6
- metadata.gz: 3edc5557919437f5c7f76b741ed4133263bd975baebb6c81d8ac416713571c6ef871e9ab4d3b1ddf34aa0ff548242e71081443bc5c3cd04c2f4bae35b030e866
7
- data.tar.gz: 21c33b917d5f9c0f3b8070bde64b42c8d800dd73c952b0d45830b9d13eb6135ba086c9abf43b3003168f5c3902753cf1a480444bbfca506f00d7bf51b5039d03
6
+ metadata.gz: cd9eb2d8fd9faf79ad16e0d32889806c93178f696ad64aa58cdc046e46c1cb5e0ff463e54cf81e491518fd732a664f5838147f83c791c869d3689695b1255384
7
+ data.tar.gz: '097d53ac525825b0b3b305dafe1be2cc178f7198e057f292561e7ffa4801476dcf151d9a51d6277033dbaf149f6ed0d9b52606aebebeffc7636564eea59bbf74'
@@ -17,9 +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));
20
+ VALUE contrast_check_and_register_instance_patch(const char *module_name,
21
+ const char *method_name,
22
+ VALUE(c_fn)(const int, VALUE *,
23
+ const VALUE));
23
24
 
24
25
  void contrast_assess_instance_eval_trigger_check(VALUE self, VALUE source,
25
26
  VALUE ret) {
@@ -65,6 +66,7 @@ void Init_cs__assess_basic_object(void) {
65
66
  * but if someone else patched BasicObject#instance_eval,
66
67
  * IDK if this is intentional... noting it. -ajm
67
68
  */
68
- contrast_check_and_register_instance_patch("BasicObject", "instance_eval",
69
- contrast_assess_basic_object_instance_eval);
69
+ contrast_check_and_register_instance_patch(
70
+ "BasicObject", "instance_eval",
71
+ contrast_assess_basic_object_instance_eval);
70
72
  }
@@ -26,14 +26,25 @@ contrast_patched_kernel_exec(const int argc, const VALUE *argv,
26
26
  return rb_funcall(self, rb_sym_assess_kernel_exec, argc, *argv);
27
27
  }
28
28
 
29
+ /* Check and see if the Kernel#exec is already prepended */
30
+ VALUE contrast_is_kernel_exec_prepended() {
31
+ return contrast_check_prepended(
32
+ rb_const_get(rb_cObject, rb_intern("Kernel")), rb_sym_kernel_exec,
33
+ Qfalse);
34
+ }
35
+
29
36
  void Init_cs__assess_kernel(void) {
37
+ VALUE rb_sym_kernel_exec = ID2SYM(rb_intern("exec"));
30
38
  kernel_propagator = rb_define_module_under(core_assess, "KernelPropagator");
31
39
  exec_apply_trigger = rb_intern("apply_trigger");
32
40
 
33
41
  rb_sym_assess_kernel_exec =
34
42
  contrast_register_patch("Kernel", "exec", contrast_patched_kernel_exec);
35
43
 
36
- /* should return the same value as above */
37
- rb_sym_assess_kernel_exec = contrast_register_singleton_patch(
38
- "Kernel", "exec", contrast_patched_kernel_exec);
44
+ /* check if prepended and register singleton patch if true */
45
+ if (contrast_is_kernel_exec_prepended() == Qtrue) {
46
+ /* should return the same value as above */
47
+ rb_sym_assess_kernel_exec = contrast_register_singleton_patch(
48
+ "Kernel", "exec", contrast_patched_kernel_exec);
49
+ }
39
50
  }
@@ -3,6 +3,8 @@
3
3
  static VALUE exec_apply_trigger;
4
4
  static VALUE kernel_propagator;
5
5
  static VALUE rb_sym_assess_kernel_exec;
6
+ static VALUE rb_sym_kernel_exec;
7
+ VALUE contrast_is_kernel_exec_prepended();
6
8
 
7
9
  VALUE
8
10
  contrast_patched_kernel_exec(const int argc, const VALUE *argv,
@@ -18,7 +18,7 @@
18
18
  * return rb_marshal_load_with_proc(port, proc);
19
19
  * }
20
20
  */
21
- static VALUE contrast_marshal_module_load(const int argc, const VALUE *argv) {
21
+ static VALUE contrast_marshal_module_prepend(const int argc, const VALUE *argv) {
22
22
  VALUE result;
23
23
  VALUE source_string;
24
24
 
@@ -67,6 +67,13 @@ void Init_cs__assess_marshal_module(void) {
67
67
  rb_sym_assess_marshal_load = rb_intern("cs__load_assess");
68
68
  rb_sym_protect_marshal_load = rb_intern("cs__load_protect");
69
69
 
70
- contrast_register_singleton_prepend_patch("Marshal", "load",
71
- &contrast_marshal_module_load);
70
+ /* check if prepended called form the after_load_patcher */
71
+ VALUE marshal = rb_const_get(rb_cObject, rb_intern("Marshal"));
72
+ VALUE marshal_load = ID2SYM(rb_intern("load"));
73
+ VALUE is_prepended = contrast_check_prepended(marshal, marshal_load, Qfalse);
74
+
75
+ if (is_prepended == Qtrue) {
76
+ contrast_register_singleton_prepend_patch("Marshal", "load",
77
+ &contrast_marshal_module_prepend);
78
+ }
72
79
  }
@@ -5,6 +5,7 @@ static VALUE marshal_propagator;
5
5
  static VALUE rb_sym_assess_marshal_load;
6
6
  static VALUE rb_sym_protect_marshal_load;
7
7
  static VALUE properties_hash;
8
+ static VALUE marshal, marshal_load, is_prepended;
8
9
 
9
10
  /*
10
11
  * Rails is a jerk. In Rails 5, they decided to do away with the alias chaining
@@ -14,7 +15,7 @@ static VALUE properties_hash;
14
15
  * special case this for now.
15
16
  * -HM (shamelessly commenting on DP's work)
16
17
  */
17
- static VALUE contrast_marshal_module_load(const int argc,
18
+ static VALUE contrast_marshal_module_prepend(const int argc,
18
19
  const VALUE *argv);
19
20
 
20
21
  void Init_cs__assess_marshal_module(void);
@@ -7,15 +7,15 @@
7
7
  #include <ruby.h>
8
8
 
9
9
  extern VALUE contrast_force_patch(const int argc, VALUE *argv) {
10
- return contrast_check_and_register_instance_patch(
10
+ return contrast_check_and_register_instance_patch(
11
11
  "Regexp", "=~", contrast_assess_regexp_equal_squiggle);
12
12
  }
13
13
 
14
14
  /* check if method is prepended and register instance alias or prepend patch */
15
15
  VALUE contrast_check_and_register_instance_patch(const char *module_name,
16
- const char *method_name,
17
- VALUE(c_fn)(const int, VALUE *,
18
- const VALUE));
16
+ const char *method_name,
17
+ VALUE(c_fn)(const int, VALUE *,
18
+ const VALUE));
19
19
 
20
20
  void contrast_alias_method(const VALUE target, const char *to,
21
21
  const char *from);
@@ -58,8 +58,10 @@ void Init_cs__assess_regexp(void) {
58
58
  rb_global_variable(&rb_sym_string);
59
59
  rb_sym_back_ref = ID2SYM(rb_intern("back_ref"));
60
60
  rb_global_variable(&rb_sym_back_ref);
61
- rb_define_singleton_method(assess, "contrast_force_repatch_regexp", contrast_force_patch, 0);
61
+ rb_define_singleton_method(assess, "contrast_force_repatch_regexp",
62
+ contrast_force_patch, 0);
62
63
 
63
- rb_sym_assess_regexp_equal_squiggle = contrast_check_and_register_instance_patch(
64
- "Regexp", "=~", contrast_assess_regexp_equal_squiggle);
64
+ rb_sym_assess_regexp_equal_squiggle =
65
+ contrast_check_and_register_instance_patch(
66
+ "Regexp", "=~", contrast_assess_regexp_equal_squiggle);
65
67
  }
@@ -1,14 +1,25 @@
1
1
  /* Copyright (c) 2022 Contrast Security, Inc. See
2
2
  * https://www.contrastsecurity.com/enduser-terms-0317a for more details. */
3
3
 
4
- #include "cs__assess_string_interpolation26.h"
4
+ #include "cs__assess_string_interpolation.h"
5
5
  #include "../cs__common/cs__common.h"
6
+ #include "../cs__scope/cs__scope.h"
6
7
  #include <ruby.h>
7
8
 
8
9
  static VALUE rb_str_concat_literals_hook(size_t num, VALUE *strary) {
9
10
  VALUE result = rb_str_concat_literals_original(num, strary);
10
11
  VALUE rb_params = rb_ary_new_from_values((int)num, strary);
11
- rb_funcall(string_propagator, track_interpolation, 2, rb_params, result);
12
+ VALUE in_contrast_scope = inst_methods_in_cntr_scope(contrast_patcher(), 0);
13
+
14
+ if (in_contrast_scope == Qfalse) {
15
+ /* enter scope */
16
+ inst_methods_enter_cntr_scope(contrast_patcher(), 0);
17
+ rb_funcall(string_propagator, track_interpolation, 2, rb_params,
18
+ result);
19
+ /* exit scope */
20
+ inst_methods_exit_cntr_scope(contrast_patcher(), 0);
21
+ }
22
+
12
23
  return result;
13
24
  }
14
25
 
@@ -20,7 +31,7 @@ static int install_hooks() {
20
31
  return 0;
21
32
  }
22
33
 
23
- void Init_cs__assess_string_interpolation26(void) {
34
+ void Init_cs__assess_string_interpolation(void) {
24
35
  string_propagator =
25
36
  rb_define_class_under(core_assess, "StringPropagator", rb_cObject);
26
37
  track_interpolation = rb_intern("track_interpolation");
@@ -10,4 +10,4 @@ static VALUE rb_str_concat_literals_hook(size_t num, VALUE *strary);
10
10
 
11
11
  static int install_hooks();
12
12
 
13
- void Init_cs__assess_string_interpolation26(void);
13
+ void Init_cs__assess_string_interpolation(void);
@@ -97,9 +97,10 @@ VALUE contrast_register_singleton_prepend_patch(const char *module_name,
97
97
  /* module name c_char "Module"; */
98
98
  /* method name c_char "method"; */
99
99
  /* c_func => pointer */
100
- VALUE contrast_check_and_register_instance_patch(
101
- const char *module_name, const char *method_name,
102
- VALUE(c_fn)(const int, VALUE *, const VALUE)) {
100
+ VALUE contrast_check_and_register_instance_patch(const char *module_name,
101
+ const char *method_name,
102
+ VALUE(c_fn)(const int, VALUE *,
103
+ const VALUE)) {
103
104
 
104
105
  VALUE object, method, is_prepended, patch_type;
105
106
  /* check if method is prepended */
@@ -291,5 +292,5 @@ void Init_cs__common(void) {
291
292
  contrast_check_prepended, 2);
292
293
  /* defined for object lookout */
293
294
  rb_define_singleton_method(assess, "cs__object_method_prepended?",
294
- contrast_lookout_prepended, 4);
295
+ contrast_lookout_prepended, 3);
295
296
  }
@@ -222,19 +222,12 @@ VALUE contrast_run_patches(const VALUE *wrapped_args) {
222
222
  * call site. This means the rest of this function is not executed.
223
223
  */
224
224
 
225
- /* Invoke Contrast post-call patching.
226
- * Post-call patching may transform the return value,
227
- * hence the assignment.
228
- */
229
- transformed_ret = contrast_call_post_patch(method_policy, preshift, object,
225
+ /* Invoke Contrast post-call patching. */
226
+ contrast_call_post_patch(method_policy, preshift, object,
230
227
  original_ret, argc, argv);
231
228
 
232
229
  /* Special case for tracking frozen sources */
233
- if (transformed_ret != Qnil) {
234
- return transformed_ret;
235
- } else {
236
- return original_ret;
237
- }
230
+ return original_ret;
238
231
  }
239
232
 
240
233
  VALUE contrast_ensure_function(const VALUE method_policy) {
@@ -56,18 +56,8 @@ module Contrast
56
56
 
57
57
  # Probably only for source events, but we'll go with source_type instead. java & .net support source_type
58
58
  # in propagation events, so we'll future proof this
59
- def build_event_source_dtm
60
- # You can have a source w/o a name, but not w/o a type
61
- return unless source_type
62
-
63
- dtm = Contrast::Api::Dtm::TraceEventSource.new
64
- dtm.type = forced_source_type
65
- dtm.name = forced_source_name
66
- dtm
67
- end
68
-
69
- # Probably only for source events, but we'll go with source_type instead. java & .net support source_type
70
- # in propagation events, so we'll future proof this
59
+ #
60
+ # @return [Contrast::Agent::Reporting::TraceEventSource, nil]
71
61
  def build_event_source
72
62
  # You can have a source w/o a name, but not w/o a type
73
63
  return unless source_type
@@ -89,6 +79,20 @@ module Contrast
89
79
  event_dtm.target = @policy_node.target_string
90
80
  @policy_node.targets[0]
91
81
  end
82
+
83
+ private
84
+
85
+ # Probably only for source events, but we'll go with source_type instead. java & .net support source_type
86
+ # in propagation events, so we'll future proof this
87
+ def build_event_source_dtm
88
+ # You can have a source w/o a name, but not w/o a type
89
+ return unless source_type
90
+
91
+ dtm = Contrast::Api::Dtm::TraceEventSource.new
92
+ dtm.type = forced_source_type
93
+ dtm.name = forced_source_name
94
+ dtm
95
+ end
92
96
  end
93
97
  end
94
98
  end
@@ -5,6 +5,7 @@ require 'contrast/agent/patching/policy/policy_node'
5
5
  require 'contrast/api/decorators/trace_taint_range_tags'
6
6
  require 'contrast/utils/object_share'
7
7
  require 'contrast/agent/assess/policy/policy_node_utils'
8
+ require 'contrast/components/logger'
8
9
 
9
10
  module Contrast
10
11
  module Agent
@@ -13,6 +14,7 @@ module Contrast
13
14
  # This class functions to translate our policy.json into an actionable
14
15
  # Ruby object, allowing for dynamic patching over hardcoded patching.
15
16
  class PolicyNode < Contrast::Agent::Patching::Policy::PolicyNode
17
+ include Contrast::Components::Logger::InstanceMethods
16
18
  include PolicyNodeUtils
17
19
  JSON_TAGS = 'tags'
18
20
  JSON_DATAFLOW = 'dataflow'
@@ -107,12 +109,16 @@ module Contrast
107
109
  def validate
108
110
  super
109
111
  validate_tags
112
+ rescue ArgumentError => e
113
+ logger.debug('Validation of policy node failed with: ', e)
114
+ nil
110
115
  end
111
116
 
112
117
  # TeamServer is picky. The tags here match to ENUMs there. If there
113
118
  # isn't a matching ENUM in TS land, the database gets got. We really
114
119
  # don't want to get them, so we're going to prevent the node from being
115
120
  # made.
121
+ # @raise[ArgumentError] raises if any of the tags is invalid
116
122
  def validate_tags
117
123
  return unless tags
118
124
 
@@ -133,16 +133,6 @@ module Contrast
133
133
  true
134
134
  end
135
135
 
136
- # Safely duplicate the target, or return nil
137
- #
138
- # @param target [Object] the thing to check for duplication
139
- # @return [Object, nil]
140
- def safe_dup target
141
- target.dup
142
- rescue StandardError => _e
143
- nil
144
- end
145
-
146
136
  # Iterate over each key and value in a hash to allow for propagation to each.
147
137
  #
148
138
  # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
@@ -199,25 +189,11 @@ module Contrast
199
189
  return unless can_propagate?(propagation_node, preshift, target)
200
190
  return unless (propagation_class = find_propagation_class(propagation_node))
201
191
 
202
- restore_frozen_state = false
203
- if target.cs__frozen? && !Contrast::Agent::Assess::Tracker.trackable?(target)
204
- return unless can_handle_frozen?(propagation_node)
205
- return unless (dup = safe_dup(propagation_data.ret))
206
-
207
- restore_frozen_state = true
208
- ret = dup
209
- target = ret
210
- Contrast::Agent::Assess::Tracker.pre_freeze(ret)
211
- ret.cs__freeze
212
- # double check that we were able to finalize the replaced return
213
- return unless Contrast::Agent::Assess::Tracker.trackable?(target)
214
- end
215
-
216
192
  # If we are using the original object tracking, the preshift object is not created.
217
193
  # Instead identify the source as the original object itself and propagate with it.
218
194
  source = propagation_node.use_original_object? ? propagation_data.object : preshift
219
195
  handle_propagation(propagation_class, propagation_node, source, target)
220
- update_properties(restore_frozen_state, propagation_node, target, propagation_data, ret)
196
+ update_properties(propagation_node, target, propagation_data)
221
197
  end
222
198
 
223
199
  def handle_propagation propagation_class, propagation_node, source, target
@@ -228,7 +204,7 @@ module Contrast
228
204
  end
229
205
  end
230
206
 
231
- def update_properties restore_frozen_state, propagation_node, target, propagation_data, ret
207
+ def update_properties propagation_node, target, propagation_data
232
208
  if propagation_node.use_original_on_bang_method?
233
209
  properties = use_original_object_properties(propagation_data)
234
210
 
@@ -248,11 +224,10 @@ module Contrast
248
224
  event_data = Contrast::Agent::Assess::Events::EventData.new(propagation_node,
249
225
  target,
250
226
  propagation_data.object,
251
- ret,
227
+ propagation_data.ret,
252
228
  propagation_data.args)
253
229
  properties.build_event(event_data)
254
230
  logger.trace('Propagation detected', node_id: propagation_node.id, target_id: target.__id__)
255
- restore_frozen_state ? ret : nil
256
231
  end
257
232
 
258
233
  # Find the propagation class from the given node, if one exists.
@@ -269,17 +244,6 @@ module Contrast
269
244
  propagation_class
270
245
  end
271
246
 
272
- # We can handle frozen propagation iff we're allowed to, as determined by configuration, and the target of
273
- # the propagation is a return, as that's a replaceable value.
274
- #
275
- # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs a
276
- # propagation event.
277
- # @return [Boolean]
278
- def can_handle_frozen? propagation_node
279
- ::Contrast::ASSESS.track_frozen_sources? &&
280
- propagation_node.targets[0] == Contrast::Utils::ObjectShare::RETURN_KEY
281
- end
282
-
283
247
  # For certain bang methods we return the same object, no need to create expensive new properties.
284
248
  #
285
249
  # @param propagation_data [Contrast::Agent::Assess::Events::EventData] used to hold object, args
@@ -3,6 +3,7 @@
3
3
 
4
4
  require 'contrast/agent/assess/policy/policy_node'
5
5
  require 'contrast/api/decorators/trace_taint_range_tags'
6
+ require 'contrast/components/logger'
6
7
 
7
8
  module Contrast
8
9
  module Agent
@@ -14,6 +15,8 @@ module Contrast
14
15
  # untrusted data (indicate points in the application where user
15
16
  # controlled input is modified).
16
17
  class PropagationNode < PolicyNode
18
+ include Contrast::Components::Logger::InstanceMethods
19
+
17
20
  JSON_ACTION = 'action'
18
21
  JSON_UNTAGS = 'untags'
19
22
  JSON_PATCH_CLASS = 'patch_class'
@@ -41,6 +44,9 @@ module Contrast
41
44
  @patch_method = propagation_hash[JSON_PATCH_METHOD]
42
45
  @patch_method = @patch_method.to_sym if @patch_method
43
46
  validate
47
+ rescue ArgumentError => e
48
+ logger.error('Propagation Node Initialization failed with: ', e)
49
+ nil
44
50
  end
45
51
 
46
52
  def node_class
@@ -56,6 +62,7 @@ module Contrast
56
62
 
57
63
  # Standard validation + TS trace version two rules:
58
64
  # Must have source, target, and action
65
+ # @raise[ArgumentError] raises if any of the required propagation node field is not valid, or is missing
59
66
  def validate
60
67
  super
61
68
  raise(ArgumentError, "Propagator #{ id } did not have a proper action. Unable to create.") unless action
@@ -78,6 +85,7 @@ module Contrast
78
85
  validate_untags
79
86
  end
80
87
 
88
+ # @raise[ArgumentError] raises if any of the tags is invalid
81
89
  def validate_untags
82
90
  return unless untags
83
91
 
@@ -25,6 +25,8 @@ module Contrast
25
25
  Contrast::Agent::Assess::Tracker.tracked?(value)
26
26
  end
27
27
 
28
+ # @raise [NoMethodError] This is being raised if any of the implementing subclasses does not have
29
+ # that method implemented, but is being called on.
28
30
  def propagate _propagation_node, _preshift, _target
29
31
  raise(NoMethodError("Expected Base propagator subclass: #{ cs__class } to implement #propagate"))
30
32
  end
@@ -35,30 +35,17 @@ module Contrast
35
35
  # @param object [Object] the Object on which the method was invoked
36
36
  # @param ret [Object] the Return of the invoked method
37
37
  # @param args [Array<Object>] the Arguments with which the method was invoked
38
- # @return [Object, nil] the tracked Return or nil if no changes were made
39
38
  def apply_source method_policy, object, ret, args
40
39
  return unless analyze?(method_policy, object, ret, args)
41
40
  return unless (source_node = method_policy.source_node)
42
41
 
43
42
  # used to hold the object and ret
44
43
  source_data = Contrast::Agent::Assess::Events::EventData.new(nil, nil, object, ret, nil)
45
- return unless (target = determine_target(source_node, source_data, args))
46
-
47
- return_val = nil
48
- if target.cs__frozen? && !Contrast::Agent::Assess::Tracker.trackable?(target)
49
- return unless ::Contrast::ASSESS.track_frozen_sources?
50
- return unless source_node.targets[0] == Contrast::Utils::ObjectShare::RETURN_KEY
51
- return unless (dup = safe_dup(source_data.ret))
52
- return unless Contrast::Agent::Assess::Tracker.trackable?(dup)
53
44
 
54
- Contrast::Agent::Assess::Tracker.pre_freeze(dup)
55
- return_val = dup.cs__freeze
56
- target = dup
57
- end
45
+ return unless (target = determine_target(source_node, source_data, args))
46
+ return if target.cs__frozen? && !Contrast::Agent::Assess::Tracker.trackable?(target)
58
47
 
59
48
  process_source(source_node, target, source_data, source_node.type, nil, *args)
60
-
61
- return_val
62
49
  end
63
50
  Contrast::Components::Logger.add_trace_log_timing_for(SourceMethod, :apply_source)
64
51
 
@@ -108,42 +95,10 @@ module Contrast
108
95
  # map
109
96
  # @param args [Array<Object>] the Arguments with which the method was invoked
110
97
  def apply_hash_tags source_node, target, source_data, source_type, *args
111
- to_replace = []
112
98
  target.each_pair do |key, value|
113
- # We only do this for Strings b/c of the way Hash lookup works. To replace another object would break
114
- # hash lookup and, therefore, the application
115
- if replace_hash_key?(key, target)
116
- key = key.dup
117
- to_replace << key
118
- end
119
99
  process_source(source_node, key, source_data, key_type(source_type), key, *args)
120
100
  process_source(source_node, value, source_data, source_type, key, *args)
121
101
  end
122
- handle_hash_key(target, to_replace)
123
- end
124
-
125
- # Given an unfrozen hash, if the key is a String, we should replace it with one that we can finalize,
126
- # allowing us to track that key. This method handles checking if that replace can and should occur.
127
- #
128
- # @param key [Object] the key in the hash that may need replacing.
129
- # @param hash [Hash] the hash to which the key belongs.
130
- # @return [Boolean] whether replace the key in the hash or not.
131
- def replace_hash_key? key, hash
132
- ::Contrast::ASSESS.track_frozen_sources? &&
133
- !hash.cs__frozen? &&
134
- key.is_a?(String) &&
135
- !Contrast::Agent::Assess::Tracker.trackable?(key)
136
- end
137
-
138
- # Hash is designed to keep one instance of the string key in it. We need to remove the existing one and
139
- # replace it with our new tracked one.
140
- def handle_hash_key target, to_replace
141
- to_replace.each do |key|
142
- Contrast::Agent::Assess::Tracker.pre_freeze(key)
143
- key.cs__freeze
144
- value = target.delete(key)
145
- target[key] = value
146
- end
147
102
  end
148
103
 
149
104
  # @param source_node [Contrast::Agent::Assess::Policy::SourceNode] the node to direct applying this source
@@ -35,6 +35,7 @@ module Contrast
35
35
 
36
36
  # Standard validation + TS trace version two rules:
37
37
  # Must have source and type
38
+ # @raise[ArgumentError] raises if any of the required fields is missing or invalid
38
39
  def validate
39
40
  super
40
41
  raise(ArgumentError, "Source #{ id } did not have a proper target. Unable to create.") unless targets&.any?
@@ -4,6 +4,7 @@
4
4
  require 'contrast/agent/assess/policy/trigger/reflected_xss'
5
5
  require 'contrast/agent/assess/policy/trigger/xpath'
6
6
  require 'contrast/api/decorators/trace_taint_range_tags'
7
+ require 'contrast/components/logger'
7
8
 
8
9
  module Contrast
9
10
  module Agent
@@ -15,6 +16,8 @@ module Contrast
15
16
  # vulnerability (indicate points in the application where uncontrolled
16
17
  # user input can do damage).
17
18
  class TriggerNode < PolicyNode # rubocop:disable Metrics/ClassLength
19
+ include Contrast::Components::Logger::InstanceMethods
20
+
18
21
  JSON_BAD_VALUE = 'bad_value'
19
22
  JSON_GOOD_VALUE = 'good_value'
20
23
  JSON_DISALLOWED_TAGS = 'disallowed_tags'
@@ -59,6 +62,9 @@ module Contrast
59
62
  @trigger_method = trigger_hash['trigger_method']
60
63
  @trigger_method = @trigger_method.to_sym if @trigger_method
61
64
  validate
65
+ rescue ArgumentError => e
66
+ logger.error('Trigger Node initialization failed with: ', e)
67
+ nil
62
68
  end
63
69
 
64
70
  def node_class
@@ -143,6 +149,7 @@ module Contrast
143
149
 
144
150
  # Standard validation + TS trace version two rules:
145
151
  # Must have source
152
+ # @raise[ArgumentError] raises if any of the required fields is invalid or missing
146
153
  def validate
147
154
  super
148
155
  # If this isn't a dataflow rule, it can't have a source
@@ -172,6 +179,7 @@ module Contrast
172
179
  @disallowed_tags << (VALIDATOR_START + loud_name)
173
180
  end
174
181
 
182
+ # @raise[ArgumentError] raises if any of the tags is invalid
175
183
  def validate_rule_tags tags
176
184
  return unless tags
177
185
 
@@ -42,27 +42,13 @@ 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
45
  append_to_ruby_object(current_request, event)
47
46
  end
48
47
 
49
- def append_to_dtm current_request, event
50
- if current_request.observed_route.sources.any? do |source|
51
- source.type == event.forced_source_type &&
52
- source.name == event.forced_source_name # rubocop:disable Security/Module/Name
53
- end
54
-
55
- return
56
- end
57
-
58
- event_source_dtm = event.build_event_source_dtm
59
- return unless event_source_dtm
60
-
61
- current_request.observed_route.sources << event_source_dtm
62
- end
63
-
48
+ # @param current_request [Contrast::Agent::RequestContext]
49
+ # @param event [Contrast::Agent::Assess::Events::ContrastEvent]
64
50
  def append_to_ruby_object current_request, event
65
- if current_request.new_observed_route.sources.any? do |source|
51
+ if current_request.observed_route.sources.any? do |source|
66
52
  source.type == event.forced_source_type &&
67
53
  source.name == event.forced_source_name # rubocop:disable Security/Module/Name
68
54
  end
@@ -73,7 +59,7 @@ module Contrast
73
59
  event_source = event.build_event_source
74
60
  return unless event_source
75
61
 
76
- current_request.new_observed_route.sources << event_source
62
+ current_request.observed_route.sources << event_source
77
63
  end
78
64
  end
79
65
  end