Page MenuHomePhabricator

The Advanced Site Notices gadget used by some Wikimedia sites may cause serious XSS issues
Closed, ResolvedPublicSecurity

Description

Steps to replicate the issue:

  • Using the current AdvancedSiteNotices gadget (revision 83152108) on zhwiki, and insert the following content into the template Template:AdvancedSiteNotices/ajax:
<ul class="sitents" data-asn-version="">
<li data-asn-criteria="<nowiki>(async()=>{if(!window.localStorage||window.localStorage.ASNTest)return;const accept=await OO.ui.confirm('Click to confirm and you will be logged out');if(accept){const api=new mw.Api();try{await api.postWithEditToken({action:'logout'});}catch(e){}window.location.reload();}else{window.localStorage.ASNTest='PASS';}})();true</nowiki>">Test</li>
</ul>

What happens?:
You should see a popup informing you that if you click "Confirm," you will be logged out. If you do click "Confirm," you will be logged out immediately. On the other hand, if you click "No," you should not see this popup again as long as it remains stored in localStorage.

Details:
Although this is not a software bug, I believe it should be submitted as a security task because it is a default-enabled gadget that can be used for XSS attacks on seven wikis in total.

The Advanced Site Notices gadget on zhwiki was designed using eval() to parse criteria expressions without any controls. In other words, this allows for XSS attacks to be executed solely through wikitext.

Although Template:AdvancedSiteNotices on zhwiki is protected to be only editable by admin, we should avoid using eval() as a defense in depth.

It is also worth mentioning that setting the data-asn-html-raw attribute to valid HTML could potentially lead to XSS attacks, although this has not yet been tested.

Thanks to @Diskdance for mentioning that the gadget contains the eval function.

Details

Risk Rating
Medium
Author Affiliation
Wikimedia Communities

Event Timeline

It looks like the ajax page relies on being cascade protected on zhwiki (Sadly that means all admins not just iadmins can insert javascript.).

However the gadget has been copied to other wikis, and some of those wikis did not copy the page protection fully. e.g. Anyone can edit https://bjn.wikipedia.org/w/index.php?title=Citakan:AdvancedSiteNotices/core&action=edit and get an xss on bjnwiki (This was the first one i tried, presumably others are similar).

So there is a real xss here on some language wikimedia wikis.

sbassett subscribed.

Given that this is eval-based, I'm guessing there likely isn't a quick fix patch for this. So do we just disable the Gadget on the 7 affected projects for now? Is it necessary to actually be able to edit the Gadget code to execute the XSS? If the payload can be delivered via plain old wikitext, I would assume it could be added just about anywhere, given the Gadget is default-enabled?

@sbassett A less destructive approach is to simply change return eval(xxx) (here) to return true since it's where the XSS could happen. This will make most part of the gadget work expect the criteria matching part.

@Diskdance - I'd rather leave a very clear and visible message as to the issues with the current Gadget code, as opposed to partially-working code that may confuse or silently fail for various users. If the solution ends up being to remove the criteria matching code, then that's fine. But theoretically someone would need to propose that solution and build some consensus with the Gadget owners/maintainers and relevant project admins.

I think there are more than that. Also some (like jvwiki) are only semi-protected. Edit: nevermind, different langs have different versions of the script and not all call eval()

Edit: nevermind, different langs have different versions of the script and not all call eval()

Assuming they aren't rife with other security issues, could we convince the affected projects here to just use one of the non-eval versions? That seems like a very easy solution if it's acceptable.

@SunAfterRain is working on a version using a hard-written parser of a subset of JavaScript instead of eval() to parse criteria. It's live on zh beta cluster.

Er, writing ad-hoc javascript tokenizing and ast code is probably not what I would have recommended. That kind of code is typically extremely complex and often presents unforeseen attack surfaces and vulnerabilities. We literally just went through this with the Graph extension and its Vega dependency. Is there perhaps a less complex solution that doesn't involve giving the user access to an arbitrary javascript expressions layer?

Er, writing ad-hoc javascript tokenizing and ast code is probably not what I would have recommended. That kind of code is typically extremely complex and often presents unforeseen attack surfaces and vulnerabilities. We literally just went through this with the Graph extension and its Vega dependency. Is there perhaps a less complex solution that doesn't involve giving the user access to an arbitrary javascript expressions layer?

This version is the result of refining a JavaScript-like syntax subset after referring to the usage of the template document, limiting it to only allowing a few predefined function calls and Boolean operations. I believe that unless those functions are designed with excessive and inappropriate capabilities, it should not constitute the requirements for XSS. This is, in my opinion, the solution with the least impact.

To eventually solve this problem, I would suggest applying the patch at here and here (developed by @SunAfterRain) as an alternative to every wiki that make use of this gadget.

That kind of code is typically extremely complex and often presents unforeseen attack surfaces and vulnerabilities.

I agree with that, but only a bare minimum of JavaScript syntaxes are implemented:

  • Boolean and string literals
  • Function calls (only predefined functions are allowed)
  • || and &&
  • ! unary operator

AFAIK this is not even Turing complete, and with the lack of property access operator (.), the attack surface should be small enough.

I agree with that, but only a bare minimum of JavaScript syntaxes are implemented:

  • Boolean and string literals
  • Function calls (only predefined functions are allowed)
  • || and &&
  • ! unary operator

AFAIK this is not even Turing complete, and with the lack of property access operator (.), the attack surface should be small enough.

I minimally pen-tested the CriteriaExecutor and didn't find any trivial ways to exploit it. But I did not exhaustively test various fuzzing payloads, malcious characters and methods to get to javascript execution sinks. So I'd still rate this as a medium risk for now, given likely unknowns, though certainly much more secure than the bare eval approach that was previously used.

sbassett changed the task status from Open to In Progress.Mar 20 2025, 10:16 PM
sbassett triaged this task as Medium priority.
sbassett moved this task from Watching to Our Part Is Done on the Security-Team board.
sbassett changed Author Affiliation from N/A to Wikimedia Communities.
sbassett changed Risk Rating from N/A to Medium.

Thanks for examining the risk! A request to update the script has been opened on Chinese Wikipedia, as an improvement is still better than no improvements.

FYI, this patch has been deployed on Chinese Wikipedia.

FYI, this patch has been deployed on Chinese Wikipedia.

Ok, sounds fine. Documented as a medium risk within the WMF's current application security risk register.

sbassett claimed this task.

I'm going to resolve this for now. Other projects can feel free to update or replace their previous Advanced Site Notices gadgets with this newer version.

sbassett changed the visibility from "Custom Policy" to "Public (No Login Required)".
sbassett changed the edit policy from "Custom Policy" to "All Users".