Your deploy box is the target: supply chain defenses after this week's attacks A developer, responding to two supply chain attacks reported in November, audited their own CI configuration and found a single build job holding a registry token, deploy key and cloud credential at once. The attacks included a stolen developer key that pushed a dropper into @ethersphere/bee-js 13.3.0 via the normal publish workflow, and a fresh GitHub account that opened CI exfiltration PRs, added an AGENTS.md note telling reviewers not to flag the uploads, and shipped a Rust crate whose build.rs harvested credentials. The developer's proposed fix splits builds from deploys so dependency-installing jobs carry no deploy credentials. I read the OpenSourceMalware report on Tuesday and then did something simple. I opened my own CI config and listed every secret a single build job could see. The attack it describes starts with a PR from a brand new account labeled "CI diagnostics" that sends environment variables to a remote URL. The answer was uncomfortable. A build job on my side holds a registry token, a deploy key and a cloud credential, all in one shell. That is exactly the shopping list attackers wrote down this week. | What happened | Date | What it means for you | |---|---|---| | A stolen developer key pushed a dropper into @ethersphere/bee-js 13.3.0, and the publish workflow shipped it to npm and GitHub | Nov 9 | Your release pipeline will publish whatever a valid key commits | | A brand new GitHub account sent CI exfiltration PRs, a prompt injection for reviewers and a Rust crate with a build.rs stealer | Nov 10 | Build scripts and PR checks run with your secrets in reach | | Socket's hardening guide says most 2025 and 2026 CI compromises came through npm install , not workflow bugs | Nov 3 | Install time is the weak spot, so lock it down first | OX Security reported on November 9 that attackers likely used a stolen developer access key to commit malicious code to the official bee-js and swarm-desktop repositories. The commit triggered the normal publish workflow, which created the npm release and the GitHub release. No one broke into the registry. The pipeline did its job with a bad commit. The dropper then asked a command server for a payload matched to the victim's operating system. It uploaded the local Swarm node's encrypted key and config, then installed a backdoor. On Linux and macOS the backdoor looks up its server address from an Ethereum contract, so the attacker can move it whenever they like. OX counts about 16,800 monthly downloads of exposure. That is small. The pattern is not. The second attack, written up by OpenSourceMalware on November 10, came from a GitHub account created about seven hours before the report. It ran four moves in a row. Two PRs tried to send environment variables and signing material out of CI. A third PR added a paragraph to AGENTS.md telling reviewers, including automated ones, not to flag those uploads. Another PR added a Rust crate, lwd-uri-util , whose build.rs gathers .git-credentials , .aws/credentials and .npmrc . Finally, a fake security disclosure sent two maintainers to a cloned sign-in page. Read that list again if you deploy code. The target is not your app. The target is the box where your app gets built. A typical CI job carries a registry push token, a cloud credential and a deploy SSH key. It also runs arbitrary install scripts from hundreds of transitive packages. One malicious postinstall or build.rs inherits all of it. The OpenSourceMalware report lists what the Rust stealer wants: GitHub, AWS, Cargo, npm, PyPI, Android signing keys and CI secrets. Its advice for anyone who built the affected branches is to revoke and reissue every secret present in that build environment. That is a long afternoon. The cheaper move is to make sure the build never holds most of them. Here is the rule I now apply. A job that installs dependencies gets no deploy credentials. A job that deploys installs nothing. name: release on: push: tags: "v " permissions: {} jobs: build: runs-on: ubuntu-latest permissions: contents: read steps: - uses: actions/checkout@