{"schema":"threatline.record/2","record":{"id":"GHSA-pqx5-gx68-83h4","aliases":["GHSA-pqx5-gx68-83h4"],"summary":"A logged-in user can copy the body of any page revision into a page they can access via /_api/tags.update","details":"### Impact\n\n`POST /_api/tags.update` (API v1) took a `revisionId` from the request body and saved that revision's body as a new revision of the page given by `pageId`. It checked that the caller may view the page identified by `pageId`, but never checked that the revision belonged to that page.\n\nAn authenticated, non-read-only user who knew (or could guess) the ID of a revision of a page they cannot view could therefore:\n\n1. read that revision's body in the API response (`savedPage`), and\n2. store that body as a new revision of a page they can access, so it stays readable there. The content of that page is replaced by the copied body.\n\n`PUT /_api/v3/page` had the same gap when it looked up the previous revision from a client-supplied `revisionId`. This lookup is reached only when the editor's conflict check is skipped (`origin=editor` and the latest revision's origin is editor or view). The other revision's body could then be used to compute the diff, including the diff sent in the Slack update notification when `isSlackEnabled` and `slackChannels` are sent.\n\nThe read-side counterpart (page view, `comments.get` and comment linking) is GHSA-m72c-xgjf-56ww.\n\n#### Preconditions\n\n- A logged-in user who is not a read-only user.\n- The attacker must know the target revision ID. It is a MongoDB ObjectId (timestamp, per-process random value, counter), so it is not secret by design. A user can create revisions of their own and learn the per-process value and the counter, so IDs created around the same time by the same process may be easier to find than a random value would suggest.\n\n#### Affected versions\n\nThe `revisionId` handling of `tags.update` was introduced in v4.5.5. All versions from v4.5.5 up to and including v8.0.6 are affected.\n\n### Patches\n\nFixed in **v8.0.7**. Both routes now use the looked-up revision only when it belongs to the target page, as `GET /_api/v3/revisions/:id` already did:\n\n- `tags.update` rejects the request.\n- `PUT /_api/v3/page` ignores the foreign revision.\n\n### Workarounds\n\nNone. Upgrade to v8.0.7 or later.\n","categories":["Unclassified"],"product":"growi","vendor":"","ecosystem":null,"affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/growilabs/growi/security/advisories/GHSA-pqx5-gx68-83h4","source_modified_at":"2026-10-27T05:18:35Z","fetched_at":"2026-10-28T08:18:35.509402Z","package":{"ecosystem":"other","name":"growi"},"range":">= 4.5.5, <= 8.0.6"}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/growilabs/growi/security/advisories/GHSA-pqx5-gx68-83h4","source_modified_at":"2026-10-27T05:18:35Z","fetched_at":"2026-10-28T08:18:35.509402Z","package":{"ecosystem":"other","name":"growi"},"version":"8.0.7"}],"cvss":null,"severity":"Medium","kev":{"listed":false},"epss":{"probability":null,"percentile":null,"score_date":null},"published_at":"2026-10-27T05:18:34Z","modified_at":"2026-10-27T05:18:35Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/growilabs/growi/security/advisories/GHSA-pqx5-gx68-83h4","fetched_at":"2026-10-28T08:18:35.509402Z","source_modified_at":"2026-10-27T05:18:35Z"}],"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-27T05:18:35Z","content_hash":"df65ed2c9c8dea5311b7420a3873d9d9b29c53e00e71997e2ffb257b7c6fe21a"}}
