loki-secrets-dump: A Security Wake-Up Call
How a malicious workflow infiltrated all my repositories, what it tried to steal, and the critical lessons I learned about GitHub Actions security.
It started like any other day. I opened GitHub to check on my projects, and suddenly noticed something wrong—every single one of my repositories, fortunately its only the public ones, had a new commit I didn’t make. The commit added a workflow file called loki-secrets-dump.yml. My stomach dropped.
I had been hacked.
The Attack: What Happened
Within minutes, a malicious GitHub Actions workflow had been committed to all of my public repositories. Here’s what the attacker pushed:
name: loki-secrets-dump
on:
workflow_dispatch:
jobs:
dump:
runs-on: ubuntu-latest
steps:
- name: Dump env
run: |
echo "=== ENV ==="
printenv | sort
echo "=== GITHUB ==="
echo "GITHUB_TOKEN=${GITHUB_TOKEN}"
At first glance, it looks simple. But this workflow is designed to do one thing: steal secrets.
What This Workflow Actually Does
When triggered, this workflow:
- Dumps all environment variables available in GitHub Actions runners
- Explicitly prints the
GITHUB_TOKENwhich has read/write access to the repository - Logs everything to the workflow run output where the attacker can retrieve it
The GITHUB_TOKEN automatically provided by GitHub can:
- Read all repository code (including private repos)
- Push commits and create branches
- Modify issues, pull requests, and releases
- Access repository settings
Even worse, the attacker used workflow_dispatch, meaning they could trigger this workflow manually at any time to harvest fresh tokens.
The Real Danger I Almost Missed
While investigating, I found something far worse in one of my deployment workflows:
- name: Copy environment files from secrets
run: |
echo "VITE_API_BASE_URL=${{ secrets.FE_BASE_URL }}" >> .env
echo "VITE_ALLOWED_HOSTS=${{ secrets.FE_ALLOWED_HOSTS }}" >> .env
# ... more secrets ...
cat .env # ⚠️ THIS LINE PRINTS ALL SECRETS TO LOGS
That innocent-looking cat .env command? It was broadcasting all my secrets to anyone who could view the workflow logs. This included:
- API endpoints
- Configuration values
- And most critically: AWS credentials used later in the workflow
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
If the attacker triggered this workflow, they would have gotten:
- Full AWS access to my S3 buckets
- Ability to modify, delete, or exfiltrate data
- Potential access to other AWS resources
- The ability to rack up massive cloud bills
My Response: What I Did Immediately
1. Changed My GitHub Password
The attacker clearly had access to my account. First priority: cut off that access.
2. Enabled Two-Factor Authentication
I should have had this enabled already. Don’t make my mistake—enable 2FA now.
3. Checked and Revoked All Access
I went through:
- Personal access tokens (classic and fine-grained)
- OAuth Apps - revoked anything suspicious
- GitHub Apps with repository access
- SSH keys - removed any I didn’t recognize
4. Reviewed the Security Log
Fortunately, my security log only showed my own activity, which meant the attacker likely:
- Stole credentials from my local machine
- Had malware on my computer
- Compromised a password I reused elsewhere
5. Scanned for Evidence
I checked the Actions tab on every affected repository to see if the malicious workflows had actually executed. Thankfully, they hadn’t—the attacker had deleted the branch before triggering them.
But here’s the scary part: workflow logs can be deleted. The attacker could have:
- Triggered the workflows
- Stolen all the secrets from the logs
- Deleted the workflow runs to cover their tracks
I would never know.
6. Rotated Everything
Because I couldn’t be 100% certain the workflows hadn’t run, I treated this as a full compromise:
- Rotated all AWS credentials
- Changed all GitHub repository secrets
- Reviewed AWS CloudTrail for suspicious activity
- Checked S3 buckets for unauthorized access
7. Fixed the Vulnerable Workflow
I immediately removed that cat .env line from my deployment workflow. There is never a good reason to print secrets to logs.
The Critical Lessons
1. Never Print Secrets to Logs
Even for debugging. Even temporarily. Even in private repos. Use GitHub’s secret masking and assume workflow logs are public.
Bad:
run: |
echo "My secret is: ${{ secrets.MY_SECRET }}"
Good:
run: |
echo "Secret loaded successfully"
2. Audit Your Workflows for Secret Exposure
Search all your workflows for:
cat .envprintenvechostatements with secrets- Any debug logging that might leak credentials
3. Use Minimal Permissions
The GITHUB_TOKEN permissions can be restricted:
permissions:
contents: read # Only read access, not write
4. Enable 2FA Everywhere
Not just GitHub—everywhere. This single step makes most credential theft attacks significantly harder.
5. Review OAuth and App Permissions Regularly
Go to your GitHub settings and audit:
- What apps have access to your repos?
- When did you last review this list?
- Do you recognize everything?
6. Monitor Your Repositories
Set up alerts for:
- New workflow files being added
- Changes to existing workflows
- Unexpected commits or branches
7. Treat GitHub Actions Like Production Infrastructure
Because it is. Workflows run with real credentials, access real resources, and can cause real damage if compromised.
8. Assume Breach and Verify
When something suspicious happens:
- Don’t assume “it probably didn’t run”
- Check CloudTrail, access logs, everything
- Rotate credentials even if you’re not certain
- Better safe than sorry
What You Should Do Right Now
- Check your GitHub workflows for the
loki-secrets-dump.ymlfile or similar - Search for secret exposure in your existing workflows (look for
cat,printenv,echowith secrets) - Enable 2FA if you haven’t already
- Review your OAuth apps and revoke anything suspicious
- Audit your security log for unusual activity
The Bigger Picture
This attack wasn’t sophisticated. It was a simple workflow that exploited a fundamental truth: GitHub Actions runs with real credentials and real permissions.
The attacker knew that:
- Most developers don’t carefully review what permissions their workflows have
- Many workflows accidentally leak secrets through logging
- Workflow logs persist and can be accessed later
- Most people don’t have 2FA enabled
They were counting on these security gaps. Don’t let your repositories be the next target.
Final Thoughts
I got lucky. The workflows didn’t run (as far as I can tell), and I caught it quickly. But this was a wake-up call about how easily a single compromised credential can cascade into a full infrastructure breach.
Security isn’t about being paranoid—it’s about being prepared. Review your workflows, enable 2FA, rotate your credentials regularly, and always assume that anything printed to logs is public information.
Stay safe out there.