Page MenuHomePhabricator

CVE-2023-37301: Wikidata edit filter does not fire when test tool says it should
Closed, ResolvedPublic5 Estimated Story PointsSecurity

Description

https://www.wikidata.org/w/index.php?title=Wikidata:Contact_the_development_team&oldid=1161804660#AbuseFilter_not_triggering_on_edits_that_would_trigger_it
https://www.wikidata.org/wiki/Topic:Vkqokk527p3u4cnp

I created Wikidata edit filter 131 to block certain LTA activity from wide IP blocks, intended as a softer alternative to imposing blocks across many /16 blocks. Since then, while is has been successful in preventing some abuse, there have been multiple cases where it did not fire in cases where it would have been expected to do so. Further, the test tool intended to preview the effect if the tool says that it _does_ fire for those edits. Even if there is some bug in the filter definition, we would expect the filter and the test tool to behave consistently.

Steps to reproduce:

  1. Open https://www.wikidata.org/wiki/Special:AbuseFilter/131
  2. Click on the tool "Test this filter against recent edits"
  3. Under "Changes made to page" enter "Q1447095".
  4. Observe green check marks against certain changes on 2020-04-20 by 113.218.0.173 and 113.218.0.0.
  5. Under "Changes made to page", now enter "Q275139".
  6. Observe green check marks against certain changes on 2020-04-18 by โ€Ž61.187.158.133.

If the edit filter had been operating consistently with the test tool (and the behaviour I expect), then these changes would have been prevented.

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
Restricted Application added a subscriber: Aklapper. ยท View Herald TranscriptApr 20 2020, 5:06 PM

Haven't checked deeply, but a possible hint is that AF doesn't see automatic edit summaries (I think there was a task for that) which, however, it sees when retrospectively examinating edits.

Haven't checked deeply, but a possible hint is that AF doesn't see automatic edit summaries (I think there was a task for that) which, however, it sees when retrospectively examinating edits.

But still, the edit summary it sees (the *real* summary) is something like /* undo:0||REVID|USERNAME */. The filter's summary-related part is designed to catch "undo:0" (not "Undo revision REVID by USERNAME", which is the automatically generated summary).

For information: I have now disabled this edit filter in favour of a set of softblocks on certain /16 IP ranges.

For testing, I re-used blank https://www.wikidata.org/wiki/Special:AbuseFilter/31 with

'undo:0' in summary

During the test, there were at least 9 undo actions (tagged as mw-undo, example) but none of them triggered the filter. So @Daimona may be right...

Haven't checked deeply, but a possible hint is that AF doesn't see automatic edit summaries (I think there was a task for that) which, however, it sees when retrospectively examinating edits.

But still, the edit summary it sees (the *real* summary) is something like /* undo:0||REVID|USERNAME */.

It depends on how you define "real". I have to say, I'm not at all certain about the summary that the filter is effectively seeing, so... I don't even know where the 'undo:0 ...' part is coming from in Wikibase, so I can't tell whether it can be read by the AF.

For testing, I re-used blank https://www.wikidata.org/wiki/Special:AbuseFilter/31 with

'undo:0' in summary

During the test, there were at least 9 undo actions (tagged as mw-undo, example) but none of them triggered the filter. So @Daimona may be right...

Not surprising... I'd be glad to confirm this and investigate it locally, but I don't have Wikibase installed on my wiki, and it's also not so easy to install IIRC (also I'm not practical with it).

matej_suchanek changed the visibility from "Public (No Login Required)" to "Custom Policy".
matej_suchanek changed the subtype of this task from "Task" to "Security Issue".

We are currently dealing with LTA IPs on Wikidata which harass users by undoing their edits. An abuse filter has been created to block them automatically, but it isn't effective, and the addresses evade it seamlessly.

This made me look at this problem again, and unfortunately, abuse filters are apparently not run at all when undoing edits to items on Wikidata.

I am protecting this as a security problem.

SubmitEntityAction (Wikibase), which handles undos, does not fire the EditFilterMergedContentHook, which is the entry point to having the change checked by edit filters.
It claims it does not have to do constraint checks, but edit filters had definitely not been run by then:

repo/includes/Actions/SubmitEntityAction.php
// NOTE: Constraint checks are performed automatically via EntityHandler::validateSave.
$status = $page->doUserEditContent(
	$content,
	$this->getUser(),
	$summary,
	/* flags */ 0,
	$originalRevId ?: false,
	/* tags */ [],
	$undidRevId
);

The least effort fix is to fire the hook from SubmitEntityAction::attemptSave:

