-
Notifications
You must be signed in to change notification settings - Fork 12
Description
Context
The LiteLLM supply chain attack showed how unpinned CI/CD dependencies can cascade into full credential theft and malicious package publishing. An attacker compromised Trivy (a scanning tool), used that foothold to steal PyPI publishing credentials from LiteLLM's CI, and published backdoored versions for ~3 hours (~3.4M downloads/day).
Spawn is not vulnerable to the exact same attack (we don't publish to npm/PyPI — CLI releases use gh release upload), but we share several of the same root-cause patterns.
Findings
HIGH — GitHub Actions pinned by tag, not commit SHA
All 11 workflow files reference actions by major version tag (@v4, @v2, @v7, etc.). A compromised action maintainer (or stolen credentials) can force-push malicious code to an existing tag.
Affected actions across all workflows:
actions/checkout@v4actions/github-script@v7oven-sh/setup-bun@v2docker/login-action@v3docker/build-push-action@v6hashicorp/setup-packer@main← worst case: branch ref, not even a tag
Fix: Pin every action to its full commit SHA with a version comment:
- uses: actions/checkout@e2f20c01b594fdf7527dbad7fecee28055a9b47a # v4.0.0HIGH — hashicorp/setup-packer@main + version: latest
packer-snapshots.yml uses a branch ref (@main) for the action AND version: latest for Packer itself — double-unpinned. Packer runs with DO_API_TOKEN in the same job, so a compromised action could exfiltrate cloud credentials.
MEDIUM — Unpinned tool installs
| Tool | Workflow | Issue |
|---|---|---|
| shellcheck | lint.yml |
apt-get install -y shellcheck — no version pin |
| bun | agent-tarballs.yml |
bun-version: latest |
MEDIUM — Agent curl \| bash installs without integrity checks
packer/agents.json installs claude, opencode, hermes via curl | bash with no checksum verification. The domain allowlist and command blocklist are good mitigations, but don't prevent a compromised upstream install script.
GOOD — Already solid
- ✅ Secret isolation: Publishing/cloud credentials properly scoped to their workflow steps
- ✅ No npm/PyPI tokens in CI — releases use
gh release upload - ✅ Lockfile committed:
bun.lockpins all dependency versions exactly - ✅ No lifecycle scripts: No
postinstall/prepackhooks - ✅ Domain allowlist + command blocklist on agent tarball builds
Recommended mitigations (priority order)
- Pin all GitHub Actions to commit SHAs — highest ROI, prevents the Refactor spawn scripts with shared library and OAuth fallback #1 LiteLLM-style vector
- Pin
hashicorp/setup-packerto a commit SHA + specific Packer version — this one has cloud creds in scope - Pin shellcheck and bun to specific versions in CI
- Add SHA256 checksums for agent
curl | bashinstalls where upstream provides them - Enable Dependabot for GitHub Actions version updates (it can auto-PR SHA bumps)
- Consider adding
permissions:blocks to every workflow (currently some inherit defaultwrite-all)
Filed from Slack by SPA