Severity : High
Description : Since there is no valid way of determining where the request to spectrum is originating from, an attacker can setup a malicious website and when the victim visits that page, the attacker can make any number of authenticated requests to spectrum as the victim.
Proof of Concept : Bug Demo Video
Reproduction Steps :
https://devangeles.com/csrf-exploit.html and wait for 2 seconds.Explanation :
Impact : An attacker can make any request to an endpoint in the context of a victim's session like delete the any account without authorization.
Mitigation : Find a good way to identify and validate the origin request, probably using randomized tokens. More on Mitigations
Extras
https://devangeles.com/JSONCT/. Open the exploit.html and allow flash to work. This exploit does not delete the user's account, I thought that would be really dangerous to try out, so instead, this proof of concept is for changing the name and website of you account settings. See references down below to know more about JSON CSRF.References
Have a great day!
s0cket7
I tried but was unable to reproduce using the steps provided. Chrome reports the xhr is blocked (as intended):
Access to XMLHttpRequest at 'https://spectrum.chat/api' from origin 'https://devangeles.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Yes, it blocks, unless you have a domain like attacker-spectrum.chat (because there's also a CORS misconfiguration bug - I've reported it to @brianlovin over the email), but in CSRF the response doesn't really matter, only the request has to be processed in the backend. So even if you get the error, it would still work because the request will be processed in the backend regardless of the CORS.
I just tested the exploit in Chrome, it works. Yes I did get the same error but it still worked anyway because in CSRF attacks the reponse really doesn't matter, Same Origin Policy will act.

https://devangeles.com/csrf-exploit.htmlThank you for the in-depth report, I'm taking a look at mitigating this!
My pleasure.
Also, could you open another issue for the CORS misconfiguration issue? I'd like to tackle that too.
Sure.
Another question just to make sure I understand everything: how does https://devangeles.com/csrf-exploit.html get the value of the cookie to send to the server?
Whenever the browser initiates the request to spectrum.chat it automatically sends the cookie, even if that request originated from a different origin like https://devangeles.com, so that's the reason the origin check is critical or else these kinds of attacks are possible.
Whenever the browser initiates the request to spectrum.chat it automatically sends the cookie, even if that request originated from a different origin like https://devangeles.com
I see, thanks for the elaboration!
As far as I can tell, setting the SameSite cookie attribute (#3697) and then checking the Origin and Referrer headers should be enough to combat this issue?
Origin and Referrer check works everywhere, except in IE11So in summary, only a tiny subset of users who are on very old versions of IE11 would still be affected, but that should be it, if I understand that correctly?
Although checking for Origin and Referer header is kind of a solution to this problem, it's not really the right way because those headers are not always reliable (like in IE). So you have to choose a good and reliable way to ensure that it is protected from CSRF attacks. One way is by using randomized tokens, so basically on the server-side, you can generate a unpredictable random token and send it to the client as a part of html form hidden element or something like that and then every time there's a request from the client, you check for this token, if they match, you know that this request was from the know origin. With this kind of approach you can even protect those small subset of IE users.
You can check out more defenses to CSRF here
@mxstbr this article on universal react CSRF protection might be useful as a reference.
Unfortunately, we can't easily use the server-side token approach because our apps serve a client-side-only app shell via ServiceWorker caching鈥攚hich means after the first request, no request will hit the server apart from API fetches. (on top of that it would mean that any user who's currently logged in would be logged out since they don't have a CSRF token, but that's only a minor nuisance)
As far as I can tell, this only won't work in old versions of IE11 and before. According to GA ~0.5% of our users are on those versions of IE. That means the Origin and Referer check + samesite cookie get us a solid 99% of the way there, so let's go for that for now and then investigate how to do handle tokens properly with our caching setup in the future?
Sounds good.