diff --git a/gems/decidim-api/GHSA-ghmh-q25g-gxxx.yml b/gems/decidim-api/GHSA-ghmh-q25g-gxxx.yml new file mode 100644 index 0000000000..dfe1f5f746 --- /dev/null +++ b/gems/decidim-api/GHSA-ghmh-q25g-gxxx.yml @@ -0,0 +1,94 @@ +--- +gem: decidim-api +ghsa: ghmh-q25g-gxxx +url: https://github.com/decidim/decidim/security/advisories/GHSA-ghmh-q25g-gxxx +title: Decidim's comments API allows access to all commentable resources +date: 2026-04-14 +description: | + ### 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. +cvss_v3: 7.5 +unaffected_versions: + - "< 0.0.1" +patched_versions: + - "~> 0.30.5" + - ">= 0.31.1" +related: + url: + - https://github.com/decidim/decidim/security/advisories/GHSA-ghmh-q25g-gxxx + - https://github.com/advisories/GHSA-ghmh-q25g-gxxx diff --git a/gems/decidim-comments/GHSA-ghmh-q25g-gxxx.yml b/gems/decidim-comments/GHSA-ghmh-q25g-gxxx.yml new file mode 100644 index 0000000000..375105f0ab --- /dev/null +++ b/gems/decidim-comments/GHSA-ghmh-q25g-gxxx.yml @@ -0,0 +1,94 @@ +--- +gem: decidim-comments +ghsa: ghmh-q25g-gxxx +url: https://github.com/decidim/decidim/security/advisories/GHSA-ghmh-q25g-gxxx +title: Decidim's comments API allows access to all commentable resources +date: 2026-04-14 +description: | + ### 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. +cvss_v3: 7.5 +unaffected_versions: + - "< 0.0.1" +patched_versions: + - "~> 0.30.5" + - ">= 0.31.1" +related: + url: + - https://github.com/decidim/decidim/security/advisories/GHSA-ghmh-q25g-gxxx + - https://github.com/advisories/GHSA-ghmh-q25g-gxxx diff --git a/gems/decidim-core/GHSA-w5xj-99cg-rccm.yml b/gems/decidim-core/GHSA-w5xj-99cg-rccm.yml new file mode 100644 index 0000000000..760da711c1 --- /dev/null +++ b/gems/decidim-core/GHSA-w5xj-99cg-rccm.yml @@ -0,0 +1,42 @@ +--- +gem: decidim-core +ghsa: w5xj-99cg-rccm +url: https://github.com/decidim/decidim/security/advisories/GHSA-w5xj-99cg-rccm +title: Decidim amendments can be accepted or rejected by anyone +date: 2026-04-14 +description: | + ### 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). +cvss_v3: 7.5 +unaffected_versions: + - "< 0.19.0" +patched_versions: + - "~> 0.30.5" + - ">= 0.31.1" +related: + url: + - https://github.com/decidim/decidim/security/advisories/GHSA-w5xj-99cg-rccm + - https://github.com/decidim/decidim/commit/1b99136a1c7aa02616a0b54a6ab88d12907a57a9 + - https://github.com/advisories/GHSA-w5xj-99cg-rccm diff --git a/gems/iodine/GHSA-2x79-gwq3-vxxm.yml b/gems/iodine/GHSA-2x79-gwq3-vxxm.yml new file mode 100644 index 0000000000..813752acd3 --- /dev/null +++ b/gems/iodine/GHSA-2x79-gwq3-vxxm.yml @@ -0,0 +1,261 @@ +--- +gem: iodine +ghsa: 2x79-gwq3-vxxm +url: https://github.com/boazsegev/facil.io/security/advisories/GHSA-2x79-gwq3-vxxm +title: Uncontrolled resource consumption and loop with unreachable + exit condition in facil.io and downstream iodine ruby gem +date: 2026-04-14 +description: | + ### 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` + + ### 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 + #include + #include + #include + + static void on_request(http_s *h) { + fprintf(stderr, "calling http_parse_body + "); + fflush(stderr); + http_parse_body(h); + fprintf(stderr, "returned from http_parse_body + "); + http_send_body(h, "ok + ", 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 + "]] + 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` +related: + url: + - https://github.com/boazsegev/iodine/releases/tag/v0.7.58 + - https://github.com/boazsegev/facil.io/security/advisories/GHSA-2x79-gwq3-vxxm + - https://github.com/advisories/GHSA-2x79-gwq3-vxxm