Read the docs
TI-2026-66883 Aliases GHSA-mqq5-j7w8-2hgh

AlchemyCMS: Unauthenticated nested page API leaks restricted & unpublished content

Priority LOW 38CWE-862Published · Updated

Key facts

Attack vector
—
Privileges required
—
User interaction
—
Attack complexity
—
Impact type
Security bypass
Confidentiality · integrity · availability
—
Fix status
Fixed

No CVSS vector from any source. Fix status from GitHub. Impact type from CWE-862.

Summary

# 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)`.

Why it matters now

Fix Fixed alchemy_cms (RubyGems): 8.2.6, 8.1.14, 8.0.15 +1

SSVC decision points

Not available: CISA has not published SSVC decision points for this record.

Affected products

VendorProductAffected versionsFixed inStatusSource
—alchemy_cms (RubyGems)8.2.0 to before 8.2.68.2.6Patch availableGHSA-mqq5-j7w8-2hgh
—alchemy_cms (RubyGems)8.1.0 to before 8.1.148.1.14Patch availableGHSA-mqq5-j7w8-2hgh
—alchemy_cms (RubyGems)8.0.0.a to before 8.0.158.0.15Patch availableGHSA-mqq5-j7w8-2hgh
—alchemy_cms (RubyGems)before 7.4.157.4.15Patch availableGHSA-mqq5-j7w8-2hgh
  • alchemy_cms (RubyGems) Vendor— Affected 8.2.0 to before 8.2.6 Fixed in 8.2.6 Patch available GHSA-mqq5-j7w8-2hgh
  • alchemy_cms (RubyGems) Vendor— Affected 8.1.0 to before 8.1.14 Fixed in 8.1.14 Patch available GHSA-mqq5-j7w8-2hgh
  • alchemy_cms (RubyGems) Vendor— Affected 8.0.0.a to before 8.0.15 Fixed in 8.0.15 Patch available GHSA-mqq5-j7w8-2hgh
  • alchemy_cms (RubyGems) Vendor— Affected before 7.4.15 Fixed in 7.4.15 Patch available GHSA-mqq5-j7w8-2hgh

Remediation

  • Fix · GHSA-mqq5-j7w8-2hgh alchemy_cms (RubyGems) Fixed in 8.2.6 Advisory →
  • Fix · GHSA-mqq5-j7w8-2hgh alchemy_cms (RubyGems) Fixed in 8.1.14 Advisory →
  • Fix · GHSA-mqq5-j7w8-2hgh alchemy_cms (RubyGems) Fixed in 8.0.15 Advisory →
  • Fix · GHSA-mqq5-j7w8-2hgh alchemy_cms (RubyGems) Fixed in 7.4.15 Advisory →

Timeline

  1. 2026-10-03 Threatist record created from GHSA-mqq5-j7w8-2hgh

References

Sources

This product uses the NVD API but is not endorsed or certified by the NVD. Sources and licences