CVE-2024-28121
Reflex arbitrary method call in stimulus_reflex
stimulus_reflex is a system to extend the capabilities of both Rails and Stimulus by intercepting user interactions and passing them to Rails over real-time websockets. In affected versions more methods than expected can be called on reflex instances. Being able to call some of them has security implications. To invoke a reflex a websocket message of the following shape is sent: \"target\":\"[class_name]#[method_name]\",\"args\":[]. The server will proceed to instantiate reflex using the provided class_name as long as it extends StimulusReflex::Reflex. It then attempts to call method_name on the instance with the provided arguments. This is problematic as reflex.method method_name can be more methods that those explicitly specified by the developer in their reflex class. A good example is the instance_variable_set method. This vulnerability has been patched in versions 3.4.2 and 3.5.0.rc4. Users unable to upgrade should: see the backing GHSA advisory for mitigation advice.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
8.8
Reflex arbitrary method call in stimulus_reflex
stimulus_reflex is a system to extend the capabilities of both Rails and Stimulus by intercepting user interactions and passing them to Rails over real-time websockets. In affected versions more methods than expected can be called on reflex instances. Being able to call some of them has security implications. To invoke a reflex a websocket message of the following shape is sent: \"target\":\"[class_name]#[method_name]\",\"args\":[]. The server will proceed to instantiate reflex using the provided class_name as long as it extends StimulusReflex::Reflex. It then attempts to call method_name on the instance with the provided arguments. This is problematic as reflex.method method_name can be more methods that those explicitly specified by the developer in their reflex class. A good example is the instance_variable_set method. This vulnerability has been patched in versions 3.4.2 and 3.5.0.rc4. Users unable to upgrade should: see the backing GHSA advisory for mitigation advice.
- Record
CVE-2024-28121- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-470
- Updated
- 2026-11-02
EUVDEUVD-2024-0913
8.8
stimulus_reflex is a system to extend the capabilities of both Rails and Stimulus by intercepting user interactions and passing them to Rails over real-time websockets. In affected versions more methods than expected can be called on reflex instances. Being able to call some of them has security implications. To invoke a reflex a websocket message of the following shape is sent: \"target\":\"[class_name]#[method_name]\",\"args\":[]. The server will proceed to instantiate reflex using the provided class_name as long as it extends StimulusReflex::Reflex. It then attempts to call method_name on the instance with the provided arguments. This is problematic as reflex.method method_name can be more methods that those explicitly specified by the developer in their reflex class. A good example is the instance_variable_set method. This vulnerability has been patched in versions 3.4.2 and 3.5.0.rc4. Users unable to upgrade should: see the backing GHSA advisory for mitigation advice.
- Record
EUVD-2024-0913- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-f78j-4w3g-4q65
8.8
StimulusReflex arbitrary method call
Summary
More methods than expected can be called on reflex instances. Being able to call some of them has security implications.
Details
To invoke a reflex a websocket message of the following shape is sent:
{
"target": "[class_name]#[method_name]",
"args": []
}
The server will proceed to instantiate reflex using the provided class_name as long as it extends StimulusReflex::Reflex.
It then attempts to call method_name on the instance with the provided arguments ref:
method = reflex.method method_name
required_params = method.parameters.select { |(kind, _)| kind == :req }
optional_params = method.parameters.select { |(kind, _)| kind == :opt }
if arguments.size >= required_params.size && arguments.size <= required_params.size + optional_params.size
reflex.public_send(method_name, *arguments)
end
This is problematic as reflex.method(method_name) can be more methods than those explicitly specified by the developer in their reflex class. A good example is the instance_variable_set method.
<details>
<summary>Read more</summary> Let's imagine a reflex that uses `@user` as a trusted variable in an `after_reflex` callback.
This variable can be overwritten using the following message:
{
"target": "ChatReflex#instance_variable_set",
"args": ["@user", "<admin-id>"]
}
Here are other interesting methods that were found to be available for the ChatReflex sample reflex
remote_byebug: bind a debugging serverpry: drop the process in a REPL session
All in all, only counting :req and :opt parameters helps.
For example around version 1.0 only .arity was checked which allowed access to the system method (.arity == -1)
{
"target": "ChatReflex#system",
"args": ["[command here]"]
}
Using public_send instead of send does not help but the following payloads do not work since :rest parameters are not counted in the current version
{
"target": "ChatReflex#send",
"args": ["system", "[command here]"]
}
{
"target": "ChatReflex#instance_eval",
"args": ["system('[command here]')"]
}
</details>
Pre-versions of 3.5.0 added a render_collection method on reflexes with a :req parameter. Calling this method could lead to arbitrary code execution:
{
"target": "StimulusReflex::Reflex#render_collection",
"args": [
{ "inline": "<% system('[command here]') %>" }
]
}
Patches
Patches are available on RubyGems and on NPM.
The patched versions are:
Workaround
You can add this guard to mitigate the issue if running an unpatched version of the library.
1.) Make sure all your reflexes inherit from the ApplicationReflex class
2.) Add this before_reflex callback to your 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("Reflex method '#{method_name}' is not defined on class '#{self.class.name}' or on any of its ancestors") if !allowed
end
end
- Record
GHSA-f78j-4w3g-4q65- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-470
- Updated
- 2026-11-02
NVD
8.8
stimulus_reflex is a system to extend the capabilities of both Rails and Stimulus by intercepting user interactions and passing them to Rails over real-time websockets. In affected versions more methods than expected can be called on reflex instances. Being able to call some of them has security implications. To invoke a reflex a websocket message of the following shape is sent: \"target\":\"[class_name]#[method_name]\",\"args\":[]. The server will proceed to instantiate reflex using the provided class_name as long as it extends StimulusReflex::Reflex. It then attempts to call method_name on the instance with the provided arguments. This is problematic as reflex.method method_name can be more methods that those explicitly specified by the developer in their reflex class. A good example is the instance_variable_set method. This vulnerability has been patched in versions 3.4.2 and 3.5.0.rc4. Users unable to upgrade should: see the backing GHSA advisory for mitigation advice.
- Record
CVE-2024-28121- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-470
- Updated
- 2026-11-02
OSV
8.8
Reflex arbitrary method call in stimulus_reflex
stimulus_reflex is a system to extend the capabilities of both Rails and Stimulus by intercepting user interactions and passing them to Rails over real-time websockets. In affected versions more methods than expected can be called on reflex instances. Being able to call some of them has security implications. To invoke a reflex a websocket message of the following shape is sent: \"target\":\"[class_name]#[method_name]\",\"args\":[]. The server will proceed to instantiate reflex using the provided class_name as long as it extends StimulusReflex::Reflex. It then attempts to call method_name on the instance with the provided arguments. This is problematic as reflex.method method_name can be more methods that those explicitly specified by the developer in their reflex class. A good example is the instance_variable_set method. This vulnerability has been patched in versions 3.4.2 and 3.5.0.rc4. Users unable to upgrade should: see the backing GHSA advisory for mitigation advice.
- Record
CVE-2024-28121- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-470
- Updated
- 2026-11-02
OSVGHSA-f78j-4w3g-4q65
8.8
StimulusReflex arbitrary method call
Summary
More methods than expected can be called on reflex instances. Being able to call some of them has security implications.
Details
To invoke a reflex a websocket message of the following shape is sent:
{
"target": "[class_name]#[method_name]",
"args": []
}
The server will proceed to instantiate reflex using the provided class_name as long as it extends StimulusReflex::Reflex.
It then attempts to call method_name on the instance with the provided arguments ref:
method = reflex.method method_name
required_params = method.parameters.select { |(kind, _)| kind == :req }
optional_params = method.parameters.select { |(kind, _)| kind == :opt }
if arguments.size >= required_params.size && arguments.size <= required_params.size + optional_params.size
reflex.public_send(method_name, *arguments)
end
This is problematic as reflex.method(method_name) can be more methods than those explicitly specified by the developer in their reflex class. A good example is the instance_variable_set method.
<details>
<summary>Read more</summary> Let's imagine a reflex that uses `@user` as a trusted variable in an `after_reflex` callback.
This variable can be overwritten using the following message:
{
"target": "ChatReflex#instance_variable_set",
"args": ["@user", "<admin-id>"]
}
Here are other interesting methods that were found to be available for the ChatReflex sample reflex
remote_byebug: bind a debugging serverpry: drop the process in a REPL session
All in all, only counting :req and :opt parameters helps.
For example around version 1.0 only .arity was checked which allowed access to the system method (.arity == -1)
{
"target": "ChatReflex#system",
"args": ["[command here]"]
}
Using public_send instead of send does not help but the following payloads do not work since :rest parameters are not counted in the current version
{
"target": "ChatReflex#send",
"args": ["system", "[command here]"]
}
{
"target": "ChatReflex#instance_eval",
"args": ["system('[command here]')"]
}
</details>
Pre-versions of 3.5.0 added a render_collection method on reflexes with a :req parameter. Calling this method could lead to arbitrary code execution:
{
"target": "StimulusReflex::Reflex#render_collection",
"args": [
{ "inline": "<% system('[command here]') %>" }
]
}
Patches
Patches are available on RubyGems and on NPM.
The patched versions are:
Workaround
You can add this guard to mitigate the issue if running an unpatched version of the library.
1.) Make sure all your reflexes inherit from the ApplicationReflex class
2.) Add this before_reflex callback to your 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("Reflex method '#{method_name}' is not defined on class '#{self.class.name}' or on any of its ancestors") if !allowed
end
end
- Record
GHSA-f78j-4w3g-4q65- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-470
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
stimulus_reflexRubyGems |
3.5.0.pre0 up to 3.5.0.rc4 | 3.5.0.rc4 |
stimulus_reflexRubyGems |
before 3.4.2 | 3.4.2 |
stimulus_reflexnpm |
before 3.4.2 | 3.4.2 |
stimulus_reflexnpm |
3.5.0-pre0 up to 3.5.0-rc4 | 3.5.0-rc4 |
stimulus_reflexRubyGems |
3.5.0.pre0 up to 3.5.0.rc4, plus listed versions 3.5.0.pre13.5.0.pre103.5.0.pre23.5.0.pre33.5.0.pre4 Show 8 moreShow less3.5.0.pre53.5.0.pre63.5.0.pre73.5.0.pre83.5.0.pre93.5.0.rc13.5.0.rc23.5.0.rc3 |
3.5.0.rc4 |
stimulus_reflexRubyGems |
before 3.4.2, plus listed versions 0.1.00.1.10.1.100.1.120.1.2 Show 45 moreShow less0.1.30.1.40.1.50.1.60.1.70.1.80.1.90.2.00.3.00.3.10.3.20.3.31.0.01.0.11.0.21.1.01.1.12.0.02.0.12.0.22.1.02.1.12.1.22.1.32.1.42.1.52.1.62.1.72.1.82.1.92.2.02.2.12.2.22.2.33.0.03.1.23.1.33.1.43.2.03.2.0.pre03.2.0.pre13.2.13.2.23.2.2.pre03.2.2.pre1 |
3.4.2 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2024-28121 is a high vulnerability (CVSS 8.8) in Stimulusreflex Stimulus Reflex, published March 12, 2024. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 1.55%, the 75th percentile. Fixed in stimulus_reflex 3.5.0.rc4.
References
github.com/stimulusreflex/stimulus_reflex/security/advisories/GHSA-f78j-4w3g-4q65
github.com/stimulusreflex/stimulus_reflex/commit/538582d240439aab76066c72335ea92096cd0c7f
github.com/stimulusreflex/stimulus_reflex/blob/0211cad7d60fe96838587f159d657e44cee51b9b/app/channels/stimulus_reflex/channel.rb
github.com/stimulusreflex/stimulus_reflex/releases/tag/v3.4.2
github.com/stimulusreflex/stimulus_reflex/releases/tag/v3.5.0.rc4
seclists.org/fulldisclosure/2024/Mar/16
Show 6 moreShow less
github.com/stimulusreflex/stimulus_reflex/commit/d823d7348f9ca42eb6df25574f11974e4f5bc88c
nvd.nist.gov/vuln/detail/CVE-2024-28121
github.com/rubysec/ruby-advisory-db/blob/master/gems/stimulus_reflex/CVE-2024-28121.yml
github.com/advisories/GHSA-f78j-4w3g-4q65
github.com/CVEProject/cvelistV5/tree/main/cves/2024/28xxx/CVE-2024-28121.json
github.com/stimulusreflex/stimulus_reflex
Left out here: 21 versions. The JSON record has them.