HighSupply chainMonitoring

BufferZoneCorp: 10 Go modules and 7 knot-* Ruby gems stole CI secrets, planted SSH keys and rewired GitHub Actions

BufferZoneCorp Go modules and knot-* gems stole SSH, cloud, npm, gh and kube credentials and tampered with GitHub Actions. Check go.mod and Gemfile.lock.

Published
Updated
Fixed in
No clean versions. Remove every github.com/BufferZoneCorp module and every knot-* gem listed here
Exploitation
Yes. Live payloads on RubyGems and the Go module proxy from April 2026; source repositories stayed public until at least 2 October 2026

What happened

On 1 May 2026, Socket reported 17 malicious packages from the GitHub account BufferZoneCorp and the RubyGems account knot-theory (Socket). The account was created at 12:06 UTC on 20 April 2026 and published 15 repositories within the next hour (CyberXYZ). GBHackers describes the names as mimicking trusted developer utilities (GBHackers).

Go modules, all under github.com/BufferZoneCorp/ (OSV MAL-2026-3620 to 3629):

ModuleBehaviour
go-stdlib-extStealer, plants SSH key, disables checksum checks, fake go wrapper
go-retryablehttpRoutes Actions traffic through the collector; fake go leaks GH_TOKEN
go-metrics-sdkRewrites GOPROXY and strips logrus from go.sum
go-weather-sdkSame logrus swap as go-metrics-sdk
grpc-clientStealer, post-commit hook, fake kubectl
net-helperStealer, post-commit hook
config-loaderStealer, post-commit hook
go-stdlogReconnaissance: tokens, Docker socket, Kubernetes, cloud metadata
log-coreStealer in its first commit only, then cleaned
go-envconfigClean at its latest commit

Behaviour column from CyberXYZ. Socket names v0.4.0 for go-metrics-sdk, go-retryablehttp and go-stdlib-ext, and says go-stdlog had not been published as a module when it wrote; OSV now lists it (OSV MAL-2026-3625).

Ruby gems, with the versions OSV records (OSV MAL-2026-3630 to 3636):

  • knot-activesupport-logger 7.1.6
  • knot-devise-jwt-helper 1.0.7
  • knot-rack-session-store 1.0.2
  • knot-rails-assets-pipeline 6.1.11
  • knot-rspec-formatter-json 3.13.5
  • knot-date-utils-rb 1.0.0 (decoy, no payload yet)
  • knot-simple-formatter 1.0.0 (decoy, no payload yet)

The Go security team blocked the modules after Socket’s report (Socket). On 2 October 2026, CyberXYZ found proxy.golang.org returned no versions and all seven gems were gone from rubygems.org, but all 17 source repositories were still public with payloads intact. Anyone using GOPROXY=direct or GOPRIVATE, or copying the code, could still pull them (CyberXYZ). As of 2 November 2026, the GitHub API returns “not found” for the BufferZoneCorp account.

How the payloads work

