Unsafe Reflection Affecting stimulus_reflex package, versions <3.4.2 >=3.5.0-pre0, <3.5.0-rc4


0.0
high

Snyk CVSS

    Attack Complexity Low
    Confidentiality High
    Integrity High
    Availability High

    Threat Intelligence

    EPSS 0.04% (10th percentile)

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications
  • Snyk ID SNYK-RUBY-STIMULUSREFLEX-6427214
  • published 13 Mar 2024
  • disclosed 12 Mar 2024
  • credit Félix Martel

How to fix?

Upgrade stimulus_reflex to version 3.4.2, 3.5.0-rc4 or higher.

Overview

stimulus_reflex is an exciting new way to build modern, reactive, real-time apps with Ruby on Rails.

Affected versions of this package are vulnerable to Unsafe Reflection due to the handling of websocket messages that allow specifying a class_name and method_name. An attacker can manipulate the server-side behavior and potentially cause denial of service by crafting malicious websocket messages that invoke unintended methods on the server. This is particularly concerning with methods like instance_variable_set, which can be used to alter instance variables and influence the application's logic in a harmful way. Additionally, methods intended for debugging or interactive sessions, such as remote_byebug or pry, can be invoked, leading to further security implications. The vulnerability is exacerbated by the fact that the validation of method calls based on required and optional parameters does not adequately restrict access to sensitive or unintended methods.

Note:

Versions >=3.5.0.rc1 <3.5.0.rc4 contain a render_collection method on reflexes with a :req parameter. Calling this method could lead to arbitrary code execution.

Workaround

This can be mitigated by making sure all the reflexes inherit from the ApplicationReflex class and by adding this before_reflex callback to the app/reflexes/application_reflex.rb file:

class ApplicationReflex < StimulusReflex::Reflex
  before_reflex do
    ancestors = self.class.ancestors[0..self.class.ancestors.index(StimulusReflex::Reflex) - 1]
    allowed = ancestors.any? { |a| a.public_instance_methods(false).any?(method_name.to_sym) }

raise ArgumentError.new(&quot;Reflex method &#39;#{method_name}&#39; is not defined on class &#39;#{self.class.name}&#39; or on any of its ancestors&quot;) if !allowed

end end