The Signpost

File:Windows Blue Screen on room full of computers.JPG
Grj23
CC0
277
100
800
Special report

What actually happened during the Wikimedia security incident?

screenshot of Meta-Wiki's recent changes feed showing many edits posting a strange message
Recent changes on Meta-Wiki show user accounts with advanced permission posting the message "Закрываем проект", which is Russian for "closing the project".
This security incident is also the subject of this issue's opinion essay, and covered in News and Notes.

It has become the talk of the town that somebody set up us the bomb, that we were on the way to destruction, that Wikipedia was hacked, and other such things.

Well, it kind of was.

A horrifying exploit took place, which could have had catastrophic and far-reaching consequences if used maliciously; instead, it seems to have happened by accident and was used for childish peepee-poopoo vandalism.

The official statement, which you can see here, does not say a whole lot about specifically what happened:


This is not very enlightening, so let's take a closer look.

The actual script, whose source code can be seen from the Phabricator ticket page, is relatively simple. It does not do anything particularly horrifying or complicated; mostly it's just dumb schoolkid vandalism. It cannot actually get into the backend database or the server's shell, which is where private data is stored, and irreversible actions can be taken: all it can do is make a big mess on the wiki.

The way it works hinges on the fact that, on MediaWiki, all users have a page called "common.js", which is where userscripts go. If you're logged in, yours is here; mine is here. On this page, you can put code that is automatically run whenever you load a page on the website. They can either be written in the file itself, or loaded from somewhere else.