Details from Socket and CyberXYZ:

  • Go: a package-level init() starts a goroutine, so importing the package is enough. It runs in go test, during code generation and in any binary that links it. Strings are XOR-encoded with the key sysutil1.
  • Ruby: knot-activesupport-logger and knot-devise-jwt-helper run from ext/extconf.rb during gem install, as part of the native extension build. The other payload gems run when required.
  • Stolen files: ~/.ssh/id_rsa, ~/.ssh/id_ed25519, ~/.aws/credentials, ~/.npmrc, ~/.netrc, ~/.config/gh/hosts.yml, plus ~/.docker/config.json and ~/.kube/config (Go) and ~/.gem/credentials and ~/.gitconfig (Ruby). Environment variables are filtered by keywords such as token, secret, pass, aws and github; CyberXYZ notes the Go filter matches almost everything.
  • Exfiltration: hxxps://webhook[.]site/49c21843-c27c-4a1b-b1f6-037c3998055f, overridable with PKG_ANALYTICS_URL.
  • SSH backdoor: after a successful upload, go-stdlib-ext appends ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBp9VZGMxqFpTwKbKJi7dS2mNrX3LqEoHcYsWfAkZvUt deploy@buildserver to ~/.ssh/authorized_keys. knot-rack-session-store appends a different key with the comment deploy@rack-session.
  • GitHub Actions tampering: go-metrics-sdk and go-weather-sdk write GOPROXY=<collector>|direct, GOSUMDB=off, GONOSUMDB=*, GOFLAGS=-mod=mod and a new GOMODCACHE to $GITHUB_ENV. go-stdlib-ext writes GONOSUMCHECK=* and GONOSUMDB=* and puts a fake go first on $GITHUB_PATH. go-retryablehttp sets HTTP_PROXY and HTTPS_PROXY to the collector and its fake go sends GH_TOKEN in an X-Token header.
  • Ruby in Actions: the five payload gems write a monitor.rb to ~/.activesupport/lib, ~/.devise-jwt/lib, ~/.rack-session/bin, ~/.rails-assets/lib or ~/.rspec-fmt/lib, and append RUBYOPT=-r<path>/monitor.rb to $GITHUB_ENV, so every later Ruby step loads it.
  • Git hook beacon: grpc-client, net-helper, config-loader and knot-rails-assets-pipeline add a line containing gc?r= to .git/hooks/post-commit. It sends the repository’s origin URL after every commit, and survives removing the package.

Am I affected?

bash
# Go: module files, vendored code and the module cache
grep -rn 'BufferZoneCorp' go.mod go.sum vendor/modules.txt 2>/dev/null
ls "$(go env GOMODCACHE)/github.com/" 2>/dev/null | grep -i bufferzonecorp

# Ruby: lockfile and installed gems
grep -nE '^ +knot-(activesupport-logger|devise-jwt-helper|rack-session-store|rails-assets-pipeline|rspec-formatter-json|date-utils-rb|simple-formatter) ' Gemfile.lock 2>/dev/null
gem list 2>/dev/null | grep -E '^knot-'

# Planted SSH keys
grep -nE 'deploy@(buildserver|rack-session)' ~/.ssh/authorized_keys 2>/dev/null

# Git hook beacon in every repository under your home directory
grep -l 'gc?r=' $(find ~ -path '*/.git/hooks/post-commit' 2>/dev/null) 2>/dev/null

# Ruby monitor.rb drop directories
ls -la ~/.activesupport/lib ~/.devise-jwt/lib ~/.rack-session/bin ~/.rails-assets/lib ~/.rspec-fmt/lib 2>/dev/null

On self-hosted runners, check ~/.ssh/authorized_keys for the runner user too. In GitHub Actions logs, search for GONOSUMDB, GONOSUMCHECK, GOSUMDB=off, RUBYOPT=-r, and GOPROXY or HTTPS_PROXY values your workflows did not set (CyberXYZ). In network logs, look for webhook.site/49c21843-c27c-4a1b-b1f6-037c3998055f.

What to do now

  1. Remove the packages from go.mod, go.sum, vendor/ and Gemfile.lock, then go clean -modcache and reinstall gems. There is no clean version to move to.
  2. Remove persistence: delete the deploy@buildserver and deploy@rack-session lines from authorized_keys, the gc?r= lines from .git/hooks/post-commit in every clone, and the monitor.rb directories above.
  3. Rotate SSH keys, AWS credentials, npm and Docker tokens, RubyGems credentials, gh tokens and Kubernetes credentials on every machine and self-hosted runner that imported or installed these packages (CyberXYZ). Rotate any GitHub token that was in GH_TOKEN during a CI run with go-retryablehttp.
  4. Rebuild self-hosted runners. An attacker-held key in authorized_keys means anyone with the private key could log in after the job ended.
  5. Pin Go environment in CI. Set GOPROXY, GOSUMDB and GONOSUMDB explicitly in each job, and fail a job if a step changes them. Treat any dependency that writes to $GITHUB_ENV or $GITHUB_PATH as hostile.

Why this matters

$GITHUB_ENV and $GITHUB_PATH carry changes from one step into every later step in the job. A dependency that runs once during go test or bundle install can switch off checksum verification, put a fake go first on the path, or preload Ruby code for the rest of the workflow. Your workflow file does not change, so a diff review will not catch it.

Sources