On March 3rd 2024, MangaDex was made aware privately of a security vulnerability affecting our website. A few hours later, we deployed an update to patch the issue.
As far as we are aware, the issue had never been exploited.
And while it is now patched, this is a good excuse to look, in details, at the cause, the disclosure and patch process, and at future security improvements we will implement to make it impossible for such vulnerabilities to exist on our site in the long run.
In short summary
The vulnerability would have allowed an attacker to craft a link to our website containing a malicious snippet of code, and upon a victim clicking on that link, the victim's browser would execute that code within the context of our website.
And this falls in the category of Reflected XSS vulnerabilities, hence the title.
Before we go further, we would like to thank to Samyak Jain from NexusCrypt.com for their detailed private report and disclosure.
What is an XSS vulnerability?
A cross-site scripting vulnerability – XSS for short – is a flaw in a website which allows an attacker to trigger the execution of code of their choosing on another user's browser as if it was part of that website.
There are two main classes of those:
- Reflected: The malicious code is inputted by the victim themselves (hence "reflected", even if unknowingly/involuntarily), for example through a maliciously crafted link. As a result, it affects only the direct victim's browser.
- Stored: The malicious code is inputted by the attacker on the website, gets "stored", and subsequently served and executed by other users of website as well, for example by having the payload as a piece of text in a comment, a title synopsis, etc. As a result, it affects all of the users of the website that browse to a page which contains the malicious piece of text.
Today's issue falls, as per the title, in the "reflected" category, and thus would not have "spread", being limited to the direct victims of any malicious link.
While that's obviously not a good thing, it is still a relief in that regard.
Why was MangaDex vulnerable?
MangaDex was vulnerable to such an issue due to a portion of the website which handles redirecting the user back to the page they logged in from once signed in.
To explain it, here is a summary of how authentication works on MangaDex:
- First, the user clicks the login button on
mangadex.org/title/123...
, which redirects them toauth.mangadex.org
with some extra information, notably the specific page they came from. - After authenticating themselves, they are redirected back to
mangadex.org/auth/login
, once again with some extra information about the authentication result and the page they had come from originally. - Assuming the login was successful, they are then marked signed in and redirected to
mangadex.org/title/123...
.
Keeping the original page around through this redirection dance is a little tedious, but it is helpful behaviour, as sending the user back to the home page at the end would be jarring.
However, the specific way the redirection in Step 3 was implemented was wrong and caused the issue.
Here is a simplified version of the code handling it:
if (authenticationSuccessful) {
redirectTo = route.query.afterAuthentication;
window.location.assign(redirectTo);
}
- The value of
redirectTo
becomes/title/123...
, from...&afterAuthentication=/title/123
. - Location.assign(<url>) navigates to
<url>
(and thus/title/123...
here).
Seems all quite reasonable? Except... it isn't.
If you run the following snippet in your browser's console (F12
-> Console
), something quite unexpected happens:
window.location.assign(`javascript:alert('Oops!')`);
Turns out, this has nothing to even do with redirections.
Browsers, when asked to navigate to something like javascript:<code>
will execute <code>
in the current page. While surprising this has its legitimate uses, like bookmarklets.
Tying it all together, imagine the following link: mangadex.org/auth/login?afterAuthentication=javascript:<code>
.
If you convinced someone to open this link in their browser, it would have first navigated to our website, and then executed <code>
on the page.
And you could have made the code as malicious as you like, for example exfiltrating the user's current MangaDex API tokens to a server you control, then impersonating their account.
Note: non-MangaDex browser data would not have been exposed. The malicious code would have executed in the context of mangadex.org
, and modern browsers prevent websites from looking at the data relating to other websites for privacy.
Detailed timeline and corrective patch
The timeline
2024-03-03 04:43 UTC
Samyak Jain reports the issue to us on our security contact email (about the logout redirection, specifically, but the login and logout shared the same faulty logic).2024-03-03 06:14 UTC
We acknowledge the issue and let him know that we will prepare a patch.2024-03-03 08:19 UTC
A patch is written by one of our developers.2024-03-03 13:48 UTC
We get in a call to prepare a release and check that this was the only place vulnerable to this on our website.2024-03-03 15:13 UTC
A patched version of the website is deployed.2024-03-03 15:51 UTC
After internal discussions, we inform Samyak Jain that:2024-03-03 17:59 UTC
We issue his reward, and discussed the details of whether he would like to be named in this blog post.
The fix
There are a lot of approaches one can take to fix the issue; we chose the following combination for now:
- We ensure that the redirection request points to something that is a valid URL, otherwise redirecting to the homepage.
- Just in case some convoluted payload managed to bypass that check, we additionally prefix the redirection URL with
https://mangadex.org
explicitly (i.e. redirecting tohttps://mangadex.org/title/123..
rather than to/title/123...
), so that it is always guaranteed to be interpreted as a URL and never as a piece of code to execute.
Bug bounties and MangaDex
While we do not have a formal bug bounty program, astute readers will have noted that we did reward the researcher who contacted us for their disclosure.
We are indeed happy to reward valid vulnerability disclosures. Though we have no committed/public reward scale, we operate mostly based on CVSS severity scores. And we aim to make the process as fast as possible, both for the safety of our users and as respect to researchers.
If you are interested in pentesting, you can find the relevant information and contact details in our security.txt link.
The elephant in the room: Content Security Policies
Sadly, this issue should really not have ever happened in the first place.
That is, because there is an entire security system meant to prevent the entire class of attacks (XSS attacks, that is), the Content Security Policy system.
While a little bit too large of a topic for this specific post, they allow a site to deny execution of Javascript code (and much more) unless it is specifically cryptographically signed by the website.
Unfortunately, these are very poorly supported if at all in combination with client-side rendering technologies we use. We have been following or directly involved in the various layers that need changes to fix the issue. There has been progress in the right direction since the end of 2023, and hopefully we can now focus on this and get it working on MangaDex as well soon.
Thank you for reading this post to the end. We hope it was informative and that it will make you have a quick look at your own projects.
As an entire team, we would like to extend our thanks one last time to Samyak Jain from NexusCrypt.com for disclosing this issue to us.
I would also finally like to personally thank Alex, who promptly prepared the patch after I asked him, Flare, for assisting in the CVSS evaluation rationale, and the rest of the MangaDex staff at large.
PS: No footnotes this time around!