{"schema":"threatline.record/2","record":{"id":"GHSA-552r-jc93-7qr3","aliases":["GHSA-552r-jc93-7qr3"],"summary":"RSS weblinks feed (rss/links.php) leaks role-restricted category links to unauthenticated users","details":"## Summary\r\n`rss/links.php` builds the weblinks RSS feed with a hand-written query that omits the per-category role-visibility filter used by the HTML view. An unauthenticated visitor (default `weblinks_module_enabled=1` public + `enable_rss=1`) receives links from LNK categories that an administrator restricted via `category_view` roles.\r\n\r\n## Root Cause\r\nThe HTML weblinks view routes through `ModuleWeblinks::getDataSet()` which constrains the query to `cat_id IN (getAllVisibleCategories('LNK'))` (`system/classes/ModuleWeblinks.php:118,126`). `getAllVisibleCategories('LNK')` (`src/Users/Entity/User.php`) excludes any LNK category with a `category_view` role restriction the current user (a guest holds only role `0`) is not a member of. `rss/links.php` (lines 72-81) re-implements the data query by hand as `WHERE cat_type='LNK' AND cat_org_id = ?` with no `cat_id IN (visible)` clause and never calls `getAllVisibleCategories`, so it emits every LNK category's links including role-restricted ones.\r\n\r\n## Impact\r\nAnonymous disclosure of link name / URL / description / category / creator-name from categories the administrator restricted to a role. Also affects logged-in non-member users under module mode 2. Confidentiality-only (C:L); no integrity/availability impact.\r\n\r\n## Proof of Concept\r\n```\r\nGET /rss/links.php?organization=<shortname>\r\n```\r\nwith no session, when an admin has created a role-restricted LNK category containing private links. The feed returns those restricted links.\r\n\r\n## Attack Chain\r\n1. **Entry:** Admin creates an LNK category restricted to a members-only role via `category_view` and puts private links in it. **Guard:** HTML `modules/links/links.php` -> `getDataSet()` -> `cat_id IN (getAllVisibleCategories('LNK'))`. **Bypass proof:** the `category_view` SQL in `User.php` returns a restricted category only when the user's role IDs intersect its `category_view` rows OR the category has no restriction; a guest (roles = `[0]`) gets neither, so the restricted category is excluded from the HTML view.\r\n2. **Action:** Unauthenticated `GET /rss/links.php?organization=<shortname>`. **Guard:** `rss/links.php:33-37` throws on mode 0 and on (mode 2 && !login). **Bypass proof:** default mode is `1` (`install/db_scripts/preferences.php` `weblinks_module_enabled => '1'`), which matches neither throw branch; `enable_rss=1` by default. Guest passes.\r\n3. **Sink:** server runs the query at `rss/links.php:71-81`. **Guard:** NONE. **Bypass proof:** the WHERE clause is literally `cat_type = 'LNK' AND cat_org_id = ?`; there is no `cat_id IN (...)` and `getAllVisibleCategories` is never called on this path (zero references in `rss/links.php`). Role-restricted categories are returned.\r\n4. **Impact:** anonymous disclosure of role-restricted weblink data.\r\n\r\n## Bypass Evidence\r\n- `rss/links.php` query (lines 71-81): `WHERE cat_type = 'LNK' AND cat_org_id = ?` — no visibility filter.\r\n- HTML path `ModuleWeblinks.php:118,126` uses `cat_id IN (getAllVisibleCategories('LNK'))`.\r\n- Defaults (`install/db_scripts/preferences.php`): `enable_rss=1`, `weblinks_module_enabled=1`.\r\n\r\n## Affected Versions\r\n`<= 5.0.14` (latest release). Unfiltered LNK query present since v5.0.0 through latest release; 5.1-beta also affected.\r\n\r\n## Distinction from prior advisory\r\nDistinct from GHSA-mg9h-42f8-2pmm, which covers the RSS module login gate (`mode 2 && !login`) on `rss/forum.php`/`rss/announcements.php` and explicitly lists `rss/links.php` as secure w.r.t. that gate. This finding is the per-category role-visibility guard — a different check.\r\n\r\n## Suggested Fix\r\nConstrain the `rss/links.php` query to `cat_id IN ($gCurrentUser->getAllVisibleCategories('LNK'))`, mirroring `ModuleWeblinks::getDataSet()`.\r\n\r\n---\r\nReported by **zx (Jace)** — GitHub: @manus-use","categories":["Unclassified"],"product":"admidio/admidio","vendor":"","ecosystem":null,"affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/Admidio/admidio/security/advisories/GHSA-552r-jc93-7qr3","source_modified_at":"2026-10-02T18:01:34Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"other","name":"admidio/admidio"},"range":"<= 5.0.15"}],"fixed_versions":[],"cvss":5.3,"severity":"Medium","kev":{"listed":false},"epss":{"probability":null,"percentile":null,"score_date":null},"published_at":"2026-10-02T18:01:34Z","modified_at":"2026-10-02T18:01:34Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/Admidio/admidio/security/advisories/GHSA-552r-jc93-7qr3","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-02T18:01:34Z"}],"sources":["GitHub Advisory Database"],"references":[],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":null,"confidence":"unknown","reviewed":false},"change_timestamp":"2026-10-02T18:01:34Z","content_hash":"125fea27cfe5e8390e1cb04543684e0313d733a211be263d534933e8308786c7"}}
