Discord DoS with a single message
Crafted message causes causes denial of service on a Discord channel
TLDR: I discovered that sending the message http://%zz@example.com
from the mobile app would
result in a permanent denial of service of a Discord channel on the web and desktop clients.
It began when my mentor, @fransla, sent me this blog post about a WhatsApp vulnerability and encouraged me to look for similar bugs in other Electron-based chat clients. I started with Discord.
First I checked to see if the link’s preview text was being generated by my client or the server,
in the hopes that I could edit the preview that was being displayed to other users. That wasn’t
successful, so I moved on to play with the @
symbol in my URLs.
URLs can provide a username and password for authentication in the following format
user:pass@website.com
. Discord’s mobile app completely stripped the authentication part of the
URL, while the desktop and web clients left it in the link. This inconsistent handling of
authentication URLs immediately raised red flags, as it indicated that special code was used when an
@
was present. With further testing, I discovered that the Discord server was not validating
percent encoding correctly, and was accepting percent symbols even if they didn’t have two
hexadecimal characters after them.
Backend | Mobile | Desktop | Web | |
---|---|---|---|---|
Displays the user:pass | N/A | N | N | N |
Link contains the user:pass | Y | N | Y | Y |
Accepts percent encoded symbols (%78) | Y | Y | Y | Y |
Accepts unicode percent encoding (%u0078) | Y | Y | N | N |
The desktop and web clients break when they receive invalid percent encoding in the authentication
part of a URL. This happens because the JavaScript URL parser creates an uncaught error when it
attempts to decodeURIComponent
the authentication prefix.
The message http://%zz@example.com
can be successfully sent from a mobile app, or by intercepting
and editing the POST request to the server. The mobile app isn’t affected and displays a link to
http://example.com
. The desktop client will not receive any future messages, and reloading the
desktop and web clients will result in a never-ending loading screen — no messages in that channel
can ever be viewed again (except on a mobile device).
Discord’s time-to-patch was impressively short, with the patch being made live on the same afternoon that I received a human reply, less than two days after my initial report. The patch was released on Feb 13 2020 and no clients are currently vulnerable. Discord security described it as “just a client parser bug” so no bounty was awarded.
Thanks again to @fransla for pushing me on when I would have given up :)