Old food
gpnctf24
Task: GitHub Actions CI/CD security challenge with a vulnerable pull_request_target ci.yml (checks out attacker PR merge-ref) and a deleted flag.yml that references secrets.FLAG, all in a private per-player repo. Solution: achieve privileged RCE via the PR merge-ref checkout, recover the contents:write GITHUB_TOKEN from actions/checkout-persisted .git/config, roll the default branch back via the REST git refs API to resurrect the deleted flag.yml (bypassing the workflow-scope push protection), then open a triggering PR to run it and exfiltrate the double-base64 secret into the public run logs.
$ ls tags/ techniques/
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
Old food — GPNCTF24 (GPN24 / KITCTF)
Description
Old food, gold food, mold food, bold food, bad f00d, whatever.
ncat --ssl steamed-filet-under-sliced-harissa-uz0h.gpn24.ctf.kitctf.de 443
English summary: Connecting to the service provisions a private per-player GitHub
repository (a Node.js "Fresh Bite" recipe app) and adds the player as a
read-only collaborator. A repository Actions secret named FLAG holds the flag.
The repo's CI workflow uses the privileged pull_request_target trigger and
checks out the attacker's PR code, but ci.yml never references secrets.FLAG.
A second workflow, flag.yml, does reference the flag — but it was deleted
from main and only survives in git history. The goal ("Old food" =
stale/old workflow that can be resurrected) is to bring the deleted workflow
back to life and make it leak the secret. The author, intrigus-lgtm, is a
known GitHub Actions security researcher, confirming the theme.
Analysis
Provisioning mechanism
The ncat --ssl ... 443 endpoint prompts for a GitHub username. A backend
(server.py → node index.js, using an authenticated GitHub PAT) then:
- Resolves the GitHub user's
actor_idvia the GitHub API. - Creates a private repo
<actor_id>_<username>_old-food-challengein orgGPNCTF24-2. - Mirror-pushes a template carrying many branches (
main,feature/*,fix/*, ...) and the full git history. - Waits for
ci.ymlto appear, then adds the player as a pull (read-only) collaborator. - Adds a repository Actions secret
FLAG— the real flag.
Reconnaissance trick: probing the prompt with a throwaway username (e.g.
octocat) leaks the org name GPNCTF24-2 and the repo-naming scheme through the
node error output, even before owning an instance. The service warns not to
test against the live instance (limited Actions minutes) — develop the exploit on
a personal fork, then fire once at the real instance.
...
$ grep --similar
Similar writeups
- [misc][free]Volatile Component— kitctf
- [web][free]Fancy Food Notifications— GPNCTF 2025 (KITCTF)
- [web][Pro]awesome pipeline— kalmarctf
- [web][free]Prison Pipeline— hackthebox_business_ctf_2024
- [web][free]Secure Secretpickle— gpnctf