Skip to main content
Advisory ID: JOYFILL-SA-2026-001 · Published: July 29, 2026 · Last updated: August 2, 2026 (Revision 2) Status: Investigation ongoing · Severity: Critical for affected installs
Update, August 2, 2026 — npm verification complete; scope expanded to cover source repositories. We have finished verifying our published npm packages and found no additional affected versions. We have separately identified the malicious code in three public Joyfill GitHub repositories. If you cloned any Joyfill repository directly from GitHub, see Cloned GitHub repositories.

Start here: are you affected?

There are two separate ways to have been exposed. Run both checks — they are independent, and a clean result on one says nothing about the other.

Check 1 — did you install an affected npm version?

Six beta releases were published on July 28, 2026 containing malicious code. All carry the 2773 prerelease build marker, and no release without that marker has been found to contain the implant. All six have been removed from npm. Stable releases are not currently believed to be affected. Run this from the root of any project that uses @joyfill packages — the directory containing your package.json. In a monorepo, run it once at the repository root; the search recurses into workspace lockfiles beneath it.
On Windows, from the same directory (PowerShell):
To see what actually resolved rather than what the lockfile records, run this from a directory where node_modules is installed:
Repeat for every repository or checkout that depends on @joyfill. A check on your own machine does not cover lockfiles that exist only in CI caches, container images, or a colleague’s environment. If this finds anything, the affected versions execute code at import time, so an install alone is enough — go to If you installed or imported an affected version.

Check 2 — did you clone a Joyfill repository from GitHub?

Separately from npm, three public Joyfill repositories on GitHub contained the same malicious code. This is a distinct exposure path: it affects anyone who cloned those repositories directly, whether or not they ever installed a @joyfill package. If you cloned, pulled, or fetched any Joyfill repository from GitHub between May 25, 2026 and August 1, 2026 — including an older clone you updated during that window — go to Cloned GitHub repositories.

Both checks clean?

You are not affected by this advisory and can stop after the two items below. Do not install @joyfill/layouts or @joyfill/components from the npm beta dist-tag until we confirm remediation is complete, since that tag can resolve to a prerelease build on your next install. Pin to an exact version that is not a 2773 build. Whatever version you are on today is fine, as long as it does not carry the 2773 marker. Pin that exact version rather than a range:
Your package.json should read "@joyfill/components": "4.0.0-rc24" — an exact version with no ^ or ~ in front of it. This advisory is not a reason to upgrade. If you are running an older release, stay on it. Older releases predate this entirely. Upgrading across a major version to respond to this incident would take on breakage risk you do not need. If you want a version that has been independently confirmed clean by the analyses linked below, those are @joyfill/layouts@0.1.1 and @joyfill/components@4.0.0-rc24. Where the range prefix actually matters. If your components dependency is written as ^4.0.0-rc24 or ~4.0.0-rc24, change it to the exact version. Because 4.0.0-rc24 is itself a prerelease, those ranges do match the compromised 2773 builds — under semver they sort above 4.0.0-rc24, so they are valid upgrades within the range, and your next install could pull one. Any other range — ^3.x, ^2.x, anything anchored on a stable version, or any range on @joyfill/layouts — cannot reach a 2773 build. Pinning exactly is still good practice, but there is no urgency for you here. If you want to be extra careful, re-run Check 1 after your next npm install, in case a transitive update pulls a different version.

If you installed or imported an affected version

One thing to know before you start: this implant runs when Node.js loads the module, not when npm installs it. npm install --ignore-scripts does not prevent it. Any process that imported the package — test runner, bundler, dev server, SSR, CI job — is enough to have triggered it. Because the payload can execute arbitrary commands, treat the machine as compromised rather than merely exposed. The clean remediation is to reimage it. Work through these in order, and do steps 2 onward from a different, known-clean machine.
  1. Take the affected machine offline. Preserve logs, shell history, and dependency artifacts before cleaning anything. If forensics may be needed later, image the disk first.
  2. Rotate credentials reachable from that machine or process — npm tokens, cloud keys, CI secrets, SSH keys, GitHub personal access tokens, database credentials, local .env contents.
  3. Rotate browser-stored credentials and sessions on that machine: saved passwords, cookies, and any password-manager or wallet extension data.
  4. Reimage the machine. We recommend a full reimage rather than targeted cleanup. The recovered payload injects self-reloading code into local developer tooling — editors, desktop applications, and the global npm CLI — so it can survive both removal of the package and rotation of credentials, and steal the new credentials in turn. There is also no reliable way to confirm from the outside that a given machine is clean: the payload is fetched at runtime, so machines may have received different code, and the credential-stealing branch can run and exit without leaving anything behind to find. If reimaging is genuinely not possible, the linked third-party analyses below list the specific injection targets and file markers needed for manual cleanup. Treat that as the weaker option, and contact us if you want help working through it.
  5. Purge the package everywhere it persists. Delete node_modules and reinstall from a corrected lockfile so the compromised bundle is gone from disk, then clear it from local and CI caches, internal registry mirrors, container build layers, and deployment artifacts. Block the affected versions in your registry proxy or dependency policy tooling so automated resolution can’t restore them.
  6. Work out how far it reached. Reimaging fixes one machine. It does not tell you whether other machines imported the same package, whether the implant ever connected, or how long it was live — and wiping the disk destroys the local evidence that would. Network and CI logs survive the rebuild, so they are your best remaining source. Look for detached node processes and outbound blockchain RPC traffic from build agents or developer workstations; blockchain RPC calls from a CI runner are a strong signal on their own. Indicators of compromise are in the third-party analyses linked below.
