Page MenuHomePhabricator

DOM Clobbering Risk in WikiBooks
Open, LowPublicSecurity

Description

Dear WikiMedia Security Team,

We are researchers from CISPA, and as a part of one of our projects, we found that the wiki pages in wikibooks.org could be affected by DOM Clobbering. Our current understanding is that the posed risk is small. However, we would like to support you to mitigate the issue.

DOM Clobbering

DOM Clobbering is a type of attack where attackers confuse a web application by injecting HTML elements whose named properties (e.g., id/name) collide with the name of JavaScript variables and overshadow their value. For example, a p tag with id=x can clobber the variable x when injected to the DOM tree (e.g., see here for more details).

Security Risk in WikiBooks

Description: We found that the text editor used in wikibooks.org which allows users to create wiki pages and posts does not sanitize the named properties, particularly id and data-* when creating posts for several HTML tags. The complete list of tags follows, but we start with one example.

Example URL: https://en.wikibooks.org/w/index.php?title=User:XYZ&action=submit

Example Payload: The payload test<sup id=QUnit> clobbers the variable window.QUnit, which is used in multiple locations in the code as a part of a conditional check if(window.QUnit){ [...] }. This can result in client-side DoS, or simply breakage of other client-side functionalities due to triggering JS parsing issues.

Steps to Reproduce:
1- Acting as the attacker, open the example URL above.
2- insert the example payload
3- Click the Show Preview button (An attacker would click publish here to persistent the payload to the DOM tree).
4- Now you are viewing the preview page; open the browser console and see that the markup triggered JS breakage (In an attack, the victim would be affected when visiting the published wiki)

Suggested Patch:

  • To mitigate the risk of DOM Clobbering, named attributes, particularly id and data-* attributes for the case of WikiBooks should be prefixed with a constant string to ensure namespace isolation. For example, <p id=x> should be changed to <p id=user-content-x>.
  • A similar patch has been deployed in other HTML sanitizers, see, e.g, DOMPurify.

Complete List of Unsanitized Tags: The following tags allow an attacker to clobber a variable x or window.x, and x.dataset.y or window.x.dataset.y if an attacker creates a wiki post using them.

  • <div id=x data-y=z>
  • <p id=x data-y=z>
  • <span id=x data-y=z>
  • <b id=x data-y=z>
  • <i id=x data-y=z>
  • <s id=x data-y=z>
  • <br id=x data-y=z>
  • <data id=x data-y=z>
  • <dd id=x data-y=z>
  • <del id=x data-y=z>
  • <dfn id=x data-y=z>
  • <dl id=x data-y=z>
  • <dt id=x data-y=z>
  • <em id=x data-y=z>
  • <font id=x data-y=z>
  • <h1 id=x data-y=z>
  • <hr id=x data-y=z>
  • <li id=x data-y=z>
  • <mark id=x data-y=z>
  • <ol id=x data-y=z>
  • <pre id=x data-y=z>
  • <q id=x data-y=z>
  • <rb id=x data-y=z>
  • <rp id=x data-y=z>
  • <kbd id=x data-y=z>
  • <bdi id=x data-y=z>
  • <bdo id=x data-y=z>
  • <big id=x data-y=z>
  • <blockquote id=x data-y=z>
  • <center id=x data-y=z>
  • <cite id=x data-y=z>
  • <code id=x data-y=z>
  • <rtc id=x data-y=z>
  • <ruby id=x data-y=z>
  • <s id=x data-y=z>
  • <samp id=x data-y=z>
  • <strike id=x data-y=z>
  • <sup id=x data-y=z>

Notes for Your Reference: We found several sensitive sinks/instructions that we initially assumed to be exploitable for XSS, but further manual checks showed that they are not, because the text editor correctly prevents multi-level DOM Clobbering through the name property (i.e., it deletes that attribute). However, for your reference, we listed them here:

Case 1:

Case 2:

Case 3:

  • script: link
  • code: $(OO.ui.getTeleportTarget()).append(OO.ui.$defaultOverlay);
  • Similarly to previous examples. Exploitation not currently possible.

