Page MenuHomePhabricator

CVE-2026-102796: Extension:UserPageViewTracker: unauthenticated SQL injection (credential disclosure) via Special:UserPageViewTracker
Closed, ResolvedPublicSecurity

Description

Hello Wikimedia Security Team,

Extension:UserPageViewTracker has an unauthenticated SQL injection on
Special:UserPageViewTracker. The filterusers and ignoreusers request parameters
are string-spliced into a raw SQL condition, so an anonymous visitor can read any
data the wiki's database account can access, including the user table (password
hashes, email, tokens). Reproduces logged out, no browser required.

Scope: UserPageViewTracker is not installed on Wikimedia production wikis; this
affects third-party installs that enable it.

Affected: UserPageViewTracker master 092f04a and the REL1_43, REL1_44, REL1_45,
and REL1_46 branch heads (all vulnerable, unfixed); requires MediaWiki >= 1.40.
The special page uses a MariaDB/MySQL @rownum construct, so it targets
MySQL/MariaDB installs.

Severity:

CVSS 3.1 7.5, AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N. CWE-89. OWASP A1:2017 Injection.

Root cause -- includes/UserPageViewTrackerPager.php, getQueryInfo():

$includeUsers  = "user_name in ( '";
$includeUsers .= implode( "', '", $this->filterUserList ) . "')";
$conds[] = $includeUsers;

filterUserList is explode('|', $request->getVal('filterusers')). The string is
spliced verbatim and pushed as an integer-keyed condition, which IDatabase treats
as a raw SQL fragment (no escaping). ignoreusers (user_name not in (...)) is
identical. Special:UserPageViewTracker declares no getRestriction() and the
extension declares no rights, so it is reachable by anonymous readers.

Reproduce:

Enviornment: (clean MediaWiki 1.43 + MariaDB + UserPageViewTracker 092f04a)

Anonymous (no cookie):
  GET /index.php?title=Special:UserPageViewTracker&filterusers=
      zzz')) UNION SELECT 1,user_name,user_name,0,'p',user_password,'20260721000000','x' FROM user-- -

The response lists every account's user_password hash. I confirmed this locally:
the anonymous request above returned all pbkdf2 hashes (including a canary
account) in the rendered table; a benign filter returns none; the fix below
reduces the attack to zero leaked rows while normal filtering still works.

Fix: build the IN / NOT IN lists through the DB layer instead of string
splicing like $conds['user_name'] = $this->filterUserList for the escaped IN, and
$db->makeList( $this->ignoreUserList ) for NOT IN. Happy to attach a minimal patch
and pre/post fix logs if you'd like.

Coordinated disclosure welcome; happy to align on embargo and credit. Assisted by
automated review, verified by local reproduction; no production systems tested.

Thank you.

Event Timeline

Restricted Application added a subscriber: Aklapper. · View Herald Transcript

Per https://www.mediawiki.org/w/index.php?title=Extension:UserPageViewTracker :

Bug reports and feature requests
Use the talk page. Do not use Wikimedia Phabricator.

CC'ing the maintainer @Sophivorus listed on the wikipage.

Subbing others who might be able to help. This ext isn't Wikimedia-deployed and I'm not sure how active a project it is. Let's wait to add it to the supplemental release until we at least have a patch...

This exists since the import into gerrit with d581a14f32dbf8b4f6058699c975de06915f048e

implode could to be changed to IDatabase::makeList and the outer quotes removed.

 		if ( $this->filterUsers ) {
-			$includeUsers = "user_name in ( '";
-			$includeUsers .= implode( "', '", $this->filterUserList ) . "')";
+			$includeUsers = 'user_name in ( ';
+			$includeUsers .= $this->getDatabase()->makeList( $this->filterUserList ) . ')';
 			$conds[] = $includeUsers;
 		}
 		if ( $this->ignoreUsers ) {
-			$excludeUsers = "user_name not in ( '";
-			$excludeUsers .= implode( "', '", $this->ignoreUserList ) . "')";
+			$excludeUsers = 'user_name not in ( ';
+			$excludeUsers .= $this->getDatabase()->makeList( $this->ignoreUserList ) . ')';
			$conds[] = $excludeUsers;
		}

