TL, RD
Un único operador de npm pasou seis semanas publicando paquetes de "utilidades" de TypeScript falsos como ts-form-utils, ts-project-linte ts-enum-helper.
Mentres que os paquetes expoñen pequenos axudantes de validación de aspecto lexítimo, a carga útil real execútase na instalación ou na primeira solicitude e realiza a identificación dixital do host, o descubrimento de organizacións en GitHub, a clonación de repositorios e a exfiltración de código fonte.
O malware ten como obxectivo específico organizacións de GitHub de alto valor, incluíndo varias Shopify repositorios e, a continuación, arquiva e exfiltra as árbores fonte accesibles a un punto final de recollida centralizado.
Como parte do fluxo de traballo de compromiso, a carga útil commitficheiro sa de volta aos repositorios das vítimas mentres se fan pasar pola identidade de codificación autónoma de Google google-labs-jules[bot].
Fixemos un seguimento da campaña, chamada JulesJacker — en varios ámbitos de publicación e polo menos cinco xeracións de cargas útiles, incluíndo variantes cifradas e compatibles con sandbox.
A variante máis recente ten como obxectivo específico a infraestrutura de análise de software malicioso: actívase só dentro dos entornos de análise, rouba tokens de contas de servizo de metadatos na nube e sonda os planos de control de Kubernetes e os depósitos de almacenamento na nube.
O IOC principal compartido en todas as xeracións de carga útil é o punto final da colección aaronstack[.]com/jules-collect.
Gravidade: crítica.
O ataque: como funciona
Todos os paquetes de JulesJacker seguen o mesmo modelo. O paquete.json anuncia un asistente de TypeScript benigno cunha licenza MIT e sen repositorio de código fonte vinculado. O índice.js exporta un puñado de funcións reais e funcionais (expresións regulares de correo electrónico, mapas de enumeración, táboas de regras de lint) para que un desenvolvedor que realmente importe o paquete vexa un comportamento plausible. A malicia reside noutro lugar: nun postinstalación gancho ou nun bloque na parte inferior de índice.js que se executa no momento en que se require o módulo.
As cargas útiles evolucionaron a través de etapas internas claramente numeradas (o operador etiqueta os seus propios eventos de telemetría sc1-, sc3-, sc4-, etc.), e observar esa evolución é a forma máis clara de entender a campaña.
Xeración 1–2: recoñecemento e roubo de git-config
Os primeiros paquetes eran roubadores de información sinxelos. Na instalación, recollían variables de ambiente, o ficheiro hosts da CLI de GitHub e a configuración global de git (configuración de git –lista global, git remote -v), despois enviou o paquete ao punto final da colección. Isto estableceu a sinatura do operador: unha historia de portada de "utilidades de validación de formularios TypeScript", unha baliza de saída a un único dominio e unha preferencia polas credenciais de desenvolvedor en lugar dos datos do consumidor.
Xeración 3: sondas de escape do hipervisor e do kernel
Unha versión a metade da campaña involucrouse con forza nos ataques de infraestrutura. En lugar de roubar a configuración, executou unha proba de recoñecemento do arnés. AF_VSOCK sockets, rexións MMIO de Virtio, /desenvolvemento/meme indicadores de endurecemento do núcleo, e mesmo intentos de fallos do núcleo desencadeados por sysrq: comportamento asociado a intentos de saír dunha máquina virtual ou contedor. As etiquetas de telemetría (s0-vmm-recon, s1-vmm-vsock-fuzz, s2-vmm-mmio, sonda-do-núcleo-s3) fixo explícita a intención. Esta variante estaba claramente dirixida a entornos de probas na nube e de execución sen servidor — o tipo de máquina virtual efémera que constrúe e proba código non fiable.
Xeración 3 (SC3): o verme de escritura entre repositorios
O centro de gravidade da campaña converteuse nun ladrón de repositorios que se autopropaga. Na instalación, a carga útil executa unha secuencia cronometrada de cinco etapas:
- Stage 0 (~100 ms): pegada dixital do host: nome do host, información do usuario, identidade de git.
- Stage 1 (~3 s): determinar a que organización pertence a vítima inspeccionando git remote -v, despois busca un código fixo ORG_CONFIG acceso a táboas e repositorios de proba con git ls-remote — enrutado a través dun proxy SSRF controlado por un atacante en http://git@192.168.0.1:8080.
- Stage 2 (~10 segundos): clon git cada repositorio accesible na lista de destino, comprimir con tarball e gzip a árbore, codificála en base64 e exfiltrala por fragmentos.
- Stage 3 (~45 s): a "proba de acceso": clonar un repositorio escribible, eliminar un ficheiro chamado SECURITY-POC.md e commit co autor definido en google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> e a tarefa da mensaxe: actualizar a caché de dependencias e despois enviar á rama principal da vítima.
A lista de obxectivos codificada non é xenérica. Enumera máis de trinta Shopify repositorios por nome — Shopify/shopify, Shopify/identidade, Shopify/facturación, Shopify/cofre, Shopify/segredos, Shopify/infraestrutura, Shopify/.github, e moitos máis, xunto cunha organización de probas, AaronStackBarnes, que o operador parece controlar e usa como destino de escritura.
Xeración 4 (SC4): cifrada e protexida
A variante máis recente orientada aos desenvolvedores engade dúas capas de evasión sobre o verme SC3.
En primeiro lugar, a carga útil xa non se envía como texto plano. A lóxica real reside nun blob cifrado con AES-256-CBC, lib/.perf.dat, co IV nos seus primeiros dezaseis bytes. O cargador en índice.js reconstrúe a clave de descifrado a partir de fragmentos de cadeas concatenados, descifra o blob e execútao con nova función()Mesmo os nomes dos módulos están divididos para evitar os escáneres estáticos — require('crypt' + 'o'), require('f' + 's').
En segundo lugar, está controlado polo host. Unha variante só descifra e se executa cando nome do servidor do sistema operativo () é igual caixa de desenvolvemento or ubuntu-fc-uvm (unha microVM predeterminada de Firecracker) ou contén a subcadea caixa de desenvolvementoOutra porta pon en evidencia a presenza dun .xules/ directorio de traballo:
Noutras palabras, a carga útil SC4 está deseñada para permanecer inactiva no portátil dun desenvolvedor común e espertar só dentro do axente de IA automatizado e ambientes sandbox o operador realmente quere chegar a un acordo.
Acendindo o laboratorio: a variante de análise-infraestrutura
O paquete máis novedoso da campaña, axudante de ts-enum, non ataca en absoluto aos desenvolvedores nin a Shopify. O seu postinstalación.sh ábrese cunha porta que delata o xogo:
O script non fai nada a menos que se defina unha variable de ambiente específica para unha plataforma de análise de software malicioso. Cando se define, a carga útil sabe que se está a executar dentro da zona de probas que existe para detonar e estudar paquetes exactamente como este, e contraataca.
Primeiro extrae o token de OAuth da conta de servizo de GCP do servidor de metadatos da instancia e o exfiltra. Despois, usando ese token, varrer o Plano de control de Kubernetes accesible en kubernetes.predeterminado.svc:
- enumera ClusterRoleBindings, ClusterRoles e Nodes;
- sonda pods, segredos e mapas de configuración en sistema kube, defecto, kube-público, aluguer de nodos de kubee o espazo de nomes de análise;
- emite chamadas a SelfSubjectAccessReview para mapear exactamente o que se lle permite facer á identidade roubada.
Finalmente, forza os nomes dos depósitos de Google Cloud Storage creados a partir dun ID de proxecto GCP codificado (asinante-raro-437603-p9) e o número do proxecto, adiviñando combinacións como *-builds, *-artefactos, e varios malélisis- prefixos (resultados da malélisis, paquetes de malysis, exploracións de malálise). Cada código e corpo de resposta rexístrase e envíase de volta ao mesmo Jules-collect punto final.
Este é o caso pouco común dunha carga útil da cadea de subministración construída especificamente para atacar a propia infraestrutura dos defensores. A historia de portada de toda a campaña (fragmentos da cal aparecen dentro das cargas útiles como comentarios que enmarcan o comportamento como unha "proba de concepto de investigación de seguridade... escritura entre repositorios a través dun token proxy git con alcance excesivo") é a mesma autoxustificación, tanto se o obxectivo en tempo de execución é un monorepo de Shopify como o servidor de metadatos do clúster de análise.
Cronoloxía e migración do alcance
JulesJacker non é unha operación puntual. É unha operación sostida que sobreviviu a unha eliminación do rexistro simplemente cambiando o seu nome.
| Cando | evento |
|---|---|
| Mediados de abril de 2026 | Os primeiros paquetes aparecen baixo o ámbito orixinal do publicador: fachada de TS-utility, ambiente e exfiltración de git-config. |
| Principios de maio de 2026 | Publicouse a variante de recoñecemento de hipervisor e kernel-escape. |
| Mediados ou finais de maio de 2026 | O verme de escritura entre repositorios SC3 aparece xunto con cargas útiles dirixidas a Shopify e google-labs-jules[bot] suplantación de identidade. SC4 introduce cargadores cifrados con AES e controlados por host. |
| Finais de maio de 2026 | npm elimina o ámbito orixinal do publicador; os nomes dos paquetes resólvense en marcadores de posición baleiros que conteñen seguridade. |
| Mesma semana | O operador migra a un ámbito case idéntico e volve publicar o verme, incluída a variante de infraestrutura de análise. |
A migración é a parte coa que os defensores deberían conformarse. A eliminación do primeiro telescopio non puxo fin á campaña nin sequera a freou. O operador xa puxera en marcha un telescopio paralelo cuxo nome difire do orixinal nun só carácter e continuou a publicar na mesma semana. No momento de escribir isto, o novo telescopio... ts-form-utils (versións 1.0.0 a 1.1.0), as súas proxecto-lint (1.0.0 e 1.1.0) e a versión independente axudante de ts-enum (1.0.0) seguen sendo instalables.
Indicadores de compromiso
Todos os indicadores seguintes foron confirmados coa orixe do paquete.
| tipo | Indicador | Notas |
|---|---|---|
| Rede (C2) | aaronstack[.]com/jules-collect | Punto final de colección único en cada xeración; recibe telemetría JSON e fragmentos de ficheiro tar do repositorio base64-gzip. |
| Rede (proxy SSRF) | http://git@192.168.0.1:8080 | Parte dianteira dun token de proxy git con ámbito excesivo usado para chegar aos repositorios da organización de destino. |
| Rede (nube) | metadata.google.internal/computeMetadata/v1kubernetes.default.svcstorage.googleapis.com/storage/v1/b | Usado só pola variante de infraestrutura de análise para o roubo de tokens e o recoñecemento do plano de control de Kubernetes. |
| Identidade | google-labs-jules[bot]161369871+google-labs-jules[bot]@users.noreply.github.com | Forxado commit identidade do autor introducida nas ramas principais das vítimas. |
| Arquivo | lib/.perf.dat | Blob de carga útil cifrado con AES-256-CBC; IV almacenado nos primeiros 16 bytes e clave reconstruída dinamicamente en index.js. |
| Arquivo | SECURITY-POC.md | Deixou caer e commitde volta aos repositorios de vítimas coa mensaxe chore: update dependency cache. |
| Arquivo | scripts/postinstall.sh | Pechado $MALYSIS_ANALYSIS_ID; identifica a variante de análise-infraestrutura-orientación. |
| Comportamental | os.hostname() comprobacións para devbox / ubuntu-fc-uvm | Control de acceso ao entorno de sandbox e axente de IA antes do descifrado e a execución da carga útil. |
| Comportamental | .jules/ /app/.jules lecturas de directorio | Segmentación explícita de entornos de espazo de traballo de axentes de IA. |
| Comportamental | sc1-, sc3-, sc4-, s0-vmm-recon | Etiquetas de etapa de telemetría definidas polo operador útiles para a detección e a busca. |
| Obxectivo na nube | rare-signer-437603-p9malysis-* adiviñas de baldes | Identificadores de proxectos de GCP codificados de forma fixa e patróns de enumeración de depósitos de almacenamento integrados na variante de infraestrutura de análise. |
| Forma do paquete | Fachada de paquetes TS-utility sen campo de repositorio | Modelo de campaña consistente: paquetes de utilidades TypeScript falsos con cargas maliciosas integradas en postinstall hooks ou engadido a index.js. |




