From 45c80b08090c2cead5dcfb7c9a8d8fc7bd30c398 Mon Sep 17 00:00:00 2001 From: Al Snow <43523+jasnow@users.noreply.github.com> Date: Sun, 21 Jun 2026 12:37:46 -0400 Subject: [PATCH 1/2] GHSA/SYNC: 2 new advisories --- gems/alchemy_cms/GHSA-mqq5-j7w8-2hgh.yml | 99 ++++++++++++++++++++++++ gems/faraday/CVE-2026-54297.yml | 76 ++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 gems/alchemy_cms/GHSA-mqq5-j7w8-2hgh.yml create mode 100644 gems/faraday/CVE-2026-54297.yml diff --git a/gems/alchemy_cms/GHSA-mqq5-j7w8-2hgh.yml b/gems/alchemy_cms/GHSA-mqq5-j7w8-2hgh.yml new file mode 100644 index 0000000000..902fc5fa30 --- /dev/null +++ b/gems/alchemy_cms/GHSA-mqq5-j7w8-2hgh.yml @@ -0,0 +1,99 @@ +--- +gem: alchemy_cms +ghsa: mqq5-j7w8-2hgh +url: https://github.com/AlchemyCMS/alchemy_cms/security/advisories/GHSA-mqq5-j7w8-2hgh +title: AlchemyCMS - Unauthenticated nested page API leaks restricted and + unpublished content +date: 2026-06-19 +description: | + # Unauthenticated nested page API leaks restricted & unpublished content + + - **Location:** `app/controllers/alchemy/api/pages_controller.rb:28` + (`Api::PagesController#nested`) + - **Affected version:** Alchemy CMS 8.3.0.dev (Rails 8.1.3) + + ## Description + + The unauthenticated `GET /api/pages/nested` endpoint returns the full + page tree to any anonymous caller, including restricted (member-only) + pages and unpublished/draft pages that should be hidden. + Appending `?elements=true` additionally dumps the element/ingredient + **content** of restricted pages, fully bypassing the access control + the sibling `show` and `index` actions enforce. + + ## Root cause + + `Api::PagesController#nested` calls no `authorize!` and applies no + `published`/`restricted` scoping, unlike `show` (`authorize! :show`) + and `index` (`accessible_by(current_ability, :index)`). + `PageTreePreloader` loads `page.self_and_descendants` unfiltered, and + `PageTreeSerializer` emits every page's metadata (and, with `elements`, + `public_version.elements`) with no ability check. + + ## Evidence + + An unauthenticated `GET /api/pages/nested` returns HTTP 200 with the + restricted page (`"restricted":true`) and an unpublished draft + (`"public":false`);`?elements=true` leaks its content (e.g. + `TOPSECRET_RESTRICTED_BODY_proof123`). + The same guest hitting `GET /api/pages/3` (`show`) gets HTTP **403** + `{"error":"Not authorized"}`, proving `nested` returns what `show` + correctly denies. + + ### Reproduction + + ```bash + # 1) Metadata leak (guest, no auth) + curl -s http://localhost:3000/api/pages/nested | python3 -m + json.tool | grep -E '"name"|"restricted"|"public"' + + # 2) Content leak of restricted page + curl -s "http://localhost:3000/api/pages/nested?elements=true" | grep -oE + 'TOPSECRET_RESTRICTED_BODY_[A-Za-z0-9]+|RESTRICTED_RICHTEXT_[A-Za-z0-9]+' + + # 3) Contrast — show denies the same guest + curl -s -o /dev/null -w "show /api/pages/3 -> HTTP %{http_code}\n" + http://localhost:3000/api/pages/3 + ``` + + ### Suggested fix + + ```ruby + def nested + @page = Page.find_by(id: params[:page_id]) || Language.current_root_page + authorize! :show, @page + preloaded_page = PageTreePreloader.new(page: @page, user: + current_alchemy_user, ability: current_ability).call + render json: PageTreeSerializer.new(preloaded_page, ability: current_ability, + user: current_alchemy_user, + elements: params[:elements]) + end + ``` + + Additionally scope `PageTreePreloader`'s `self_and_descendants` via + `accessible_by(current_ability)` and gate element emission in + `PageTreeSerializer#page_elements` behind `opts[:ability].can?(:show, page)`. +cvss_v3: 7.5 +patched_versions: + - "~> 7.4.15" + - "~> 8.0.15" + - "~> 8.1.14" + - ">= 8.2.6" +related: + url: + - https://rubygems.org/gems/alchemy_cms/versions/8.2.6 + - https://github.com/AlchemyCMS/alchemy_cms/releases/tag/v8.2.6 + - https://github.com/AlchemyCMS/alchemy_cms/pull/3988 + - https://github.com/AlchemyCMS/alchemy_cms/pull/3982 + - https://github.com/AlchemyCMS/alchemy_cms/releases/tag/v8.1.14 + - https://github.com/AlchemyCMS/alchemy_cms/pull/3987 + - https://github.com/AlchemyCMS/alchemy_cms/releases/tag/v8.0.15 + - https://github.com/AlchemyCMS/alchemy_cms/pull/3984 + - https://github.com/AlchemyCMS/alchemy_cms/releases/tag/v7.4.15 + - https://github.com/AlchemyCMS/alchemy_cms/pull/3983 + - https://advisories.gitlab.com/gem/alchemy_cms/GHSA-mqq5-j7w8-2hgh + - https://github.com/AlchemyCMS/alchemy_cms/security/advisories/GHSA-mqq5-j7w8-2hgh + - https://github.com/advisories/GHSA-mqq5-j7w8-2hgh +notes: | + - cvss_v3 from GHSA + - No cve value, so no cvss_v2 or cvss_v4 values diff --git a/gems/faraday/CVE-2026-54297.yml b/gems/faraday/CVE-2026-54297.yml new file mode 100644 index 0000000000..ab72ce3c70 --- /dev/null +++ b/gems/faraday/CVE-2026-54297.yml @@ -0,0 +1,76 @@ +--- +gem: faraday +cve: 2026-54297 +ghsa: 98m9-hrrm-r99r +url: https://www.cve.org/CVERecord/SearchResults?query=CVE-2026-54297 +title: Faraday - Uncontrolled recursion in NestedParamsEncoder allows + stack exhaustion DoS via deeply nested query parameters +date: 2026-06-19 +description: | + # Uncontrolled Recursion in NestedParamsEncoder Allows Stack + Exhaustion DoS via Deeply Nested Query Parameters + + ## Summary + + `Faraday::NestedParamsEncoder`, the default nested query parameter + encoder/decoder in Faraday, decodes nested query strings without + enforcing a maximum nesting depth. + + A crafted query string such as: + + ```text + a[x][x][x][x]...[x]=1 + ``` + + causes Faraday to build a deeply nested Ruby `Hash` structure. The + internal `dehash` routine then recursively walks this attacker-controlled + structure without a depth limit. At sufficient depth, Ruby raises an + uncaught `SystemStackError` (`stack level too deep`), crashing the + calling thread or worker. + + This can lead to denial of service in applications that pass + attacker-controlled query strings to Faraday's nested query parsing + or URL-building paths. + + ## Impact + + A relatively small query string can trigger a `SystemStackError` and + crash the calling Ruby thread or worker. + + In my local test environment, a payload of approximately 9.4 KB + was sufficient: + + ```text + depth=3119 + bytes=9360 + result=SystemStackError + message="stack level too deep" + ``` + + Repeated requests with such payloads may cause a denial of service + against applications whose request path forwards, parses, or rebuilds + attacker-controlled query strings through Faraday. + + This issue does not provide remote code execution, authentication + bypass, or data disclosure. The confirmed impact is availability loss. + + ## Reporter + + Reported by: Emre Koca +cvss_v3: 7.5 +patched_versions: + - ">= 2.14.3" +related: + url: + - https://www.cve.org/CVERecord/SearchResults?query=CVE-2026-54297 + - https://rubygems.org/gems/faraday/versions/2.14.3 + - https://github.com/lostisland/faraday/releases/tag/v2.14.3 + - https://github.com/lostisland/faraday/compare/v2.14.2...v2.14.3 + - https://test.osv.dev/vulnerability/GHSA-98m9-hrrm-r99r + - https://advisories.gitlab.com/gem/faraday/CVE-2026-54297 + - https://github.com/lostisland/faraday/security/advisories/GHSA-98m9-hrrm-r99r + - https://github.com/advisories/GHSA-98m9-hrrm-r99r +notes: | + - cvss_v3 from GHSA + - cve is reserved, but no cve at nvd.nist.gov, so no cvss_v2 or cvss_v4 + - Removed a lot of text from description field. See reference for details. From 38a44ab674e09a46a6f78bd60dc71492186b3c87 Mon Sep 17 00:00:00 2001 From: Al Snow <43523+jasnow@users.noreply.github.com> Date: Sun, 21 Jun 2026 14:16:56 -0400 Subject: [PATCH 2/2] Removed description: field POC details --- gems/alchemy_cms/GHSA-mqq5-j7w8-2hgh.yml | 43 ------------------------ 1 file changed, 43 deletions(-) diff --git a/gems/alchemy_cms/GHSA-mqq5-j7w8-2hgh.yml b/gems/alchemy_cms/GHSA-mqq5-j7w8-2hgh.yml index 902fc5fa30..4635e5fa4e 100644 --- a/gems/alchemy_cms/GHSA-mqq5-j7w8-2hgh.yml +++ b/gems/alchemy_cms/GHSA-mqq5-j7w8-2hgh.yml @@ -30,49 +30,6 @@ description: | `PageTreeSerializer` emits every page's metadata (and, with `elements`, `public_version.elements`) with no ability check. - ## Evidence - - An unauthenticated `GET /api/pages/nested` returns HTTP 200 with the - restricted page (`"restricted":true`) and an unpublished draft - (`"public":false`);`?elements=true` leaks its content (e.g. - `TOPSECRET_RESTRICTED_BODY_proof123`). - The same guest hitting `GET /api/pages/3` (`show`) gets HTTP **403** - `{"error":"Not authorized"}`, proving `nested` returns what `show` - correctly denies. - - ### Reproduction - - ```bash - # 1) Metadata leak (guest, no auth) - curl -s http://localhost:3000/api/pages/nested | python3 -m - json.tool | grep -E '"name"|"restricted"|"public"' - - # 2) Content leak of restricted page - curl -s "http://localhost:3000/api/pages/nested?elements=true" | grep -oE - 'TOPSECRET_RESTRICTED_BODY_[A-Za-z0-9]+|RESTRICTED_RICHTEXT_[A-Za-z0-9]+' - - # 3) Contrast — show denies the same guest - curl -s -o /dev/null -w "show /api/pages/3 -> HTTP %{http_code}\n" - http://localhost:3000/api/pages/3 - ``` - - ### Suggested fix - - ```ruby - def nested - @page = Page.find_by(id: params[:page_id]) || Language.current_root_page - authorize! :show, @page - preloaded_page = PageTreePreloader.new(page: @page, user: - current_alchemy_user, ability: current_ability).call - render json: PageTreeSerializer.new(preloaded_page, ability: current_ability, - user: current_alchemy_user, - elements: params[:elements]) - end - ``` - - Additionally scope `PageTreePreloader`'s `self_and_descendants` via - `accessible_by(current_ability)` and gate element emission in - `PageTreeSerializer#page_elements` behind `opts[:ability].can?(:show, page)`. cvss_v3: 7.5 patched_versions: - "~> 7.4.15"