Discourse · Report #3689633
Hidden/restricted tags can be mutated through synonym ID paths without per-tag authorization
How it was found
Discourse requires both tag-edit permission and tag visibility for a user to edit a tag. However, the ID-based synonym mutation paths do not consistently enforce that rule for each tag being modified.
TagsController#create_synonyms authorizes only the target tag (guardian.ensure_can_edit_tag!(@tag)) and then forwards attacker-supplied synonym tag IDs to DiscourseTagging.add_or_create_synonyms without verifying that the user can see or edit each referenced synonym tag.
TagSettingsUpdater has the same issue for new_synonyms and removed_synonym_ids: it accepts tag IDs and mutates synonym relationships without per-synonym authorization checks.
In local reproduction on the 2026.4.0-latest source:
- a non-admin tag editor could not view a hidden tag (
GET /tag/:hidden_id/info.jsonreturned 404), - but the same user could still submit the hidden tag's numeric ID to
/tag/:visible_id/synonyms.jsonand/tag/:visible_id/settings.json, - and both paths updated the hidden tag's
target_tag_idsuccessfully.
This is an authorization bypass affecting hidden/restricted tag integrity. If the vendor considers a similar hidden-tag synonym issue already fixed, this should be triaged as an incomplete fix / variant.
- Create a non-admin user in
edit_tags_allowed_groups. - Create one visible tag the user can edit.
- Create one hidden/restricted tag in a tag group the user cannot access.
- Sign in as the non-admin tag editor.
- Request
/tag/<hidden_tag_id>/info.json. - Observe that the response is 404, confirming the hidden tag is not visible.
- Send
POST /tag/<visible_tag_id>/synonyms.jsonwithtags[0][id]=<hidden_tag_id>. - Observe that the request succeeds and the hidden tag becomes a synonym of the visible tag.
- Reset state and send
PUT /tag/<visible_tag_id>/settings.jsonwithtag_settings[new_synonyms][0][id]=<hidden_tag_id>. - Observe that this also succeeds and updates the hidden tag's synonym relationship.
2 examples, 0 failures
Impact
Summary:
A non-admin user with tag-editing permission can modify hidden or restricted tags by supplying their numeric IDs to the synonym creation and tag settings endpoints. Although the user cannot view the hidden tag, the controller only authorizes the visible target tag and does not re-check authorization for each synonym tag ID, allowing hidden tags to be reassigned as synonyms of a visible tag.
This allows a tag editor to modify the synonym relationship of a hidden or restricted tag they are not allowed to view or edit. The practical impact is unauthorized mutation of hidden tag taxonomy and integrity corruption of tag relationships through numeric-ID paths that skip per-synonym authorization checks.