The Browser Extension/Userscript Policy has already been officially been extended to other forms of code snippets that may be used for self-XSS, and as was expressed by me and others, this restricts the ability to create and share useful tools designed for Scratch.
Paddle2See reached out to me regarding the possibility of a system to prevent self-XSS without restrictions to sharing of code snippets, following me reporting a forum post to potentially re-open the topic that this extension of the Policy was discussed on, and I began working on a project which can be found here.
This self-XSS protection system has been tested and does work, although some user interface components do need to be updated before it is implemented into Scratch, so that newer Scratchers are not confused by what the URLs mean. I do plan to eventually officially add this to my system, but it would also work for you all to implement such a feature while implementing this system, especially since it already will be likely needed for updates in the backend of Scratch to be made to allow URL allowlisting according to authorization and URL paths. My system does include a pre-made system for path-based allowlisting, but if this were used in its pure form, for example, the moderation APIs would be disclosed to the Scratch community or otherwise moderators would be forced to manually allow every request sent by the moderation tools. This would also likely require full-stack testing as well, in order to ensure that all necessary URLs are allowlisted, and no more than what are necessary for the sake of security as well.
I understand this is a large feature addition, but it would certainly make Scratch safer while not sacrificing opportunities for the sharing of information, learning of new technologies, and development of new tools.
As someone who spends a lot of time working with Scratch API endpoints, if I understand the proposal correctly, I don't think this is a great idea. It would be incredibly inconvinent for testing and playing with the API, and I personally don't think the pros outway the cons.
I believe that the current solution of outright banning sharing functional code is a much better solution than partially banning functional code and attempting to block JavaScript from requesting dangerous URLs.
Teaching people to not run any random piece of code is (in my eyes) much more important than allowing people to share some code and hoping some defenses put up are safe enough.
It also is probably much easier for moderators to ban any code they see than to train them to find malicious code and censor it. Even with your protections, it's still possible for someone to say "hey, check out my new script. it can change your username!!! paste this code in the console while on the account settings page and type your password and the new username you want into the box that pops up." and the script just submits the password change form or something. It's not really feasible to attempt to patch all of the different ways a self-xss can hurt you, and I don't think a half-solution that limits the usefulness of the console is a good idea.
Overall while it's cool, I don't think this should be implemented on Scratch.
@jeffalo This suggestion essentially means implementing a system to block potentially malicious requests, to an endpoint inside or outside of the Scratch website. When it intercepts a request, however, it gives you the option to allow it or block it. It will display a popup box that currently just says the URL requested, but with modifications could say what the specific request could do, and then you can choose to allow it or not.
Testing and playing around with the API, all you'd need to do would be to allow the requests. Another thing I think would be beneficial for this is allowing previously allowed requests, but I still have yet to implement this.
Also, I would like to note that what this system does is essentially redefine XMLHTTPRequest and fetch, storing the original version only in a closure, so nobody can bypass the checking system in the middle without somehow either recreating these features with lower-level code (which you can't do in browser JS) or somehow finding a buffer overflow exploit, which relies on the actual browser engine and could not be shipped with a functional code snippet or a bookmarklet.
And yes, with the going to the account settings page and changing the password, that is a valid concern, given that this context would allow that endpoint. However, I think it would be pretty obvious to users to not run code on a page that controls everything with your account, and anyways, the changes would be immediately apparent too, especially with the email you get when you change the password.
And back to the security concerns of this system, I would like to mention that prototype pollution, the most realistic concern given how the system works, would also fail since the functions are defined in function scope and are defined before any potential payload could be deployed, and since prototype pollution relies on modifying future instantiations, the code is protected from this kind of attack.
I designed this system at the request of Paddle2See, as a better alternative to the current banning of functional code snippets and to more restrictive actions such as CSP headers.
I see, but I still stand by my original stance.
Adding a prompt for non-allowed requests is nice, but it's still fairly simple for someone to tell another person to ignore it. It makes all of the other work you put in to this a waste.
You can't trust that people will be smart enough to know what's a scam and not. Scratch is about learning, and you'll have lots of younger kids who don't know any better.
I used to love sharing code on Scratch, browser extensions and bookmarklets and userscripts were the coolest things. But it was really dangerous and I didn't understand back then. Even with the tightest technical securities, there are always bypasses or ways around it. I don't think it makes sense for the scratch team to maintain something like this, when just keeping the current system of banning functional code and making people aware of the dangers works far better and teaches people a little about personal cybersecurity.
@jeffalo If someone sees a request to a URL that says "delete-account" or something in it, I think it would be pretty obvious that it is dangerous... Also, future updates would tell you what each endpoint could do, so Scratchers would be aware of the potential dangers.
And I think making Scratchers aware of the specific dangers with different requests teaches more cybersecurity than not allowing Scratchers to even interact with any sort of functional code...
And yes, there are bypasses to everything, but any bypass of this system would either involve things that can't be shipped with a simple script (could be with a browser extension though, which is why browser extensions and userscripts would still be banned) or would be easily noticeable (for example, trying to use a form instead of an actual request (although I don't even think that would work. I do have to test that though... I can try to add it to the system if needed) would redirect you to a page that would pretty much say what the request did, and if that were to happen, you'd already kind of know something happened that you didn't want).
@jeffalo I actually just tested the form thing, and it fails with headers for authenticated requests. (tried making a comment on my profile bypassing the system and it didn't work)
FYI Deleting account requires password; if you have the password, you can simply send via methods that cannot be blocked, like by imging to external servers.
Current security model of Scratch is that any XSS is not persistent and leaving the page is enough to prevent extra damages. This is true since October 2020, when ST fixed a bug that allowed emails to be changed without passwords.
Scratch currently logs a big "Stop!" warning and I think that is enough. Or, they should implement better solutions like CSP.
FYI Deleting account requires password; if you have the password, you can simply send via methods that cannot be blocked, like by imging to external servers.
Current security model of Scratch is that any XSS is not persistent and leaving the page is enough to prevent extra damages. This is true since October 2020, when ST fixed a bug that allowed emails to be changed without passwords.
Scratch currently logs a big "Stop!" warning and I think that is enough. Or, they should implement better solutions like CSP.
That is true, but big changes can be made before you leave the page. For example, someone could share all your unshared projects or delete all of the content of one you have, or even potentially modify account information (although many such actions require a password).
Also, technically, for some actions, such as reading messages, the x-token is used, and this can be currently sent to external servers after being retrieved with a request to /session. If the request to /session was blocked in the first place, though, it would be impossible to get this.
Also, I would like to mention that the big "Stop!" warning is very clear to see, but how about self-XSS that is not through the console, such as those through bookmarklets? Also, even with that warning, if someone reassures them that it's safe, and then the Scratcher puts the code in and sees a popup saying that there is a request that could be used to get their email address or allow someone to perform actions as you, that would help prevent a potential self-XSS attack through x-token sharing. And it is much more difficult to persuade someone that a more specific warning is fine, than a general one like that message in the console.
The problem is that any good coder could work around this, it just encourages people to get better. I just bypassed this REALLY easily 馃槢. (ie. 1 line bypass)
The problem is that any good coder could work around this, it just encourages people to get better. I just bypassed this REALLY easily 馃槢. (ie. 1 line bypass)
Yeah, I just realized one way it can be bypassed. I'm about to fix it now! (did you redefine window.confirm?)
@GrahamSH-LLK I just fixed vulnerabilities with modifying window.confirm and prototype pollution (you could modify Array.concat to add an arbitrary URL to the allowed list). I think essentially everything is encapsulated or protected now, so I think it's good!
Just add CSP; no need for such a mess.
Just add CSP; no need for such a mess.
CSP limits all API interaction from the console, and prevents any bookmarklets, even ones you create, from being run...
That defeats the entire purpose of this suggestion, since this suggestion was meant to provide security while still allowing bookmarklets and console JavaScript snippets to be shared.
Most helpful comment
As someone who spends a lot of time working with Scratch API endpoints, if I understand the proposal correctly, I don't think this is a great idea. It would be incredibly inconvinent for testing and playing with the API, and I personally don't think the pros outway the cons.
I believe that the current solution of outright banning sharing functional code is a much better solution than partially banning functional code and attempting to block JavaScript from requesting dangerous URLs.
Teaching people to not run any random piece of code is (in my eyes) much more important than allowing people to share some code and hoping some defenses put up are safe enough.
It also is probably much easier for moderators to ban any code they see than to train them to find malicious code and censor it. Even with your protections, it's still possible for someone to say "hey, check out my new script. it can change your username!!! paste this code in the console while on the account settings page and type your password and the new username you want into the box that pops up." and the script just submits the password change form or something. It's not really feasible to attempt to patch all of the different ways a self-xss can hurt you, and I don't think a half-solution that limits the usefulness of the console is a good idea.
Overall while it's cool, I don't think this should be implemented on Scratch.