PT-2026-120309 · Npm · Apostrophe
Published
2026-10-20
·
Updated
2026-10-20
CVSS v3.1
5.3
Medium
| Vector | AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N |
Summary
The REST route
GET /api/v1/<piece-type>/: id/locales (and the equivalent page route) does not apply the publicApiCheckAsync gate that ApostropheCMS's other read routes enforce. An unauthenticated caller can therefore query this route for any document id and learn whether the document exists and which locales it is published in — a document-existence and locale-metadata disclosure that the read-API is otherwise supposed to gate.Affected
- Repository:
apostrophecms/apostrophe(monorepo packageapostrophe). - Confirmed at 4.32.2 (commit
d3ff8c9== the shipped 4.32.2; unchanged at current HEAD). No fix at time of report. - Stack: Node.js / Express + MongoDB.
- Endpoints:
GET /api/v1/<piece-type>/: id/localesandGET /api/v1/@apostrophecms/page/: id/locales.
Technical detail
- Unsafe:
modules/@apostrophecms/piece-type/index.js:397registers the: id/localesroute with nopublicApiCheckAsync. The page module has the same omission atmodules/@apostrophecms/page/index.js:925. - Gated siblings: the read routes in the same module (e.g.
getAllatpiece-type/index.js:256-263) callpublicApiCheckAsync(:263) to enforce the public-API access policy. - So the
localeshandler (which callsgetLocales()for the document) runs for any caller regardless of the public-API gate the other read routes apply, returning the document's locale/publication metadata without authorization.
Impact
An unauthenticated caller can confirm the existence of a document by
id and enumerate its locales/publication state — information the read-API is meant to gate. Defensibly 4.3 (AC:H) given the opaque id precondition (the caller needs a document id).How it was verified (local only)
Reproduced against
apostrophe@4.32.2 (== commit d3ff8c9) locally with synthetic content:- Source review confirmed the
: id/localesroute lackspublicApiCheckAsyncwhile the sibling read routes have it. - An unauthenticated
GET /api/v1/<piece-type>/< id>/localesreturned the document's locale metadata (existence + locales), while the gated read routes (e.g.getAll) correctly required the public-API policy. - Control: the same route with the
publicApiCheckAsyncgate added (matching the siblings) denies the unauthenticated request — isolating the missing gate as the cause. Synthetic content only; nothing hosted was touched.
Remediation
Add the
publicApiCheckAsync (or equivalent) authorization gate to the : id/locales route in both the piece-type and page modules, matching the sibling read routes, so the locale/existence metadata is only returned to callers permitted by the public-API policy.Credit
Please credit Santosh Kumar Puppala (https://github.com/Santoshkumarpuppala).
Fix
Missing Authorization
Information Disclosure
Found an issue in the description? Have something to add? Feel free to write us 👾
Related Identifiers
Affected Products
Apostrophe