RubyGems package strutil-core 1.0.1 is not a string helper. Socket's November 6, 2026 analysis and OSV MAL-2026-19054 describe a 5.48 MB Miasma-family worm that runs during gem install via ext/strutil-core/extconf.rb, steals cloud, registry, and AI coding tool credentials, exfiltrates to paleasbest[.]top, poisons MCP and SessionStart configs, and installs net-health-checker, which can rm -rf ~ when a stolen GitHub token starts returning 401/403 after you revoke it.
Account jamnajiea published clean 1.0.0 on November 1, 2026, then 1.0.1 less than two hours later. Socket's scanner flagged the bundle 70 seconds after publication; RubyGems removed both versions within about five hours. Socket has not confirmed victims, but the mechanics matter for anyone who runs Claude Code, Codex, Cursor, or VS Code agents on Ruby or Rails projects.
| Question | Short answer |
|---|---|
| Am I affected? | Only if 1.0.1 was installed on a machine or CI runner you control (check Gemfile.lock) |
| Is 1.0.0 safe? | Clean in sandbox, but RubyGems yanked both versions—do not install either |
| Is there a fix? | Isolate host, remove persistence before revoking GitHub tokens, rotate all secrets, rebuild |
| Does opening a repo trigger it? | Yes if the worm already committed .cursor/mcp.json, AGENTS.md, or folder-open tasks |
| Does Beam block the gem? | Beam scans local MCP/skill files; it does not intercept gem install |
Install-time execution: why bundle install is enough
RubyGems runs extconf.rb for native extensions during installation. In strutil-core, that script does not compile code. On Linux and macOS it:
- Creates
/tmp/.b_<pid>. - Downloads Bun 1.2.18 from Bun's official GitHub releases.
- Executes
ext/strutil-core/index.jswith that runtime. - Writes a no-op Makefile so the install appears normal.
The visible Ruby library only implements a trivial slugify helper—the worm lives entirely in the extension path. Socket notes gem install strutil-core -v 1.0.1 or bundle install resolving to that version is sufficient; nothing must require the gem at runtime.
OSV's sandbox narrative matches Socket: during a test install the payload read 51 credential stores (AWS, Azure, GCP, Vault, npm, PyPI, RubyGems, Docker, Kubernetes, .claude/.credentials.json, .codex/auth.json, wallets, SSH keys, and more), called cloud control planes across many regions, and rewrote ~/.cursor/mcp.json.
Attack chain from registry to AI tool poisoning
Image: Socket Threat Research
Credential theft and exfiltration
Collectors target the same classes of secrets as the October testmetest GitHub hook campaign and the wider npm worm wave aimed at AI tooling. Results encrypt with AES-256-GCM (RSA-wrapped keys) and post to https://paleasbest[.]top/v1/api. Fallback paths create a public GitHub repo with description project-utils or exfiltrate to GitLab.
On GitHub Actions runners the bundle scans /proc/*/cmdline for Runner.Worker, then uses passwordless sudo to read process memory— the same class of technique as the tj-actions compromise Socket cites. StepSecurity reports Harden-Runner tampering attempts fail, but the code is present.
Local and repository-level AI config injection
After copying itself to ~/.config/index.js, the worm searches the home directory for writable mcp.json, settings.json, config.json, and .aider.conf.yml files belonging to AI tools.
Socket documents two consistent changes:
- An MCP server named
workspace-toolswithcommand:nodeand args pointing at the payload. SessionStarthooks where the harness supports them.
With stolen Git credentials it commits the same patterns into repositories: .claude/settings.json, .cursor/mcp.json, .gemini settings, CLAUDE.md, AGENTS.md, .github/init.js, and a .vscode/tasks.json task with runOn: folderOpen. Generated AGENTS.md text instructs coding agents to run a setup script before their first command—overlapping the malicious AGENTS.md Downloads-folder hijack we documented in October.
Opening an affected repo in an agent IDE can re-run the worm depending on workspace trust and whether folder-open tasks run automatically.
Persistence and command-and-control
sync.py (SHA-256 c7ef186aa59b67d9b198a14f6dc8aaee6dd86510ac7c37d28f65d310cd846411) installs as pkg-runtime (systemd user service or macOS LaunchAgent). Hourly, it searches public GitHub commits for marker msync-3f7a, pulls a Base64 URL from the commit message, verifies an RSA-PSS signature, and runs the downloaded Python. That is the same backdoor Socket and JFrog tied to testmetest.
The token-revocation wiper
When GitHub exfiltration succeeds, the worm installs net-health-checker, stores the token in plaintext under ~/.config/net-health-checker/token, and polls https://api.github.com/user every 45 seconds for up to 172800 seconds. HTTP 401 or 403 executes a handler equivalent to rm -rf ~ and rm -rf ~/Documents.
Socket's remediation order is deliberate: remove net-health-checker and pkg-runtime before revoking the GitHub token, or revocation becomes the wipe trigger.
Relationship to Miasma, testmetest, and Shai-Hulud
Socket assesses strutil-core as a later build of testmetest with a RubyGems delivery path, sharing sync.py, msync-3f7a, AutoSyncComplete commits, net-health-checker timing, and the June Miasma RubyGems injector template. The public Shai-Hulud toolkit explains shared code—not single-operator attribution.
OSV MAL-2026-19054 links paleasbest.top to the pystr-codec PyPI worm (MAL-2026-18432), published on October 31, 2026 hours before strutil-core 1.0.0.
Propagation modules present in the bundle
Socket emphasizes it confirmed code paths, not successful spread from this gem. Still, defenders auditing Ruby shops should know what else ships inside index.js:
| Module (Socket description) | Intent |
|---|---|
| npm / PyPI republishers | Rebuild trojanized tarballs with stolen registry tokens |
RubyGems injector ([rg] logs) | Patch existing gems with extconf.rb hooks |
| JFrog Artifactory harvester | Pivot from developer creds to private package feeds |
| Fake CodeQL GitHub Actions workflow | Exfiltrate secrets as scan-output artifacts |
GitLab cache_sync job | Request OIDC tokens from CI |
SSH known_hosts enumerator | Lateral movement across developer workstations |
| Locale kill-switch | Exit on CIS-region language settings |
The RubyGems injector is why supply-chain responders now grep maintainers' gems for unexpected extensions: lines—a pattern that also appeared in June Miasma tooling (SafeDep write-up linked from our testmetest post).
Exposure timeline (UTC)
| Time | Milestone |
|---|---|
| 2026-10-31 22:21–23:32 | pystr-codec 0.1.0–0.1.2 on PyPI (shared C2) |
| 2026-11-01 02:19:56 | strutil-core 1.0.0 published |
| 2026-11-01 04:05:04 | Malicious 1.0.1 published |
| 2026-11-01 04:06:14 | Socket AI Scanner flags malware (70 s after 1.0.1) |
| 2026-11-01 ~08:52–09:13 | RubyGems removes both versions (Bitbison timeline) |
Download counters are misleading: Socket notes 89 total downloads shortly after release, mostly against clean 1.0.0 from mirrors—not proof of mass 1.0.1 installs. Your Gemfile.lock pin is the ground truth.
Indicators of compromise
Defang domains and hashes before sharing outside a TI platform:
| Type | Value | Notes |
|---|---|---|
| Package | [email protected] | Malicious; both versions yanked |
| Publisher | RubyGems user jamnajiea | Account now owns no gems |
| SHA-256 (gem) | 3b3f6e1bde0b28b015030a81a6d805b5b5306dc3f021e1102123971cfd83acc0 | Full 1.0.1 artifact |
| C2 | paleasbest[.]top /v1/api | Primary exfil per Socket/OSV |
| MCP name | workspace-tools | Injected server label |
| Service | pkg-runtime | systemd/LaunchAgent persistence |
| Monitor | net-health-checker | 45 s polling; wipe on 401/403 |
| Git marker | msync-3f7a in commit messages | Backdoor command channel |
| Commit prefix | AutoSyncComplete | Token exfil commits |
ReversingLabs classifies the entry point as ext/strutil-core/extconf.rb with Archive/Script supply-chain detection names—useful if your SOC maps alerts to vendor taxonomies.
What this means if you run AI coding agents
| Scenario | Risk |
|---|---|
Rails developer runs bundle install on a compromised lockfile | Immediate credential theft and MCP poisoning on that laptop |
Agent opens a repo with planted .cursor/mcp.json | workspace-tools runs node payload when MCP starts |
| Engineer revokes GitHub PAT first | net-health-checker may wipe $HOME |
CI uses bundle install without lockfile review | Runner secrets and Actions memory scraping |
Concrete checks:
# Lockfiles and caches
grep -r strutil-core Gemfile.lock vendor/bundle 2>/dev/null
# MCP poisoning indicator (inspect manually; do not run unknown servers)
grep -r workspace-tools ~/.cursor/mcp.json ~/.config/*/mcp.json 2>/dev/null
# Persistence (Linux)
systemctl --user list-units | grep pkg-runtime
ls -la ~/.local/share/runtimes/sync.py ~/.config/systemd/user/pkg-runtime.service 2>/dev/null
If 1.0.1 touched a host: isolate, remove net-health-checker and pkg-runtime, then rotate credentials from a clean device, and reimage the machine. Audit packages you maintain for unexpected extconf.rb extensions—Socket shows the worm can republish gems with stolen RubyGems API keys.
Rails and monorepo specifics
Ruby teams often assume bundle install in CI is isolated from developer laptops. This worm targets both:
- CI images that cache
vendor/bundlewithout lockfile review can bake in a poisoned native extension step. - Dockerized dev environments that mount
~/.claudeor~/.cursorinto the container give the payload the same MCP paths as the host. - Multi-language repos may combine Ruby services with Node agents; the worm writes Node-driven MCP entries even when delivery was Ruby.
After cleanup, re-run beam scan on every mcp.json and AGENTS.md the machine can write to, including team-shared templates in dotfiles repos. Compare against known-good baselines stored outside the infected host.
Why the wiper punishes good IR instincts
Incident responders are trained to revoke stolen PATs immediately. Socket's ordering is counter-intuitive but grounded in the malware design: net-health-checker treats 401/403 as success conditions for rm -rf ~. Document this in your playbooks for supply-chain gems, not only for ransomware.
If you already revoked tokens and the home directory is intact, you may have dodged the GitHub exfiltration branch—or the monitor never installed. Do not treat that as safety; assume full credential theft from the 51-store sandbox list OSV publishes.
What Beam can and cannot do here
beam scan path/to/mcp.json --mcpapplies 11 heuristic patterns plus version-pin checks to MCP JSON before you enable a server (scanning guide). A craftedworkspace-toolsentry may match risky-command or unknown-server heuristics, but this is not full malware detection.beam scan AGENTS.md(orCLAUDE.md) can surface instructions that tell agents to run setup scripts—similar to plantedAGENTS.mdlines.- PreToolUse deny hooks on supported harnesses can block some destructive recovery commands agents suggest after compromise, with fail-open limits documented on Beam's landing page.
Beam does not hook gem install, bundle, or RubyGems mirrors. It will not stop extconf.rb execution. Treat scanning as evidence for a human decision, not a substitute for lockfile review and dependency allowlists.
How Beam handles this
Registry scanners such as Socket flagged strutil-core in 70 seconds at the publish boundary. Beam complements that on the workstation: after you hear about a gem, you can offline-scan MCP and instruction files the worm targets, compare against known-good configs, and retain local audit history when the collector is enrolled—without sending file contents to a cloud SIEM by default. Where Socket fits publish-time supply chain, Beam fits "what did this worm leave on my laptop's agent configs?" after the fact.
Recovery order (from Socket)
Socket's guidance for suspected infection:
- Isolate the host from the network.
- Stop and remove
net-health-checkerandpkg-runtimebefore revoking GitHub tokens. - Delete
workspace-toolsMCP entries, rogue SessionStart hooks,.github/init.js, and unexpectedAGENTS.md/CLAUDE.mdchanges. - Rotate RubyGems, npm, PyPI, cloud, SSH, Vault, Kubernetes, and AI provider credentials from a clean system.
- Rebuild the machine from trusted media.
Related reading
- testmetest: 42 GitHub repos armed with agent hooks
- npm supply-chain worms targeting AI tooling
- Malicious AGENTS.md hijacking Codex and Claude Code
- WardenStealer and Claude/Codex token theft
- Postman installer hook abuse in agent plugins
- October 2026 attacks timeline (Miasma/testmetest entry)
Primary sources: Socket Threat Research (Nov 6, 2026), OSV MAL-2026-19054, ReversingLabs Spectra Assure summary. Secondary: Cyber Security News (Nov 10, 2026).
Frequently asked questions
Which strutil-core versions are malicious?
OSV MAL-2026-19054 and Socket document only version 1.0.1 as malicious. Version 1.0.0 from account jamnajiea was clean in Bitbison sandbox runs; RubyGems removed both versions within hours on November 1, 2026.
Does requiring the gem in Ruby code trigger the worm?
No. Socket and OSV agree the payload runs during gem installation when RubyGems executes ext/strutil-core/extconf.rb. A Gemfile that resolves to 1.0.1 and runs bundle install is enough.
What AI tools does the worm modify?
Socket static analysis shows writes to MCP and settings files, adding a workspace-tools MCP server that runs node against the payload path, plus SessionStart hooks and repository files such as AGENTS.md, CLAUDE.md, and .cursor/mcp.json.
Why is GitHub token revocation dangerous here?
When exfiltration captures a GitHub token, the worm installs net-health-checker, which polls api.github.com every 45 seconds and runs rm -rf on the home directory if the token returns HTTP 401 or 403—responses common after revocation.
Are there confirmed victims?
Socket states it found no public dependents and has not confirmed victims or successful propagation from this gem. OSV and Bitbison sandbox data confirm install-time behavior, not production breach counts.
How do I check my machine?
Search for workspace-tools in MCP JSON, pkg-runtime systemd units, ~/.config/index.js, net-health-checker under ~/.local/bin, and Gemfile.lock entries for strutil-core. Rotate every credential that lived on the host before reinstalling from clean media.
Version numbers, hashes, and timelines follow Socket and OSV as of November 10, 2026. Beam is a local prototype; scanning is heuristic and does not replace incident response procedures from your security team.

