Qais "qaisjp" Patankar

Emojimancer: recovering deleted Discord emoji

09 Apr 2021

It’s quite nice how Slack allows anyone to add emoji. To emulate that on Discord, we granted the @everyone role the “Manage Emoji” permission.

This has been fine for years, but because of the pandemic, and young people these days preferring Discord as a primary communication platform, that Discord server has had to grow up a little bit. (i.e. less Facebook Messenger, less in-person chat, more Discord chat.)

Unfortunately, last night we had a little bit of an incident:

<annoying_user> oh shit oh shit, sorry, I deleted all moving emojis on your server. can you revert the change?

<admin> wtf? why would you do that

<annoying_user> I was bored and joking when I did it, now I’m not…

<annoying_user> ok I’ll just leave the server and never disturb you again

annoying_user deletes their Discord account

And as with all incidents, in true “this is why we can’t have nice things” fashion, we must now react by taking away the ability for anyone to add emoji. Maybe in the future, once Discord’s Slash commands supports attachments, it would be nice to look into creating an /add-emoji command.

So, here is how I recovered the emoji:

  1. Opened Chrome Developer Tools, navigated to the Network tab, and set the filter to XHR requests.
  2. With the Developer Tools pane open, navigated to the audit logs page.
  3. Saw a request called /audit-logs?limit=50 appear.
  4. Clicked that entry, selected the “Response” tab on the right hand side, and copy the JSON inside to a file, audit-log.json.
  5. Inspected audit-log.json and saw events like this:
    {
      "audit_log_entries": [
          {
              "id": "829840235889688597",
              "user_id": "812683478374023218",
              "target_id": "688076782351417399",
              "action_type": 62,
              "changes": [
                  {
                      "key": "name",
                      "old_value": "crabrave"
                  }
              ]
          },
          ...
      ],
      ...
    }
    
  6. I spotted that target_id is probably the emoji ID.

    To test that this emoji ID is correct and still works, I sent an animated emoji in another server, then right clicked it, and selected “Open Image in New Tab”, which sent me to a page like this:

    https://cdn.discordapp.com/emojis/403011495144980480.gif?v=1

    I replaced that ID with the target_id, and the old emoji appeared. So it’s definitely possible to recover the emoji!

  7. Then I wrote a jq filter to fetch all the emoji that were deleted:

    cat audit-log.json | \
        jq -r '
            .audit_log_entries[] |
            select(.action_type==62) |
            ("curl https://cdn.discordapp.com/emojis/" + .target_id + ".gif?v=2 > " + .changes[0].old_value + ".gif")
        '
    

    This filters for EMOJI_DELETE (62) audit log events, and creates a URL based on the target_id and old_value fields.

    Resulting in these lines:

    curl https://cdn.discordapp.com/emojis/688076782351417399.gif?v=2 > crabrave.gif
    curl https://cdn.discordapp.com/emojis/776757668458659880.gif?v=2 > dat_boi_coming.gif
    curl https://cdn.discordapp.com/emojis/784418433890123816.gif?v=2 > apensive.gif
    curl https://cdn.discordapp.com/emojis/819566467266904064.gif?v=2 > diamond_hands_to_the_moon.gif
    curl https://cdn.discordapp.com/emojis/806491952681844736.gif?v=2 > thinkaboutit.gif
    curl https://cdn.discordapp.com/emojis/822592042596433932.gif?v=2 > floppapet.gif
    
  8. I ran these commands to download the gifs, and then manually uploaded them using the regular Emoji tab on Discord.

    Discord automatically picks up the name of the emoji from the filename, and there were only six, so this was quick & easy to do. For larger numbers of emoji, I imagine one would want to a proper script that uses the API, provides more configurability, and correctly handles non-animated emoji.

I hope you find this useful!