diff --git a/repo/includes/Actions/SubmitEntityAction.php b/repo/includes/Actions/SubmitEntityAction.php
index 93fc60f7a0..93a583a8f5 100644
--- a/repo/includes/Actions/SubmitEntityAction.php
+++ b/repo/includes/Actions/SubmitEntityAction.php
@@ -5,6 +5,7 @@ namespace Wikibase\Repo\Actions;
 use Article;
 use Content;
 use IContextSource;
+use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
 use MediaWiki\MediaWikiServices;
 use MediaWiki\Permissions\PermissionManager;
 use MediaWiki\Revision\RevisionRecord;
@@ -28,6 +29,7 @@ use Wikibase\Repo\WikibaseRepo;
  * @author Daniel Kinzler
  */
 class SubmitEntityAction extends EditEntityAction {
+       use ProtectedHookAccessorTrait;

        /**
         * @var SummaryFormatter
@@ -239,6 +241,13 @@ class SubmitEntityAction extends EditEntityAction {
                        return $status;
                }

+               if ( !$this->getHookContainer()->run(
+                       'EditFilterMergedContent',
+                       [ $this->getContext(), $content, &$status, $summary, $this->getUser(), false ]
+               ) ) {
+                       return $status;
+               }
+
                // save edit
                $page = MediaWikiServices::getInstance()->getWikiPageFactory()
                        ->newFromTitle( $title );

Or we should inject MediawikiEditFilterHookRunner which fires the hook, too. I am not sure.

SubmitEntityAction (Wikibase), which handles undos, does not fire the EditFilterMergedContentHook, which is the entry point to having the change checked by edit filters.
It claims it does not have to do constraint checks, but edit filters had definitely not been run by then:

I believe โ€œconstraint checksโ€ refers to constraints like โ€œno two items can have the same sitelinkโ€ (see docs: constraints); I donโ€™t think it would include edit filters.

Or we should inject MediawikiEditFilterHookRunner which fires the hook, too. I am not sure.

Using that class sounds good to me. It can be injected as the WikibaseRepo.EditFilterHookRunner service; HistoryEntityAction looks like itโ€™s possible to inject services into actions, so we can probably reuse some patterns from there.

ItamarWMDE set the point value for this task to 5.Jun 13 2023, 9:53 AM

FTR, according to Re-implement undo action based on EntityContent, the reason that this code doesnโ€™t use the EditEntity interface (which would take care of edit filters and other things) is that EditEntity doesnโ€™t support redirects (EntityDocument and EntityRedirect are disparate types), but undoing redirects needs to be supported.

Task Breakdown notes

  • This justifies making sure this issue is not ocurring in other areas, e.g. EntitySchema
  • We should also make sure it abuse filters work for rollbacks (but this is improbable since most users do not have permissions for rolling back)
  • the current plan of action is mentioned in the comments above

NOTE This is a security patch, which should not go on Gerrit, but rather be attached to this task

We should also make sure it abuse filters work for rollbacks (but this is improbable since most users do not have permissions for rolling back)

AFAIK rollbacks bypass abuse filters on purpose.

NOTE This is a security patch, which should not go on Gerrit, but rather be attached to this task

The Security-Team is always happy to assist with a security deployment once CR looks good. Just ping us here if such assistance is needed.

Or we should inject MediawikiEditFilterHookRunner which fires the hook, too. I am not sure.

Using that class sounds good to me. It can be injected as the WikibaseRepo.EditFilterHookRunner service; HistoryEntityAction looks like itโ€™s possible to inject services into actions, so we can probably reuse some patterns from there.

On second thought, letโ€™s not inject the class. (Use it, but just get it from WikibaseRepo::getEditFilterHookRunner() in the constructor.) SubmitEntityAction is used in both Wikibase and WikibaseLexeme, so converting it to dependency injection will require a bit of patch juggling that we can defer until this can all go public on Gerrit.

Security patch for review:

I ran the repo PHPUnit tests locally and they still pass.

Security patch for review:

I ran the repo PHPUnit tests locally and they still pass.

Reviewed: +2

PS: The new exception in StatsdTimeRecordingEditFilterHookRunner should really be fine, but in general I would prefer a silent ignore or warning in that case for the backport (this is for stats tracking only, after all).

PS: The new exception in StatsdTimeRecordingEditFilterHookRunner should really be fine, but in general I would prefer a silent ignore or warning in that case for the backport (this is for stats tracking only, after all).

Fair enough, letโ€™s switch it out. (We can convert this and other places to real union types once T328921: Drop PHP 7.4 support from MediaWiki is done.)

Diff between old and new patch:

diff --git a/repo/includes/EditEntity/StatsdTimeRecordingEditFilterHookRunner.php b/repo/includes/EditEntity/StatsdTimeRecordingEditFilterHookRunner.php
index 3fe3a1536d..3ed14bc8a6 100644
--- a/repo/includes/EditEntity/StatsdTimeRecordingEditFilterHookRunner.php
+++ b/repo/includes/EditEntity/StatsdTimeRecordingEditFilterHookRunner.php
@@ -57,7 +57,7 @@ public function run( $new, IContextSource $context, $summary ) {
 			} elseif ( $new instanceof EntityContent ) {
 				$entityType = $new->getEntityId()->getEntityType();
 			} else {
-				throw new InvalidArgumentException( '$new must be instance of EntityDocument, EntityRedirect or EntityContent' );
+				$entityType = 'UNKNOWN';
 			}
 			$this->stats->timing(
 				"{$this->timingPrefix}.run.{$entityType}",

Should be deployed now. @matej_suchanek can you confirm? (I guess we should see more matches in the filter 210 abuse log soon?)

Yes. I have just done the same experiment as previously:

For testing, I re-used blank https://www.wikidata.org/wiki/Special:AbuseFilter/31 with

'undo:0' in summary

After a few minutes, several edits were matched.
The variables dump also looks correct at a glance.

It sounds like the security patch is deployed and stable now? If so, can we track this for the next supplemental security release (T333626)? ext:Wikibase isn't bundled.

sbassett changed the task status from Open to In Progress.Jun 15 2023, 5:47 PM
sbassett triaged this task as Medium priority.
sbassett moved this task from Security Patch To Deploy to Watching on the Security-Team board.

It sounds like the security patch is deployed and stable now? If so, can we track this for the next supplemental security release (T333626)? ext:Wikibase isn't bundled.

I think so, yes. Tagging Wikibase Suite release crew for attention.

Is there any ETA for this next supplemental security release? Those are published quarterly in general, right? So end of June/early July?
Asking to anticipate when codes of fixes will be published so it could be released for non-Wikidata Wikibase users.

Is there any ETA for this next supplemental security release? Those are published quarterly in general, right? So end of June/early July?
Asking to anticipate when codes of fixes will be published so it could be released for non-Wikidata Wikibase users.

The Security-Team are requesting CVEs yesterday and today for the next supplemental release, which we hope is out by next Friday, June 30th. Or, at worst, Wednesday, July 5th.

Hello, the patch for this task failed to apply against 1.41.0-wmf.15:

Applying patch /srv/patches/1.41.0-wmf.15/extensions/Wikibase/01-T250720.patch in /srv/mediawiki-staging/php-1.41.0-wmf.15
ERROR: git am: error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch' to see the failed patch

[FAILED] /srv/patches/1.41.0-wmf.15/extensions/Wikibase/01-T250720.patch

Hello, the patch for this task failed to apply against 1.41.0-wmf.15:

Applying patch /srv/patches/1.41.0-wmf.15/extensions/Wikibase/01-T250720.patch in /srv/mediawiki-staging/php-1.41.0-wmf.15
ERROR: git am: error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch' to see the failed patch

[FAILED] /srv/patches/1.41.0-wmf.15/extensions/Wikibase/01-T250720.patch

New patch:

A --3way almost fixed it, but there was a minor conflict in the use statements in repo/tests/phpunit/includes/Actions/EditEntityActionTest.php. This applies fine to Wikibase@master for me, so I assume it will apply to 1.41.0-wmf.15.

Thanks. I've committed the above to /srv/patches.

...
A --3way almost fixed it, but there was a minor conflict in the use statements in repo/tests/phpunit/includes/Actions/EditEntityActionTest.php. This applies fine to Wikibase@master for me, so I assume it will apply to 1.41.0-wmf.15.

Thank you very much for the rebase!

Change 933663 had a related patch set uploaded (by Mstyles; author: Lucas Werkmeister (WMDE)):

[mediawiki/extensions/Wikibase@master] SECURITY: Run edit filters on submit (undo/restore)

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

Change 933663 merged by jenkins-bot:

[mediawiki/extensions/Wikibase@master] SECURITY: Run edit filters on submit (undo/restore)

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

All good from me :)

Thanks so much!

Mstyles renamed this task from Wikidata edit filter does not fire when test tool says it should to CVE-2023-37301: Wikidata edit filter does not fire when test tool says it should.Jun 30 2023, 5:49 PM
Mstyles changed the visibility from "Custom Policy" to "All Users".
Mstyles changed the visibility from "All Users" to "Public (No Login Required)".