If you need help assessing exposure, contact us directly — see Contact.

Cloned GitHub repositories

Separately from npm, we identified malicious code in project files in three public Joyfill repositories on GitHub. This section is about environments that cloned these repositories directly from GitHub. These repositories were made inaccessible on August 1, 2026. They can no longer be cloned or pulled from. This section applies to any clone that was created, pulled, or fetched between May 25, 2026 and August 1, 2026 — including a clone made years earlier that was updated during that window. If you cloned any of these, inspect the file listed above in your clone. The code is hidden behind a long run of whitespace padding on an existing line, so it will not be visible during a normal read. Two reliable tells: an unexpected jump in file size, and any line longer than about 2,000 characters.
Finding the code in a clone does not mean your machine was affected. The code is inert on disk and runs only when the file it sits in is executed or imported. If you cloned a repository and never built, tested, or ran anything from it, delete the clone and there is nothing further to do. The threshold is lower than it sounds, though. For the two configuration files, running any build from the project is enough. For layout-engine, importing the module is enough — a dev server, a test run, or a bundling step will do it, without anyone deliberately running that file. If you built, tested, or ran anything from one of these clones, follow the steps in If you installed or imported an affected version.

If you publish npm packages

Read this even if you have already cleaned the affected machine. The payload patches the global npm CLI. Once that file is modified, every subsequent npm command on that machine re-executes the loader — including npm publish. Any package built or published from an affected machine may therefore carry the implant onward to your own users, independently of anything to do with @joyfill. If you maintain packages and an affected machine was used to build or publish them:
  1. Treat any release published from that machine since it was affected as suspect, and verify the published tarballs rather than the source they were built from. The implant is injected into built bundles, so a clean repository does not mean a clean artifact.
  2. Rotate your npm publishing tokens from a clean machine before publishing anything else.
  3. Publish subsequent releases from CI with provenance rather than from a workstation.
We recognise how much work that is. We would rather flag it than leave anyone to discover it downstream.

What the malicious code does

For readers who need to scope their response. Two teams independently identified and analyzed this compromise, and we are grateful for their work. Both write-ups are recommended reading and together carry the full set of indicators of compromise: The implant retrieves its payload dynamically at runtime, which means its behavior could change without a new package being published. The recovered payloads are capable of:
  • Establishing an interactive remote-control channel to attacker infrastructure
  • Executing arbitrary JavaScript and shell commands on the host
  • Collecting host and environment information, and reading clipboard contents
  • Uploading files from the machine
  • Harvesting browser-stored credentials, wallet and password-manager extension data, Git credentials, GitHub CLI configuration, and editor storage
  • Persisting by modifying local developer tooling, including the global npm CLI
Socket links the implant to the DEV#POPPER / Contagious Interview malware family. As of this publication, we have found no indication that Joyfill’s hosted platform, production infrastructure, or customer data stored in Joyfill are affected. That review is still in progress, so we are describing this as a preliminary assessment rather than a final finding, and we will update this page if it changes. The risk we have identified from this incident is to developer and build machines that imported the affected packages.

Investigation status

Our investigation has made substantial progress. We have established how the malicious code reached our published packages, and we have already acted on what we found — the remediation work described below reflects specific findings rather than precautionary guesswork. When our investigation is complete, we will publish a full technical post-mortem covering root cause, timeline, and remediation, and we will link it from this page. If you have a specific question in the meantime — as a customer, a downstream maintainer, or a researcher — please contact us directly rather than inferring from what is not yet published. See Contact.

Scope verification

Verification complete for npm. We have manually inspected every version we published to npm over the past 12 months (over 800+ versions), along with the dependency packages we publish and manage. We did not find the known malicious code in any of them. The affected versions are the beta releases listed above, and no others at this time. This closes the verification we committed to when this advisory was first published. Our npm packages outside those beta releases are clean from the known malicious code.

What we are changing

  • Removing the code from all affected branches and re-verifying full repository history
  • Auditing and restricting repository access across the organization
  • Rotating all publishing tokens and third-party integration credentials
  • Moving publishing off individual machines onto CI with npm trusted publishing, so future releases carry verifiable provenance
  • Adding automated checks for code introduced outside of normal review, and requiring Joyfill maintainer review on all merges

Contact

For anything related to this advisory — security questions, security reports, or help assessing your own exposure — contact support@joyfill.io. We respond within one business day. If you believe you were affected and want help working through the steps above, reach out and we will work through it with you.

Changelog

  • 2026-08-02 (Revision 2) — Completed verification of all npm versions published in the past 12 months; no additional affected versions found. Added a section covering three public GitHub repositories found to contain the same code, none of which were published to npm. Those repositories were made inaccessible on August 1, 2026.
  • 2026-07-29 (Revision 1) — Initial publication.