Page MenuHomePhabricator

Improve safe mode feature for better security
Open, In Progress, MediumPublic

Description

Background

Currently all logged in users run gadgets and user scripts by default. There is an existing safe mode feature that disables all wiki-based scripts but this can easily be toggled off via JavaScript (without 2FA step) and does not completely protect the user. I've been using that on my staff account given I don't need site scripts in this account. Often site wide styles are essential for viewing the page, so disabling everything can have other negative consequences for this to be useful and I find myself disabling safe mode to troubleshoot issues with articles that require MediaWiki:Common.css. This would also incentivize good practices such as not adding user scripts to gadgets. Based on conversations with @Catrope and @EMill-WMF I have created this ticket.

User story

As a user with privileged wiki rights, safe mode and 2FA enabled I want better protections from on-wiki scripts.

Requirements

  • Changing the Safe mode preference should require 2FA when enabled.
  • Safe mode should be more flexible and support disabling by type (user script, site script, site style, site script)
  • If I have safe mode enabled, calling functions such as importScript('User:Jdlrobson/rlExtra.js') should not work

Benefits

  • Improved privacy - We can disable data collection for users who have explicitly enabled user scripts (which might lead to them being more identifiable in anonymized data) e.g. webclienterror
  • Improved performance for readers - readers not using watchlist do not need many of the watchlist gadgets that are enabled by default
  • Improved security - power users can limit vectors of attack on their account either temporarily or permenantly .

BDD

  • For QA engineer to fill out

Test Steps

  • For QA engineer to fill out

Design

Screenshot 2026-05-21 at 4.12.19 PM.png (1,612×714 px, 120 KB)

Acceptance criteria

  • Add acceptance criteria

Communication criteria - does this need an announcement or discussion?

  • Add communication criteria

Rollback plan

  • What is the rollback plan in production for this task if something goes wrong?

This task was created by Version 1.2.0 of the Web team task template using phabulous

Event Timeline

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

Change #1290963 had a related patch set uploaded (by Jdlrobson; author: Jdlrobson):

[mediawiki/core@master] POC: Exploration of replacing safe mode binary with bit string

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

Changing the Safe mode preference should require 2FA when enabled.

@Catrope Would this better said as, "If a user has 2FA enabled, then disabling the Safe Mode checkbox should be considered a privilege-elevation-worthy check"? A couple things in that are 1) not sure why we'd need to check anything for enabling Safe Mode, and 2) we aren't prepared (yet) to do any kind of reauth-like step for non-2FA-enabled users, I think.

Safe mode should be more flexible and support disabling by type (user script, site script, site style, site script)

This would really only be relevant to developers/tech-savvy users, so I assume we could safely put that behind some "Advanced" language? I wouldn't want to intimidate non-tech-savvy users away from Safe Mode, especially since Safe Mode is really more of a reasonable default for them.

@Jdlrobson-WMF Does the screenshot in the ticket represent a specific set of proposed defaults? Or should we have a separate ticket/discussion for appropriate defaults?

@Jdlrobson-WMF Does the screenshot in the ticket represent a specific set of proposed defaults? Or should we have a separate ticket/discussion for appropriate defaults?

Separate ticket. For now the defaults would be current default (all enabled by default). I'd like to separate this out. Once the preferences exist it is very easy to configurable different defaults for different groups.

This would really only be relevant to developers/tech-savvy users, so I assume we could safely put that behind some "Advanced" language? I wouldn't want to intimidate non-tech-savvy users away from Safe Mode, especially since Safe Mode is really more of a reasonable default for them.

Totally. Another suggestion from @DLynch (hopefully not misrepresenting is something like this) would be to split safe mode into several preferences:

  • One for enabling/disabling all gadgets:

Screenshot 2026-05-22 at 1.53.47 PM.png (1,376×1,570 px, 414 KB)

  • For site JS/CSS and user JS/CSS

Screenshot 2026-05-22 at 1.55.43 PM.png (1,398×1,326 px, 288 KB)

Changing the Safe mode preference should require 2FA when enabled.

@Catrope Would this better said as, "If a user has 2FA enabled, then disabling the Safe Mode checkbox should be considered a privilege-elevation-worthy check"? A couple things in that are 1) not sure why we'd need to check anything for enabling Safe Mode

I think you're right that we would need privilege elevation only for enabling scary things, not for disabling them. So enabling safe mode shouldn't need it, but disabling safe mode should.