In mine, for example, I have it (among other things) load User:JPxG/Difformatter.js, a script I wrote that gives me buttons in the editing box to automatically format external diff URLs (like my 123,456th edit, whose URL is https://en.wikipedia.org/w/index.php?title=&diff=prev&oldid=1336463538 and looks like this) into internal links (like Special:Diff/1336463538, which looks like this). Most userscripts do something along these lines. There are a great number of them, and there is a semi-active newsletter for new ones, which I at one point wrote an issue of.

There is also a page on every wiki called MediaWiki:Common.js, which the English Wikipedia has here, and Meta-Wiki has here. This is a version of the same page that runs for everybody on the entire site. Because this could be very easily used to make a huge mess, either intentionally or unintentionally, access to it is very limited: I am a template editor and an edit filter manager and one of the thousand or so sysops on Wikipedia who have to be elected, and I could put Goatse on the Main Page if I wanted to, but I still cannot edit the site's common.js unless I make a request for another userright, "interface administrator". There are only fifteen of these; in addition to being administrators, they are all serious-business technical editors like Izno and Oshwah who can be trusted around high voltage.

Anyway, here is what Ololoshka562's script does:

  • Loads jQuery, gets the account name of the current user, and checks to see if it has already infected the site. Literally, it fetches the current site's MediaWiki:Common.js and checks to see if it has "Ololoshka562" anywhere in it.
  • Tries to edit the sitewide common.js, and replaces it with a gigantic block of gibberish. This gibberish is also JavaScript, but it's encoded as a URL is, so it is kind of hard to read. The script de-gibberishifies it later, so the only reason it's that way is to make it hard to read the code. Presumably, if it was just written directly, it would be obvious what it did, so it is kind of munged up.
  • Also edits the current user's common.js, and replaces it with the same bolus. Only interface administrators can edit the sitewide common.js, so this allows it to work on people who aren't intadmins.
  • Tries to use Special:Nuke three times. If you aren't an administrator, you can't do anything from this page, but I can use it to delete massive numbers of pages. That is what this script does.
  • Gets twenty random pages and tries to vandalize them by adding a big image (File:Woodpecker10.jpg)[1], as well as a script that tries to load... something... from some sleazy-looking website I've never heard of (basemetrika.ru). This site was, by March 2026, not only nonexistent but also unregistered.
  • Gets twenty more random pages, and tries to delete them. If you aren't an administrator this won't do anything.

The actual bolus of crap that it loads does a few more annoying things:

  • Loads itself.
  • Makes every link to a page called "common.js" unviewable, so you cannot fix it from the normal web interface.
  • Redefines the importScript function so that, when userscripts try to load other userscripts, instead of the local site they load them from cyclowiki.org.

Strewn among this is a bunch of junk that doesn't do anything malicious, and looks like it came from some normal wiki's Common.js (like you would find here) to expand and collapse boxes, tables, and so on.

As far as I can tell, this was either made purely for the lulz, or as part of some puerile beef between two random wikis. It doesn't do anything permanent or extremely dangerous; basically everything it does is within the interface that MediaWiki exposes to users. It does load and execute random JavaScript; at the time it was written, whatever was in those offsite URLs could have been some kind of horrifying smallpox code that stole your banking details. However, it didn't do this when it was actually executed, because the URL didn't exist anymore. Whatever heist this was originally cooked up for, if it was carried out at all, seems to have been finished and wrapped up years ago. This script is basically just a random grenade that was left lying in a cornfield. It was basically harmless, except in the specific scenario where somebody with extremely powerful sitewide permissions decided to import and run it with full privileges, which is usually something that people do not do. Mostly because this kind of thing can happen as a result.

Essentially, to carry the analogy further, a grenade lying in a random cornfield is not a particularly dangerous or sophisticated attack against the nation in question. It would cause significant damage if a head of state picked it up off the ground and fixed to take a bite out of it, but under normal circumstances there are people whose job it is to prevent this from happening.

Why was it the case that this could happen?

In the aftermath of every accident, it is necessary to figure out not just why it happened, but why it was allowed to happen. The "find one guy to yell at" system is alluring, because it is simple, but in most cases it is not sufficient to explain failures. Especially with systems as complex as modern software, it is rarely the case that the person who bumped into the "blow everything up" button is to blame — for starters, why is there a "blow everything up" button in the first place? Was it right next to the light switch?

At the Meta-Wiki page created to discuss the incident, a great deal of confusion ensued. Generally speaking, in the software industry, this is not supposed to happen. Over decades, it has become pretty well understood that some activities are inherently risky, and in most systems there is a framework in place to test them out where it won't blow anything important up.

The basic principle is similar to how, when the army is making some new type of gigantic bomb, and they need to test something by actually blowing it up in real life instead of working it out on graph paper, they go to some sand dunes in the middle of nowhere, even though their offices are in the middle of a densely populated city. Most companies and organizations that develop software have similar arrangements. Indeed, the prevailing practice in most software-related industries is to maintain two copies of infrastructure, called "testing" and "production".

On Wikipedia, there is a single-page version of the Nevada Test and Training range, at the aptly-named Sandbox; there's a whole-website-sized version of it at test.wikipedia.org. The Wikimedia Foundation, which develops a lot of software, has a wide variety of testing environments, which are used for developing the MediaWiki software and testing various things. It's not immediately clear what test was being done here, or why it was being done on the live site, or why it was being done with an account with such high privileges (e.g. an interface administrator).

However, there are some clues. The most likely thing, in any situation like this, is that there wasn't a solidly established framework for whatever was being tested here; either it was a quick, one-off thing that nobody wanted to build a whole testing harness for, or it was something where a whole testing harness would be extremely time-consuming to create. This is not a very good reason to "test in production", as it's called, but it is often necessary on Wikimedia sites. This brings me to my next point.

MediaWiki doesn't really have version control or testing infrastructure

While MediaWiki may seem like a paragon of orderly version control — after all, every action a user account takes is logged, timestamped, diffable and reversible — in practice it has become kind of a mess.

As an example: on the English Wikipedia there are a great deal of templates and modules. The original purpose of the "template" function was to let the periodic table be displayed on every element's article without having to hard-code it in the article source; they now do basically everything. Templates (which use MediaWiki markup and HTML) and modules (which use Lua) do a dizzying variety of things, and handle virtually all elements of a Wikipedia page that aren't the bare text of articles, and sometimes that. They format infoboxes, display maps, organize maintenance, display citations, display a lack of citations, and most importantly provide functions and components for other templates.

Templates and modules all individually have version histories; for example, Special:History/Template:Section sizes. However, most templates on Wikipedia are meta-templates, which call other templates. For example, I created {{Generating stations in California}}, which is the big expandable box at the bottom of Topaz Solar Farm and Gateway Generating Station that lists all the power plants in the state. All of the categories and links are coded into that template. Navboxes are heavily used, so they are a very straightforward and simplified type of template. But even with this one, if you look at the tree of every template that the template itself uses, you get this:

Now, you might think 21 templates (what most programmers would call "dependencies") is not a whole lot for something as big as a navbox. But each of them have their own tree of dependencies. For example, here is every template used in {{Collapsible option}}:

Why does it matter what dependencies a template has? Who cares? Well, there's no form of inter-page version control whatsoever!

When you edit {{Generating stations in California}}, for example, you cannot specify that you want to use the version of {{collapsible option}} from 2026-03-09. The only option is to just use whatever the current version happens to be. This means that, from time to time, templates just break for no apparent reason, and the only way to debug or fix them is to go through everything they transclude individually and see what changed.

More relevantly to this incident, there is no way to "create a testing branch" of the whole dependency tree. If you want to make a version of {{Generating stations in California}} that has different colors, you cannot do this on your local machine, or even on a different Wikimedia site. You need to do it on the English Wikipedia specifically, because the English Wikipedia is the only MediaWiki install in the world that has this specific panoply of templates and modules and meta-templates. It's possible to create a separate copy of the template, on the English Wikipedia — most templates (especially complicated ones) have a sandbox subpage where you can test modifications. But there's no way to actually replicate the testing environment without replicating the entire English Wikipedia.

If templates were designed as a programming framework, there might be, but they weren't; they were designed as a way to put the periodic table at the bottom of articles about elements.

This may seem like it has nothing to do with userscripts, and I admit it is a long digression, but I mention it to illustrate a fundamental point about MediaWiki: it's a quarter-century-tall stack of weird kludges built on stuff that in most cases wasn't designed for its current purpose. Any time you are asking yourself why some weird thing happened, this is probably a big part of the answer.

What is to be done?

I may be biased in my characterization of the situation, but as far as I can tell, the root issue here is likely not that the Wikimedia Foundation employed engineers to poke around with the software, but rather that they did not employ enough engineers to poke around with the software.

The one thing that seems pretty clear is that this was not some kind of sophisticated cyberattack, and there was no Tom Clancy business — it was just a random grenade lying in a cornfield that was for some reason imported and run with one of the highest privilege levels possible. It did not have shell access, and it did not have database admin access, but it did have the ability to load random scripts for viewers of the site.

In all likelihood, whoever Ololoshka562 is had no clue that it was even happening, and certainly did not plant it there to make this incident happen on purpose. This is quite fortunate, because if they had, it could have been a giant global catastrophe. Wikipedia is one of the world's most widely-used websites, and it did not have an arbitrary code execution incident, but seemingly purely by coincidence. This is a pretty narrow bullet-dodge (or nuke-dodge as the case may be), and some changes need to be made.

What changes I cannot say. It's hard to say exactly what went wrong, and whether it was an infrastructure issue or an organizational issue or what — but it was very fucking bad, and it is of paramount importance that it never happen again.

Notes

  1. ^ This image currently depicts two birds getting it on, which aligns with the general immaturity of the enterprise, but it was only uploaded after the exploit occurred, so who knows what it originally was.
+ Add a comment

Discuss this story

These comments are automatically transcluded from this article's talk page. To follow comments, add the page to your watchlist. If your comment has not appeared here, you can try purging the cache.
  • Odd to realize that the same software we all use every day on Wikipedia and let into our devices under the axiom that ‘of course it’s safe, it’s MediaWiki,’ can be ‘hacked’ so easily that a simple accident caused all of this. Better discovered by accident than through an intentional attack before we’re even aware that MediaWiki has this vulnerability, though, so in a way I think we’re lucky this happened before it was exploited by someone. Shadestar474 (they/he) (talk) 04:52, 10 March 2026 (UTC)[reply]
  • Yikes! Thank goodness this was handled quickly. As Shadestar474 states above, better to find out about this sooner than later. TheTechie[she/they] | talk? 04:55, 10 March 2026 (UTC)[reply]
  • There's a reason the top of our common.js pages says Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. There are plenty of editors making really useful scripts, but you just can't be running scripts if you don't know what they are. This goes doubly for administrators and infinitely more for people who have more serious privileges. With that said, this was obviously a mistake and in the end no harm was done. Thebiguglyalien (talk) 05:09, 10 March 2026 (UTC)[reply]
  • If the situation was resolved quickly, mainstream media would have covered the incident. Gladly, only Bleeping Computer covered the incident. Ahri Boy (talk) 05:51, 10 March 2026 (UTC)[reply]
  • The image of the Woodpeckers mating was not present at the time of the incident. The image did not exist on Commons. I saw the red link during the incident. The current image was added on March 9, 2026. Ellywa (talk) 06:49, 10 March 2026 (UTC)[reply]
    I was going to comment the same thing. Good thing it has been corrected now: "by adding what's now a photograph of two woodpeckers mating (this file didn't exist when vandalism occured)" Bennylin (talk) 10:20, 10 March 2026 (UTC)[reply]
  • FYI, More relevantly to this incident, there is no way to "create a testing branch" of the whole dependency tree. is not true. In many cases you can fairly easily use Special:Export to export the whole dependency tree, then on your testing wiki use Special:Import to import it. In some cases you may also need to track down code from MediaWiki:Common.js or MediaWiki:Common.css to copy, although TemplateStyles has made this less necessary in many cases. Anomie 07:01, 10 March 2026 (UTC)[reply]
  • Some notes about the script: Tries to edit the sitewide common.js, and replace it with a gigantic block of gibberish. This gibberish is also JavaScript, but it's encoded as a URL is, so it is kind of hard to read.The script de-gibberishifies it later, so the only reason it's that way is to make it hard to read the code. Presumably, if it was just written directly, it would be obvious what it did, so it is kind of munged up. - I think this is the incorrect conclusion to draw. This code needs to be url encoded due to the way it is working - its doing find and replace on things that have already been percent encoded. Best practise would probably be to write it encodeURIComponent( 'non-encoded code here' ) instead of directly encoding it for easier reading, but regardless the percent encoding appears to mostly have to do with the structure of the code. I don't believe it was an attempt at obfuscation. then add a tracking script to load... something... from some sleazy-looking website I've never heard of. This site was, by March 2026, not only nonexistent but also unregistered. - one thing to note here is it appears this was trying to exploit CVE-2016-6334 in order to load the other domain. This issue was discovered by me and User:Legoktm back in 2016. Even if the domain existed, it would not have worked on Wikimedia wikis after June 2016. It is interesting that it was used in the wild, so long after it was fixed. My primary guess here is that this script was originally intended for use in some sort of attacks against Cyclowiki in the distant past and perhaps that wiki was using an outdated version of MediaWiki at the time (Its currently is on 1.39.1 [Dec 2022], which is new enough by a wide margin to not to have this vulnerability but is old enough to have other publicly known vulnerabilities, so it seems like they aren't conscientious about applying security updates). If we want to cast our minds back to 2016, I guess its kind of noteworthy that this report was published in 2015 and sort of discusses the possibility of something like this. If an attacker was doing background research they could have seen it and been inspired by it. However the attack vector is also so obvious that that is probably just a coincidence. Bawolff (talk) 07:19, 10 March 2026 (UTC)[reply]
    My primary guess here is that this script was originally intended for use in some sort of attacks against Cyclowiki in the distant past and perhaps that wiki was using an outdated version of MediaWiki at the time
    Exactly what it was. Ololoshka is definitely not the script's author — the script is exactly the same as the one used on Cyclowiki in 2023 (Ololoshka just copied it on ruwiki and modified to not execute for him). And yeah, as far as I remember, at least in the attack on Wikireality (at the same time as on Cyclowiki) a vulnerability was used and that wiki utilized an old MW version. Well very well (talk) 08:44, 11 March 2026 (UTC)[reply]
  • Really enjoyed this write-up. I look forward to asking questions and learning more about the WMF's plan to expand their engineering team to both prevent this incident from repeating and to improve the technical design and operation of the wikis. — ♠ Ixtal ( T / C ) Non nobis solum 07:48, 10 March 2026 (UTC)[reply]
  • @JPxG: The person who did this was "testing userjs loads" (i.e. loading as many random scripts as possible), per this edit history. This article goes out of its way to avoid naming and shaming anyone though, as it should, so I'm not sure how to put this bit of information in without violating that principle. Graham87 (talk) 09:00, 10 March 2026 (UTC)[reply]
  • Excellent write-up, appreciate the details and explanations! --Elmidae (talk · contribs) 13:06, 10 March 2026 (UTC)[reply]
  • WMF seems to be a bit behind on security controls. there's needs to be change control and testing environments for sure. I don't think they need a full replica of enwiki, but enough to test scripts like this. and they need to have change control to ensure a review of planned actions on the production environment. and IMO, Stewards, Iadmins, probably oversighters and CUs as well, perhaps even crats and sysops, should have the permissions on separate accounts that are locked into safe mode, or perhaps only allowed approved versions of approved scripts like twinkle. that would help reduce the chances of session hijacking on privileged accounts. it's an industry standard under ISO 27001, and while I think having Wikpedia fully compliant with that would be impractical given the overall mission, it does contain good practices for cybersecurity. the internet is an ever more dangerous place these days. -- Aunva6talk - contribs 15:03, 10 March 2026 (UTC)[reply]
    I think the need for a better replica environment to do testing on is a bit of a red herinng. I think testing on meta stems from a mis-assesment of risk. If risk was appropriately assessed i suspect the test would have been conducting in a safer way. I agree with you on principle of least privledge stuff. Bawolff (talk) 18:15, 10 March 2026 (UTC)[reply]
  • What's incredible is they figured this out and resolved it in just 2 hours. Chattenoir (talk) 15:37, 10 March 2026 (UTC)[reply]
    I'd be surprised if it had taken longer to figure it out given the person who triggered the incident was a security engineer doing a test. Nardog (talk) 08:38, 16 March 2026 (UTC)[reply]
  • Nobody seems to mention this, but imagine if the script were actually written in a harmful and skilled way and someone had planned for this. You can easily go from Meta to Wikipedia with global.js. Having 20 minutes with thousands of computers all over the world on all Wikipedias and other projects might have been bad. Also, not all private data is only in the DB. There are deleted edits you could access, some deleted because of privacy issues. There is mw.config.values, some of which is somewhat confidential or private. Some user preferences you might download and send to a remote server. And of course there are page visits, which you might use for profiling specific users (you could assign them to a specific user with wgUserName and send to remote server). You might need big server(s) to process all the data you would get, but that is not impossible to have. --Nux (talk) 15:48, 10 March 2026 (UTC)[reply]
  • My evaluation of the code agrees with what people have written above. I think that Woodpecker10.jpg was a screenshot of the source code on the ru: WP. While there are interesting factors in the event, there's little that hasn't been in our communal threat model for ever. It does, however, focus the mind on the realities, particularly what didn't happen, but could have, in regard to advanced user permissions. All the best: Rich Farmbrough 17:37, 10 March 2026 (UTC).[reply]
    To expand on the encoded JavaScript, it is stored in strings, and needed some kind of encoding as the code contained both line breaks and quotation marks. There might have been more elegant ways to do this, but this was quick and functional. I believe there was also some recursive encoding, Thanks to Bawolff above for explaining why 'obviously non-functional' code was included, and to everyone who has been part of the Foundation and community response. All the best: Rich Farmbrough 17:52, 10 March 2026 (UTC).[reply]
    Yeah, it looks like there was 2 levels of percent encoding. The first was to encode the POST body so that it would be sent to the server correctly. The inner lay seems related to the attempt to exploit CVE-2016-6334, as that was a bug in how mediawiki handled percent encoded links, so it needed to use percent encoding to try to trigger that. Bawolff (talk) 21:42, 10 March 2026 (UTC)[reply]
    I was one of the victims of the original attack at Cyclowiki. My contribition log there (cyclowiki.org/wiki/Служебная:Вклад/Ssr) contains the same vandal-edits (not made by me) dating back to 7 april 2023. The image used there was named "Dzieciol_bialogrzbiety_samiec.jpg" and was inserted in the same way as "Woodpecker10.jpg" with 5000px width. It contained image of a woodpecker. Woodpecker, «дятел» (wikireality.ru/wiki/Дятел_(викисреда)), is a commonly used symbol of persistent wiki vandalism. -- ssr (talk) 15:37, 14 March 2026 (UTC)[reply]
  • There are only fifteen of these; in addition to being administrators, they are all serious-business technical editors like Izno and Oshwah who can be trusted around high voltage. and Only interface administrators can edit the sitewide common.js, so this allows it to work on people who aren't intadmins. Well, this is a bit too short. — I just hold admin rights on English Wikipedia, but as a Steward (as well as a few other global groups like Global interface editors New wikis importers, Global sysops in their wiki set [no enwiki], the Staff group and System administrators) I hold the editsitejs permission in all wikis (see Special:GlobalGroupPermissions) and could have edited the local MediaWiki:Common.js involuntarily (as it happened on my homewiki metawiki when I tried to help with the situation before the effects of the script where known).
    It's not immediately clear what test was being done here WMF is currently conducting security tests on user scripts and gadgets. For example, they discovered another questionable script just Monday last week, which was subsequently deleted by enwiki administrators. That incident was just another test within this framework. Thankfully, it was not tested on enwiki, but metawiki, and didn't spread from there to other places. Deletion-restore vandalism on content wikis does way more harm than on metawiki. Best, —DerHexer (Talk) 11:56, 12 March 2026 (UTC)[reply]
  • Relevant: https://xkcd.com/286/ Antony–22 (talkcontribs) 21:44, 12 March 2026 (UTC)[reply]
  • Huh, I was wondering what happened. Thanks so much for the explanation! jiraijohnny˚₊‧꒰ა ♡ ໒꒱ ‧₊˚ (KISS ME GOOD-BYE.⋆˚꩜。) 14:00, 13 March 2026 (UTC)[reply]

















Wikipedia:Wikipedia Signpost/2026-03-10/Special_report