But I can only provide public patches via gerrit, feal free to treat the code above as public domain/CC0 if used.

But I can only provide public patches via gerrit, feal free to treat the code above as public domain/CC0 if used.

Thanks. In general, it should be fine to push patches like this up to gerrit for MediaWiki extensions, etc. that are not Wikimedia-deployed or bundled with the core security release. But double-checking with the Security-Team is always encouraged. We can re-announce any issues like this within the supplemental release, the next one (T429207) due out towards the end of September 2026.

Hi! I'm monitoring this but I can also only provide public patches. If the Security-Team confirms it's ok, I can help submit or review the patches.

Hi! I'm monitoring this but I can also only provide public patches. If the Security-Team confirms it's ok, I can help submit or review the patches.

This one is fine to go through gerrit publicly. It's not Wikimedia-deployed and not core-bundled.

Change #1319458 had a related patch set uploaded (by Umherirrender; author: Umherirrender):

[mediawiki/extensions/UserPageViewTracker@master] SECURITY: Use Database::makeList to build in/not in sql clause

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

Change #1319458 merged by jenkins-bot:

[mediawiki/extensions/UserPageViewTracker@master] SECURITY: Use Database::makeList to build in/not in sql clause

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

Change #1319471 had a related patch set uploaded (by Umherirrender; author: Umherirrender):

[mediawiki/extensions/UserPageViewTracker@REL1_46] SECURITY: Use Database::makeList to build in/not in sql clause

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

Change #1319472 had a related patch set uploaded (by Umherirrender; author: Umherirrender):

[mediawiki/extensions/UserPageViewTracker@REL1_45] SECURITY: Use Database::makeList to build in/not in sql clause

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

Change #1319473 had a related patch set uploaded (by Umherirrender; author: Umherirrender):

[mediawiki/extensions/UserPageViewTracker@REL1_44] SECURITY: Use Database::makeList to build in/not in sql clause

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

Change #1319474 had a related patch set uploaded (by Umherirrender; author: Umherirrender):

[mediawiki/extensions/UserPageViewTracker@REL1_43] SECURITY: Use Database::makeList to build in/not in sql clause

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

Change #1319471 merged by jenkins-bot:

[mediawiki/extensions/UserPageViewTracker@REL1_46] SECURITY: Use Database::makeList to build in/not in sql clause

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

Change #1319472 merged by jenkins-bot:

[mediawiki/extensions/UserPageViewTracker@REL1_45] SECURITY: Use Database::makeList to build in/not in sql clause

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

Change #1319473 merged by jenkins-bot:

[mediawiki/extensions/UserPageViewTracker@REL1_44] SECURITY: Use Database::makeList to build in/not in sql clause

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

Change #1319474 merged by jenkins-bot:

[mediawiki/extensions/UserPageViewTracker@REL1_43] SECURITY: Use Database::makeList to build in/not in sql clause

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

Fixed master and backported to all supported release branches

sbassett changed the task status from Open to In Progress.Jul 30 2026, 3:53 PM
sbassett triaged this task as Low priority.
sbassett moved this task from Waiting to Watching on the Security-Team board.
mmartorana renamed this task from Extension:UserPageViewTracker: unauthenticated SQL injection (credential disclosure) via Special:UserPageViewTracker to CVE-2026-102796: Extension:UserPageViewTracker: unauthenticated SQL injection (credential disclosure) via Special:UserPageViewTracker.Tue, Sep 29, 4:58 PM
sbassett changed Author Affiliation from N/A to Wikimedia Communities.Wed, Sep 30, 8:33 PM
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.
sbassett moved this task from Watching to Our Part Is Done on the Security-Team board.