Bug Writeup: Leaking Discord users emails via local RPC API
Leaking Discord users emails via local RPC API
What was the issue?
Discord's RPC API allows developers to integrate client commands into their applications (most commonly setting custom statuses).
However, a lack of permission checking granted the authorised application access to the current user's full user profile including email and phone number, even when not authorized to access it.
When the RPC websocket is opened, the client sends an AUTHORIZE command to tell the user's Discord client which application is trying to connect, and you provide a scopes array to tell the client what level of access is needed. In this case, all you needed was messages.read. Typically, the identify scope returns a user object minus the email, yet this returned a full object with sensitive information.
Realistically, there is not much room for an attacker as this is all done locally. The only authorised Discord application that I tested with was the official StreamOverlay app which many gamers and streamers will have authorized in the past (I authorised it in 2019!). However, that doesn't stop an attacker and there is always room for abuse.
What did it allow?
It allowed a potential attacker to gain undetected access to a Discord users full user object, including email and phone number. This took advantage of a lack of permission checks using the local Discord client API that all Discord desktop users have exposed. This allowed undetected access as it made 0 requests to the Discord API itself meaning suspicious activity technically can't be detected.
Screenshots / Code Snippets

{
"id": "1311134044020543529",
"blocked": false,
"bot": false,
"content": "oh i thought that was because i put `test` as my rpc button <:KEKW:829757927329628192>",
"content_parsed": [
{
"type": "text",
"content": "oh i thought that was because i put ",
"originalMatch": {
"0": "oh i thought that was because i put ",
"index": 0
}
},
{
"content": "test",
"type": "inlineCode"
},
{
"type": "text",
"content": " as my rpc button ",
"originalMatch": {
"0": " as my rpc button ",
"index": 0
}
},
{
"emojiId": "829757927329628192",
"name": ":KEKW~3:",
"animated": false,
"type": "emoji"
}
],
"nick": "test",
"edited_timestamp": null,
"timestamp": "2024-11-27T00:58:35.787Z",
"tts": false,
"mentions": [],
"mention_everyone": false,
"mention_roles": [],
"embeds": [],
"attachments": [],
"author": {
"id": "USER_ID",
"username": "MY_USERNAME",
"discriminator": "0",
"avatar": "MY_AVATAR",
"avatarDecorationData": null,
"banner": "MY_BANNER",
"email": "redacted@email.com",
"verified": true,
"bot": false,
"system": false,
"mfaEnabled": true,
"mobile": true,
"desktop": true,
"premiumType": 2,
"flags": 4194416,
"publicFlags": 4194368,
"purchasedFlags": 7,
"premiumUsageFlags": 7,
"phone": "+447XXXXXXXXXX",
"nsfwAllowed": true,
"guildMemberAvatars": {
"GUILD_ID_REDACTED": "MY_AVATAR",
"GUILD_ID_REDACTED": "MY_AVATAR"
},
"hasBouncedEmail": false,
"personalConnectionId": null,
"globalName": "MY_DISPLAY_NAME",
"clan": {
"identityGuildId": null,
"identityEnabled": false,
"tag": null,
"badge": null
}
},
"pinned": false,
"type": 0
}In total, this took Discord ~15 days to resolve.
Initial report: 24th November 2024
Confirmed fixed: 12th December 2024