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:firstname.lastname@example.org. 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 a
@ 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.
decodeURIComponent the authentication prefix.
http://%email@example.com 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 app).
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 and no clients are currently vulnerable. Discord security described it as “just a client parser bug” and unfortunately it did not qualify for the bounty program.
Thanks again to @fransla for pushing me on when I would have given up :)