Complete list of DOM Clobbering sources: We found that the way the code defines the following variables could introduce the risk of DOM Clobbering (e.g., x = window.x || {}) However, these should not be exploitable assuming proper sanitization by the text editor. However, we listed them here for future reference.

  • "window.QUnit",
  • "window.pg",
  • "window.NORLQ",
  • "window.RLCONF",
  • "window.RLSTATE",
  • "window.RLPAGEMODULES",
  • "window.RLQ",
  • "mw.uls",
  • "OO.Registry",
  • "OO.ui.PopupWidget",
  • "mw.Api",
  • "Geo.country",
  • "Geo.country_code",
  • "OO.ui.DropdownInputWidget",
  • "OO.ui.CheckboxInputWidget",
  • "OO.ui.FieldLayout",
  • "window.ve",
  • "window.ve.init.editingSessionId",
  • "OO.ui.WindowManager",
  • "OO.ui.ToolFactory",
  • "OO.ui.ToolGroupFactory",
  • "OO.ui.Toolbar",
  • "OO.EmitterList",
  • "window.WebKitMutationObserver",
  • "window.MozMutationObserver",
  • "mw.language.getFallbackLanguageChain",
  • "mw.msg",
  • "window.wpAvailableLanguages",
  • "wpAvailableLanguages.lang",
  • "OO.ui.ButtonWidget",
  • "OO.ui.mixin.PendingElement",
  • "OO.ui.Keys.ESCAPE",
  • "OO.ui.Keys.ENTER",
  • "OO.ui.LabelWidget",
  • "OO.ui.PanelLayout",
  • "OO.ui.windowManager",
  • "OO.ui.TextInputWidget",
  • "OO.ui.mixin.GroupElement",
  • "OO.ui.Widget",
  • "OO.ui.mixin.IconElement",
  • "OO.ui.mixin.FlaggedElement",
  • "OO.ui.mixin.TabIndexedElement",
  • "OO.Factory",
  • "OO.ui.mixin.PopupElement",
  • "OO.ui.mixin.IndicatorElement",
  • "OO.ui.mixin.LabelElement",
  • "OO.ui.mixin.TitledElement",
  • "OO.ui.mixin.ClippableElement",
  • "OO.ui.mixin.FloatableElement",
  • "OO.ui.IconWidget"

If you have any further questions, please do not hesitate to contact me (soheil.khodayari@cispa.de).

Best,
Soheil

Details

Risk Rating
Low
Author Affiliation
Other (Please specify in description)

Event Timeline

Thanks for creating this task, @Soheilkhodayari. I had a few follow-up questions:

Example URL: https://en.wikibooks.org/w/index.php?title=User:XYZ&action=submit

So this is using VisualEditor, the de facto text editor for many Wikimedia projects. But your vulnerabilities seem to specifically focus upon wikibooks.org sites (as opposed to also including Wikipedia, Wikiquote, et al). From various included spidering data within TheThing's repository (1, 2), it looks like you did attempt to scan other Wikimedia projects, which are very likely configured to use VisualEditor. Were no issues found within those additional Wikimedia sites?

To mitigate the risk of DOM Clobbering, named attributes, particularly id and data-* attributes for the case of WikiBooks should be prefixed with a constant string to ensure namespace isolation. For example, <p id=x> should be changed to <p id=user-content-x>

This could, perhaps, be a feature added somewhere within VE or the MediaWiki parser's Sanitizer class, but I'm not sure how much this would break existing wikitext across the projects and what type of validation and enforcement would be appropriate. We could also create an eslint or similar plugin to warn on poor naming conventions within developed code (html templates, php-rendered html, etc.), I suppose.

Complete List of Unsanitized Tags: The following tags allow an attacker to clobber a variable x or window.x, and x.dataset.y or window.x.dataset.y if an attacker creates a wiki post using them.

By "complete list", you mean within the context of Wikimedia sites running MediaWiki, correct? Not "everything".

We found several sensitive sinks/instructions that we initially assumed to be exploitable for XSS, but further manual checks showed that they are not, because the text editor correctly prevents multi-level DOM Clobbering through the name property (i.e., it deletes that attribute)

We found that the way the code defines the following variables could introduce the risk of DOM Clobbering (e.g., x = window.x || {}) However, these should not be exploitable assuming proper sanitization by the text editor.