and 2) we aren't prepared (yet) to do any kind of reauth-like step for non-2FA-enabled users, I think.

We have long had a reauth step for non-2FA users when they perform certain actions (including setting up 2FA :) ), and really it just asks them for their password again. In the context of the new designs for reauth, we (engineers among ourselves) discussed that option too, and we agreed that we should provide a way for non-2FA users to do a reauth in the new system too, by re-entering their password.

One more thing to note about the level of configurability here – there are also CSS-only gadgets, which don't have the same security implications as JS+CSS ones. An example of such gadget is "Subtle update marker" on enwiki.

As an interface admin, I like the CSS-only gadgets because they are more maintainable than putting everyting into MW:Common.css. For example, on plwiki we use this approach to style infoboxes, horizontal lists, flex-like content (multiple blocks side by side without tables), dark mode tweaks are applied this way, etc. From int-admin perspective, I'd like to be able to eventually have empty MW:Common.(js|css) files, so that everything possible is nicely extracted and split into gadgets or template styles (although the latter has some drawbacks, so won't fully replace global CSS).

Safe-mode for gadgets having worse granularity than safe-mode for sitewide code can be a non-negligible factor preventing from migrating towards a more mainainable approach around global CSS.

The gadget type is already available through Gadget::getType(), which returns either 'styles' or 'general' and corresponds to different loading method by ResourceLoader.

And one more thing (partially related to above), looking at the initial design, I'm wondering – is there any difference between site scripts and gadgets, so as to make it separate options?

Both site scripts and gadgets are editable by exactly the same people, which IMO makes no security difference between those two. The configurability (turn off/on) aspect of gadgets plays IMO no role here, as there are also default hidden gadgets, which will behave effectively the same as MW:Common.(js|css).

On the other hand, I do believe that average user knows nothing about the different methods of saving client-side code into MediaWiki (gadgets, site scripts, user scripts), so upon reading the prefs options they could have a false impression that one of these categories is something else than it really is. For example, if we advertise gadgets as "community-provided", then the "site-scripts" or "Wikipedia scripts" (as they can be understood) may be seen as something provided not by community, but e.g., by WMF. Or maybe some other body?

Making gadgets honor the settings for site-wide code will also help towards my previous comment. Then, general gadgets can obey the site-wide JS setting, and styles gadgets – the site-wide CSS setting, as these are effectively the same scope.

sbassett changed the task status from Open to In Progress.Tue, May 26, 4:46 PM
sbassett triaged this task as Medium priority.
sbassett moved this task from Incoming to Watching on the Security-Team board.
sbassett added a project: SecTeam-Processed.

I agree with @mszwarc's comments: I think it makes more sense to group all sitewide scripts together (Common.js + gadgets) and all sitewide styles together.

I agree with @mszwarc's comments: I think it makes more sense to group all sitewide scripts together (Common.js + gadgets) and all sitewide styles together.

I agree it should be possible to disable JS gadgets but not CSS gadgets. Instead of grouping together it might be a good idea to separating these out as well for consistency (either as part of this phase or a later phase).
e.g.

  • Gadget CSS
  • Gadget JS
  • Site CSS
  • Site JS

Improved privacy - We can disable data collection for users who have explicitly enabled user scripts (which might lead to them being more identifiable in anonymized data)

I'd push back on this one. @mpopov and I talked about this on Slack a bit. There may be ways to further anonymize these log events, but I would not be in favor of disabling them entirely as 1) logstash access should be gated and we put a bunch of other user data in there that is likely far more sensitive (and there are many other ways of tracking user activity) and 2) it is critical to have access to this and similar data in logstash during security incidents etc.

I agree with @mszwarc's comments: I think it makes more sense to group all sitewide scripts together (Common.js + gadgets) and all sitewide styles together.

I agree it should be possible to disable JS gadgets but not CSS gadgets. Instead of grouping together it might be a good idea to separating these out as well for consistency (either as part of this phase or a later phase).
e.g.

  • Gadget CSS
  • Gadget JS
  • Site CSS
  • Site JS

What I was suggesting was:

  • Sitewide CSS
  • Sitewide JS
  • User CSS
  • User JS

Where "sitewide" includes both Gadgets and MediaWiki:Common.js etc.

Change #1290963 abandoned by Jdlrobson:

[mediawiki/core@master] POC: Exploration of replacing safe mode binary with bit string

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