Page MenuHomePhabricator

CVE-2025-53499: AbuseFilter 'abusefiltercheckmatch' API does not check protected variable access restrictions
Closed, ResolvedPublicSecurity

Description

When using the AbuseFilter 'abusefiltercheckmatch' API, I can compare against the value of protected variables that the user cannot see. For example, if CheckUser is installed I can inspect the value of user_unnamed_ip when the user does not have the right to see temporary account IP addresses.

This can happen when comparing against a specific AbuseFilterLog entry (logid) or RecentChange (rcid).

Steps to reproduce

  1. Install the AbuseFilter and CheckUser extensions on your local mediawiki environment
  2. Make a test edit using a temporary account
  3. Log in as a user who has the sysop and checkuser group
  4. Open Special:CheckUser, enter the temporary account name, submit the form, and note the IP used by the temporary account
  5. Go to Special:AbuseFilter/new
  6. In the conditions field, enter something like the following where 1.2.3.4 is replaced with the IP found in step 4
user_unnamed_ip = '1.2.3.4'
  1. Edit using a temporary account again
  2. While logged in as the user with sysop and checkuser, find the AbuseFilterLog entry for the edit performed in step 7 and note down the ID.
  3. Log in as a user who has the sysop group but not the checkuser group
  4. Open Special:AbuseFilterLog/ID where the ID is the ID noted down in step 8, and note that an error is displayed
  5. Open Special:ApiSandbox, select abusefiltercheckmatch as the action, and enter logid as the ID from step 7
  6. Enter user_unnamed_ip = '1.2.3.4' where 1.2.3.4 is the IP you noted down in step 4
  7. Submit the API request and note that the API says that the filter conditions matched the log entry

What happened
The API responded to match the filter log against the filter log entry. For example:

image.png (698×904 px, 50 KB)

What should have happened
The API should have thrown an error saying that the user does not have access to that log entry

Acceptance criteria

  • The AbuseFilter 'abusefiltercheckmatch' API checks protected variable access for both 'logid' and 'rcid' requests

Event Timeline

Proposed patch:

That's a pretty massive patch. It would be great if others who were familiar with AbuseFilter's internals could provide some code review here prior to any attempted production deployment.

Proposed patch:

That's a pretty massive patch. It would be great if others who were familiar with AbuseFilter's internals could provide some code review here prior to any attempted production deployment.

TSP will have a look and comment after we've reviewed.

Functionality broadly lgtm, have some questions/comments:

			if ( $filter->isProtected() ) {
				$varsArray = $this->afVariablesManager->dumpAllVars( $vars, true );

Can this be condensed into the general check below? getForbiddenVariables calls canViewProtectedVariables under the hood and it's called there under a subset of the variables called here.


// Check that the user can see all the protected filters in the abuse_filter_log log.

non-blocking, can happen w/i18n update if any change needs to be made - does this mean variables? Only 1 filter can be checked at a time afaict.


// This is to avoid a user being able to know the value of the variable if they repeatedly try values to

non-blocking, can happen w/i18n update if any change needs to be made - I agree with the logging but the comment isn't clear to me. This doesn't seem to stop the behavior, only surface it, I think? It logs against the filter being tested against so at least in the QA steps listed, I'd only know that someone was looking into the temporary account but I wouldn't be able to tell that they were trial/error-ing their way to an IP.

Functionality broadly lgtm, have some questions/comments:

			if ( $filter->isProtected() ) {
				$varsArray = $this->afVariablesManager->dumpAllVars( $vars, true );

Can this be condensed into the general check below? getForbiddenVariables calls canViewProtectedVariables under the hood and it's called there under a subset of the variables called here.

No, because we are checking that the user can see all the protected variables in the specific abuse_filter_log row. That isn't applicable when providing an rcid or vars. The ::getForbiddenVariables call is specific to the provided test pattern and not the variables that were generated for the action.

This is okay because for the rcid type, the variable won't be checked against if it's not in the test pattern and vars would be specifying the variable value directly anyway (so you would know the value of it).


// Check that the user can see all the protected filters in the abuse_filter_log log.

non-blocking, can happen w/i18n update if any change needs to be made - does this mean variables? Only 1 filter can be checked at a time afaict.

Yes I meant to write "variables" here. Unless we need to modify the patch, I'll leave this as-is.


// This is to avoid a user being able to know the value of the variable if they repeatedly try values to

non-blocking, can happen w/i18n update if any change needs to be made - I agree with the logging but the comment isn't clear to me. This doesn't seem to stop the behavior, only surface it, I think? It logs against the filter being tested against so at least in the QA steps listed, I'd only know that someone was looking into the temporary account but I wouldn't be able to tell that they were trial/error-ing their way to an IP.

Yes it only surfaces it. The idea is that the logging discourages the user from using the trial-and-error method to access the value because it creates the log entry, so they instead would access the value directly. The comment isn't clear on this though. I'd prefer to update it later to avoid another version.

Ah I see, thanks for the clarification. Yes then this lgtm 👍 Comment updates can happen w/the follow-up i18n change needed when this task is public.

Tested this locally and confirmed that:

  • I don't return a match if I don't have access to protected variables
  • Logging works as expected (access recorded on the user associated w/the filter hit)

Fix only needs backporting to REL1_43 and REL1_44, because protected filters did not exist before bf28dbce0e5084340cda84365e4ffe65f020124c which was first present in release 1.43.

Deployed to wmf.6 (and wmf.5 in case of train rollback).

Deployed to wmf.6 (and wmf.5 in case of train rollback).

Thanks, and thanks for adding this to the appropriate tracking tasks!

For a large number of recent changes and abuse logs, I used abusefiltercheckmatch API to test various patterns against them, including those which used protected variables.

I checked that, when the pattern used a protected variable, an unauthorised user always got a "permission denied" response.

Jly renamed this task from AbuseFilter 'abusefiltercheckmatch' API does not check protected variable access restrictions to CVE-2025-53484: AbuseFilter 'abusefiltercheckmatch' API does not check protected variable access restrictions.Jun 30 2025, 7:23 PM
Jly renamed this task from CVE-2025-53484: AbuseFilter 'abusefiltercheckmatch' API does not check protected variable access restrictions to CVE-2025-53499: AbuseFilter 'abusefiltercheckmatch' API does not check protected variable access restrictions.Jun 30 2025, 7:26 PM

Change #1166045 had a related patch set uploaded (by Jly; author: Jly):

[mediawiki/extensions/AbuseFilter@master] SECURITY: Check protected variable access in CheckMatch API

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

Change #1166046 had a related patch set uploaded (by Jly; author: Jly):

[mediawiki/extensions/AbuseFilter@REL1_44] SECURITY: Check protected variable access in CheckMatch API

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

Change #1166047 had a related patch set uploaded (by Jly; author: Jly):

[mediawiki/extensions/AbuseFilter@REL1_43] SECURITY: Check protected variable access in CheckMatch API

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

Change #1166046 merged by jenkins-bot:

[mediawiki/extensions/AbuseFilter@REL1_44] SECURITY: Check protected variable access in CheckMatch API

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

Change #1166045 merged by jenkins-bot:

[mediawiki/extensions/AbuseFilter@master] SECURITY: Check protected variable access in CheckMatch API

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

sbassett triaged this task as Medium priority.Jul 8 2025, 8:45 PM
sbassett changed Author Affiliation from N/A to WMF Product.
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 Medium.

Change #1166047 merged by jenkins-bot:

[mediawiki/extensions/AbuseFilter@REL1_43] SECURITY: Check protected variable access in CheckMatch API

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