So it sounds like, from your findings, that there is (likely) nothing actionable on our end at this time - i.e. there are no confirmed-exploitable vulnerabilities on wikibooks.org or other Wikimedia sites which you may have scanned and analyzed.

Thanks for checking the report. I am happy to answer any questions.

Were no issues found within those additional Wikimedia sites?

Yes, to clarify, we tested only a subset of the automatically analyzed sites manually to check for exploitations, covering different site categories (i.e., cases where attackers are able to insert a named markup to the DOM tree in the first place, to control a data flow to a sink). If other sites use the same text editor / VE, they could be affected by the same risk too, provided they use the same VE configuration (e.g., allowed attributes and tags).

I'm not sure how much this would break existing wikitext across the projects

That's a good point. It may worth investigating what are the use cases of user-definable id attributes in the VE for the affected HTML tags. Answering that question may help estimating the potential breakage for existing wiki text (if any).

By "complete list", you mean within the context of Wikimedia sites running MediaWiki, correct?

Yes, by "complete" I mean the markups that can lead to DOM Clobbering in this context only. We tested the complete list of HTML tags and attributes (i.e., clobbering markups) against the VE in wikibooks.

So it sounds like, from your findings, that there is (likely) nothing actionable on our end at this time - i.e. there are no confirmed-exploitable vulnerabilities

Indeed, there seems to be no necessary patches, except for the (potentially little) risk posed by the current VE configuration, which you may consider addressing.

I think disallowing custom id attributes is a not feasible. However a blacklist of known problematic ids sounds feasible. On the other hand that probably does little to prevent the risk from the gadget ecosystem which i suspect where much of the (albeit low) risk resides.

It'd be really nice to have some high-quality SAST/Sanitization run against Gadget code (and userJS for that matter) and at least emit warnings. Or send some kind of audit report somewhere. But that's obviously not a trivial project. And one that's been talked about at least a few times, including this still somewhat-recent incident: T296855.

sbassett changed the task status from Open to In Progress.Feb 12 2024, 5:19 PM
sbassett triaged this task as Low priority.
sbassett moved this task from Incoming to In Progress on the Security-Team board.

I'm thinking about making this task public for awareness and if anybody wanted to publicly work on any related tooling. And possibly add this to any theoretically-updated security best practices for MediaWiki developers. Any strong objections?

Sounds great, I think making the report public could be beneficial, particularly to increase awareness among developers!

To add to the comment by @Bawolff, I think the blacklisting approach of id attributes is similar to what the AMP4Email Sanitizer of Gmail does [1]. That could be indeed another viable solution, but it may be a bit brittle since the code could evolve and the list need to be updated once in a while.

[1] https://research.securitum.com/xss-in-amp4email-dom-clobbering/

Example URL: https://en.wikibooks.org/w/index.php?title=User:XYZ&action=submit

Example Payload: The payload test<sup id=QUnit> clobbers the variable window.QUnit, which is used in multiple locations in the code as a part of a conditional check if(window.QUnit){ [...] }. This can result in client-side DoS, or simply breakage of other client-side functionalities due to triggering JS parsing issues.

It should be noted that window.QUnit mostly controls whether some private variables/functions are exposed to global scope (in order that unit tests can play with them). Not ideal of course, but I don't think its likely that this represents a security issue.

sbassett reopened this task as Open.
sbassett claimed this task.
sbassett moved this task from In Progress to Our Part Is Done on the Security-Team board.
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 Low.

As a practical matter, it seems like it is rather difficult to exploit when you can't control the id/name of <a> tags, and you cannot do 2 level (x.y) dom clobbering [where you fully control y]

Change 1005165 had a related patch set uploaded (by Brian Wolff; author: Brian Wolff):

[mediawiki/core@master] Add a paranoia defense against dom clobbering of window.QUnit

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

Change #1005165 merged by jenkins-bot:

[mediawiki/core@master] ResourceLoader: Create window.QUnit as undefined in production

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

Any objections to making this public at this point? There are perhaps some additional code-hardening measures that could be employed for some remaining, low-risk issues, but that's all I'm really seeing at this point?