The BufferZoneCorp campaign — a Ruby Gem supply chain attack confirmed active within the last 72 hours — published malicious gems and Go modules that appeared completely benign on installation, then received credential-stealing and persistence payloads via version updates after being adopted into production pipelines. Seven Ruby gems and nine Go modules have been confirmed as part of the campaign. All have since been yanked from RubyGems.org and blocked from the Go module proxy. If your Gemfile.lock or go.sum references any knot- gems or github.com/BufferZoneCorp/ modules, treat your CI runner, developer workstation, and any secrets accessed during builds as compromised.
This article turns the BufferZoneCorp TTP (Tactic, Technique, and Procedure — the specific methods an attacker uses) into a concrete Ruby Gem supply chain attack detection checklist: what logs to pull, what files to inspect, and how to gate your CI pipeline against the sleeper-package pattern going forward.
What Is a Sleeper Package and Why bundle audit Misses It
A sleeper package (also called a “time-bomb dependency”) is a package that passes all static vulnerability checks at install time because the malicious code has not yet been introduced. The attacker publishes a v1.0.0 that is entirely benign — complete with a plausible README, reasonable dependencies, and no flagged behavior — then later pushes a v1.0.1 that contains the payload.
bundle audit (from the bundler-audit gem) scans your Gemfile.lock against the Ruby Advisory Database for known CVE assignments. It cannot catch a package that has not yet been catalogued as malicious, and it does not inspect gem source code for behavioral indicators. go mod verify (Go’s built-in module integrity checker) confirms that locally cached modules match their recorded checksums in go.sum — but cannot detect a package that was malicious from the start, or one where the attacker pushed malicious code and had the hash recorded legitimately.
This is the core Ruby Gem supply chain attack detection gap the BufferZoneCorp campaign exploited.
Affected Packages and Payload Breakdown
Ruby Gems: the knot-* Cluster
All affected gems share the knot- namespace prefix, mimicking legitimate Rails and Ruby utility libraries:
| Gem Name | Impersonates | Payload | |—|—|—| | knot-activesupport-logger | activesupport-logger | Credential harvesting | | knot-devise-jwt-helper | devise-jwt | Credential harvesting | | knot-rack-session-store | rack-session | Credential harvesting | | knot-rails-assets-pipeline | sprockets | Credential harvesting | | knot-rspec-formatter-json | rspec-json-formatter | Credential harvesting | | knot-date-utils-rb | — | Sleeper (payload not yet deployed) | | knot-simple-formatter | — | Sleeper (payload not yet deployed) |
The credential harvesting gems exfiltrate at install time through the gem’s extconf.rb or Rakefile post-install hook — code that runs automatically when bundle install or gem install processes the package. Targeted files include:
- Environment variables (full
ENVhash) ~/.ssh/id_rsaand~/.ssh/id_ed25519(SSH private keys)~/.aws/credentials(AWS access key ID and secret)~/.gem/credentials(RubyGems authentication token)~/.npmrc(npm registry tokens)~/.netrc(generic credential store used by curl, git, and others)~/.config/gh/hosts.yml(GitHub CLI OAuth token)~/.gitconfig
All exfiltrated data is sent over HTTPS to an attacker-controlled Webhook.site endpoint — a free service that records inbound HTTP requests, allowing the attacker to collect secrets without standing up dedicated infrastructure that could be sinkholed.
Go Modules: github.com/BufferZoneCorp/*
| Module Path | Impersonates | Payload | |—|—|—| | github.com/BufferZoneCorp/go-retryablehttp | hashicorp/go-retryablehttp | Proxy hijack + SSH persistence | | github.com/BufferZoneCorp/grpc-client | google.golang.org/grpc | GitHub Actions tampering | | github.com/BufferZoneCorp/config-loader | spf13/viper | GitHub Actions tampering | | github.com/BufferZoneCorp/go-metrics-sdk | prometheus/client_golang | Proxy hijack | | github.com/BufferZoneCorp/go-weather-sdk | — | Credential harvesting | | github.com/BufferZoneCorp/go-stdlib-ext | — | Credential harvesting | | github.com/BufferZoneCorp/net-helper | — | SSH persistence | | github.com/BufferZoneCorp/log-core | — | Sleeper | | github.com/BufferZoneCorp/go-envconfig | — | Sleeper |
Go modules execute malicious logic inside init() functions — Go’s package-level initialization that runs automatically before main(), before any application code executes. The modules detect a CI environment by checking for GITHUB_ENV and GITHUB_PATH environment variables (both set automatically on GitHub Actions runners), then:
- Set
HTTP_PROXYandHTTPS_PROXYto attacker-controlled endpoints to intercept subsequent outbound network calls within the same workflow run. - Drop fake Go wrapper executables into the Go module cache (
$GOPATH/pkg/mod/cache/and$GOPATH/bin/) that impersonate legitimate Go toolchain binaries, intercepting subsequentgoinvocations from later workflow steps. - Append an attacker SSH public key to
~/.ssh/authorized_keyson self-hosted runners, establishing persistent shell access to the runner machine that survives the current workflow. - Tamper with the
$GITHUB_ENVfile to inject malicious environment variables that persist across all subsequent steps in the same job.
MITRE ATT&CK Technique Mapping
| ATT&CK ID | Technique | How BufferZoneCorp Uses It | |—|—|—| | T1195.001 | Supply Chain Compromise: Software Dependencies | Publishing malicious gem/module updates post-adoption | | T1552.001 | Unsecured Credentials: Credentials In Files | Reads .aws/credentials, .gem/credentials, .netrc, .npmrc | | T1552.004 | Unsecured Credentials: Private Keys | Exfiltrates ~/.ssh/id_rsa and ~/.ssh/id_ed25519 | | T1098.004 | Account Manipulation: SSH Authorized Keys | Appends attacker public key to ~/.ssh/authorized_keys | | T1078.004 | Valid Accounts: Cloud Accounts | Stolen GitHub OAuth tokens used for subsequent repo access | | T1036.005 | Masquerading: Match Legitimate Name or Location | knot-activesupport-logger mimics activesupport-logger | | T1059.004 | Command and Scripting Interpreter: Unix Shell | Rakefile and extconf.rb hooks execute shell commands at install time |
Step-by-Step Detection Checklist for Ruby Gem Supply Chain Attack
Phase 1: Identify Exposure
*1. Scan your Gemfile.lock for knot- packages:**
grep -E "knot-(activesupport-logger|devise-jwt-helper|rack-session-store|rails-assets-pipeline|rspec-formatter-json|date-utils-rb|simple-formatter)" Gemfile.lock
2. Scan your go.sum for BufferZoneCorp modules:
grep "github.com/BufferZoneCorp/" go.sum
3. Search all go.sum files recursively in a monorepo:
find . -name "go.sum" -exec grep "github.com/BufferZoneCorp/" {} +
4. Check installed gems on developer workstations:
gem list | grep -E "^knot-"
5. Query your CI runner artifact caches (GitHub Actions cache, GitLab CI cache, CircleCI caches) for any cached versions of the above gems or modules. A cache hit means the payload ran during an earlier build even if your current lockfile is clean. In GitHub Actions, navigate to your repository’s Actions → Caches tab and search for cache keys containing the gem names.
—
Phase 2: Check for Post-Exploitation Indicators
6. Audit ~/.ssh/authorized_keys for unknown entries on every self-hosted CI runner and any developer machine that ran a build including the affected packages:
cat ~/.ssh/authorized_keys
# Compare against your known-good baseline; any unrecognized ed25519 or rsa key warrants immediate removal and investigation
7. Search for unauthorized SSH key material across all system users on a runner host:
for user in $(cut -d: -f1 /etc/passwd); do
authkeys="/home/$user/.ssh/authorized_keys"
if [ -f "$authkeys" ]; then
echo "=== $user ===" && cat "$authkeys"
fi
done
8. Check for fake Go binaries in the module cache and GOPATH/bin:
ls -la "$(go env GOPATH)/bin/"
ls -la "$(go env GOPATH)/pkg/mod/cache/download/github.com/bufferzonecorp/"
Any executables in $GOPATH/bin/ that share names with standard Go toolchain commands (go, gofmt, gopls) but carry timestamps matching your last suspect build are indicators of the path-hijacking payload.
9. Check for unexpected proxy environment variables in your CI logs:
# Run in an affected runner shell or inspect workflow environment dumps
env | grep -iE "(https?|no)_proxy"
Legitimate builds should not set HTTP_PROXY or HTTPS_PROXY unless your organization explicitly routes CI traffic through a proxy. Any value pointing outside your infrastructure is a red flag.
10. Review GitHub Actions workflow run logs for unexpected go build steps referencing BufferZoneCorp module paths, or curl/wget calls to webhook.site endpoints:
# Using the GitHub CLI (gh)
gh run list --limit 50 --json conclusion,headBranch,createdAt
gh run view <run-id> --log | grep -iE "(webhook\.site|bufferzonecorp|HTTP_PROXY)"
—
Phase 3: Credential Rotation Triage
If any affected package was installed on a machine or CI runner during the exposure window, rotate the following immediately — do not wait to confirm whether exfiltration occurred:
11. Rotate:
- GitHub personal access tokens and OAuth tokens (
~/.config/gh/hosts.yml) — revoke atgithub.com/settings/tokens - AWS access keys referenced in
~/.aws/credentials— rotate in IAM, then audit CloudTrail for activity from the exposed key ID - RubyGems API keys (
~/.gem/credentials) — revoke atrubygems.org/profile/edit - Any SSH private keys whose material resided on an affected host — generate new keypairs and update all remote authorized_keys files
12. Re-authenticate GitHub CLI after token rotation:
gh auth logout
gh auth login
13. Audit GitHub repository deploy keys and OAuth app authorizations for unfamiliar entries created during the exposure window:
- SSH keys:
github.com/settings/keys - OAuth apps:
github.com/settings/applications - Organization-level:
github.com/organizations/<org>/settings/oauth_application_policy
CI Pipeline Hardening: Gating Against Sleeper Packages
The following controls address the sleeper-package pattern specifically — packages that bypass snapshot-based vulnerability scanners by being malicious only post-adoption. This is the CI pipeline dependency security checklist for preventing a recurrence.
1. Pin lockfiles and enforce frozen installs in CI
Require Gemfile.lock and go.sum to be committed and treat any mid-build modification as a build failure:
# GitHub Actions: fail if bundle install would modify Gemfile.lock
- name: Install gems (frozen)
run: bundle install --frozen
# For Go: verify module checksums against the Go checksum database
- name: Verify Go modules
run: go mod verify
go mod verify confirms that locally cached modules match their recorded checksums in go.sum. A checksum mismatch fails the build immediately.
2. Enable Dependabot for lockfile version monitoring
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "bundler"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"
Dependabot opens pull requests for every version bump in your locked dependencies — ensuring that a sleeper payload delivered via a v1.0.1 update triggers a code review rather than silently landing on a developer machine via bundle update.
3. Add behavioral package analysis to your CI
Socket performs behavioral analysis of RubyGems and Go modules — flagging packages that read environment variables, make outbound network calls, or access sensitive file paths at install time. The BufferZoneCorp campaign was identified and reported by Socket’s research team. Their GitHub App blocks pull requests that introduce packages with these behaviors before they reach a developer machine.
4. Restrict CI runner network egress
If you operate self-hosted GitHub Actions runners, prevent exfiltration by restricting outbound HTTPS to a known-good allowlist. The BufferZoneCorp campaign used webhook.site for exfiltration — a connection that would silently fail in an egress-restricted environment:
# Example iptables allowlist for a self-hosted runner (adjust for your registries)
iptables -P OUTPUT DROP
iptables -A OUTPUT -d <rubygems-org-ip> -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -d proxy.golang.org -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -d api.github.com -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -d 0.0.0.0/0 -p udp --dport 53 -j ACCEPT # DNS
5. Generate and diff SBOMs on every build
An SBOM (Software Bill of Materials — a machine-readable inventory of every dependency and its exact version, analogous to a nutrition label for software) generated on each build and diffed against the previous build’s SBOM makes an unexpected package introduction visible immediately.
Syft (open-source, Apache-2.0 license) generates SBOMs for Ruby gems, Go modules, npm, Python, and dozens of other ecosystems:
# Generate an SBOM in SPDX JSON format
syft dir:. -o spdx-json > "sbom-$(git rev-parse HEAD).json"
# Diff two SBOMs to detect new or changed packages
diff \
<(jq -r '.packages[].name' sbom-previous.json | sort) \
<(jq -r '.packages[].name' sbom-current.json | sort)
Integrate SBOM generation into a GitHub Actions workflow:
- name: Generate SBOM
uses: anchore/sbom-action@v0
with:
format: spdx-json
output-file: sbom.json
- name: Upload SBOM artifact
uses: actions/upload-artifact@v4
with:
name: sbom-${{ github.sha }}
path: sbom.json
Store SBOMs as signed build artifacts. During incident response, comparing the SBOM from a suspect build against a known-clean baseline identifies exactly which package version changed and when.
6. Audit gem install hooks in CI
Ruby gem post-install hooks execute arbitrary code during bundle install. Inspect any gem that declares extensions (native C extensions compiled at install time) or includes a Rakefile with custom install tasks — both are common vectors:
# List gems that include extconf.rb (native extension builds — highest risk)
bundle exec gem contents --all 2>/dev/null | grep extconf.rb
# Inspect a specific gem's Rakefile for install tasks
gem contents knot-activesupport-logger 2>/dev/null | xargs grep -l "install" 2>/dev/null
In CI, pass --without development test to bundle install to reduce the install surface. Never run bundle install or go get as root on runner machines.
IOC Reference
| Type | Value | Context | |—|—|—| | Ruby gem | knot-activesupport-logger | Credential harvesting at install | | Ruby gem | knot-devise-jwt-helper | Credential harvesting at install | | Ruby gem | knot-rack-session-store | Credential harvesting at install | | Ruby gem | knot-rails-assets-pipeline | Credential harvesting at install | | Ruby gem | knot-rspec-formatter-json | Credential harvesting at install | | Ruby gem (sleeper) | knot-date-utils-rb | No active payload confirmed yet | | Ruby gem (sleeper) | knot-simple-formatter | No active payload confirmed yet | | Go module | github.com/BufferZoneCorp/go-retryablehttp | Proxy hijack + SSH persistence | | Go module | github.com/BufferZoneCorp/grpc-client | GitHub Actions env tampering | | Go module | github.com/BufferZoneCorp/config-loader | GitHub Actions env tampering | | Go module | github.com/BufferZoneCorp/go-metrics-sdk | Proxy hijack | | Go module | github.com/BufferZoneCorp/go-weather-sdk | Credential harvesting | | Go module | github.com/BufferZoneCorp/go-stdlib-ext | Credential harvesting | | Go module | github.com/BufferZoneCorp/net-helper | SSH persistence | | Go module (sleeper) | github.com/BufferZoneCorp/log-core | No active payload confirmed yet | | Go module (sleeper) | github.com/BufferZoneCorp/go-envconfig | No active payload confirmed yet | | Domain | webhook.site | Exfiltration endpoint for harvested credentials | | File path | ~/.ssh/authorized_keys | SSH persistence target on self-hosted runners | | File path | ~/.aws/credentials | AWS credential theft target | | File path | ~/.gem/credentials | RubyGems API key theft target | | File path | ~/.config/gh/hosts.yml | GitHub CLI OAuth token theft target |
Conclusion
The BufferZoneCorp campaign demonstrates that bundle audit and go mod verify are necessary but not sufficient for modern supply chain defense. Neither tool detects a package that was malicious from publication, or one that received its payload through a legitimate post-adoption version bump. The controls that catch sleeper packages are behavioral: egress restriction on CI runners, SBOM diffing between builds, install-hook auditing, and behavioral analysis tools like Socket. Run the detection checklist above against your current lockfiles and CI history, rotate credentials on any affected systems, then implement the hardening steps to close the gap permanently.
For a parallel Ruby Gem supply chain attack detection approach applied to the npm ecosystem, see our guide on auditing npm packages for DPRK-linked AI-generated backdoors. For the same sleeper-package TTP used against VS Code extensions targeting developer workstations, see GlassWorm VS Code extension supply chain attacks. And if you’re hardening Go and Node.js CI pipelines simultaneously, the SAP npm mini-shai-hulud supply chain analysis covers shared patterns worth reviewing.
For any query contact us at contact@cipherssecurity.com

