growi: A logged-in user can copy the body of any page revision into a page they can access via /_api/tags.update
What fixes it
- 8.0.7growi, otherGitHub
A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.
Description
Impact
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.
An authenticated, non-read-only user who knew (or could guess) the ID of a revision of a page they cannot view could therefore:
- read that revision's body in the API response (
savedPage), and - 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.
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.
The read-side counterpart (page view, comments.get and comment linking) is GHSA-m72c-xgjf-56ww.
Preconditions
- A logged-in user who is not a read-only user.
- 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.
Affected versions
The 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.
Patches
Fixed 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:
tags.updaterejects the request.PUT /_api/v3/pageignores the foreign revision.
Workarounds
None. Upgrade to v8.0.7 or later.
Text from GitHub Advisory Database
Affected versions 1
- growi, other>= 4.5.5, <= 8.0.6GitHub