Build1 publisher3 min readPublished
Every wiki that ran MediaWiki External Data before 3.7 needs a hunt for planted PHP shells
Automated exploit attempts hit MediaWiki's External Data extension within a day of the 25 September disclosure of CVE-2026-100382, a CVSS 10.0 flaw. Upgrading to 3.7 closes the entry point but leaves behind any PHP shell an attacker already wrote to disk.
The Engineer · Build desk
Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

What happened
- From version 3.0 the External Data extension could run local programs on the server, and commands passed through one of its parser functions were not filtered.
- Exploitation is confirmed in the wild, and the proof of concept is public in Wikimedia Phabricator task T434961.
- In the reported intrusion, the attacker first queried the API to check whether the extension was installed, then sent a rapid series of POST requests, then retrieved PHP files the payload had just written.
- According to the write-up, Lajoie found the planted shell in the wiki's skins directory.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- exposure A shell that survives the upgrade can still read LocalSettings.php, so the wiki's database credentials, secret keys and API keys stay within an attacker's reach after patching.
- cost Every host that ran a pre-3.7 release has to rotate its database password, secret keys and administrator passwords and replace stored API keys, whether or not a shell turns up.
- decision Scope has to come from the extension list in Special:Version and on disk, because External Data is optional and a MediaWiki build number does not show whether it is installed.
Wikitext is untrusted content. According to a detection write-up on dev.to, External Data's parser function forwarded it into a server-side program invocation, and the default extension setup left that path reachable [3]. The CVE record says no authentication or privilege is required [6]. The write-up concludes that every request reaching a vulnerable wiki is a potential exploitation attempt, successful or not [6].
From the intrusion pattern the post derives four checks [8]. First is a file-system pass over PHP files created since 25 September in writable, web-served directories, with names matching Nx_.php or NX_.php at the front of the queue [8]. Skin and upload directories belong in that first pass [9].
That window opens on the disclosure date. The unfiltered command path dates to version 3.0 [1]. A content-integrity diff has no start date: compare the extension and skin directories against a known-good deployment, and anything an attacker added stands out because it sits outside the platform's version control [11]. I would run the diff first. A shell written before 25 September would fall outside the file-system window and still show up in the diff [2].
In the logs, the post correlates the three intrusion steps from one source address [10]. It calls the last step the most distinctive, because legitimate traffic rarely fetches a file moments after it appears [10]. Its sample filter does not look for that step. The code compiles `api\.php` and prints a line when the pattern matches and the line contains `POST` or `.php` [13]. Every line that matches already contains `.php`, so the `or` test is always true and could be deleted without changing the output [1]. What comes out is every api.php request, GET or POST, and never a GET for a fresh file under skins or uploads [1]. Catching the retrieval needs a second rule for GETs of .php paths other than api.php [1]. To be fair, the author tells readers to treat the output as leads and to correlate source addresses and time clusters [13].
The fourth check is the best advice in the post. It asks operators to verify in the web server's own configuration that upload directories cannot execute PHP [12]. Relying on .htaccess is not proof, because such a rule can be bypassed or ignored depending on configuration [12].
For sizing, a ZoomEye search for `http.body="ExternalData"` returned 1,128 assets at the time of writing [16]. The figure counts response bodies that contain a string [16]. To equal the number of exposed wikis, every hit would have to run a pre-3.7 release and every vulnerable wiki would have to print the string where the crawler looked [3]. The author calls it a scoping hint, not a vulnerability confirmation [16].
Cleanup has an order too. Remove confirmed shells and re-scan, because a partial cleanup leaves the same access path open, then confirm the deployed version on Special:Version as the last step [18].
What to watch
- An update to Phabricator task T434961 or the CVE record dating first exploitation before 25 September would push the file-system search window back.
- Published indicators beyond the Nx_.php naming pattern, such as file hashes or source addresses from the observed campaign, would let operators hunt without relying on creation dates.
- Reports of credentials from LocalSettings.php being used against other systems would turn wiki cleanup into a wider incident for affected operators.