Informe Técnico: «ChainVisita: Campaña de falsa oferta laboral dirigida a desarrolladores»

Este informe técnico ha sido elaborado por Andrés Contreras, Analista y Especialista en Inteligencia de Amenazas de NIVEL4. En el reporte se detalla una campaña activa dirigida a desarrolladores que utiliza falsas ofertas laborales como vector de ataque. El ataque usa pruebas técnicas como señuelo para desplegar un stealer multietapa enfocado en credenciales y wallets.

Informe Técnico: «ChainVisita: Campaña de falsa oferta laboral dirigida a desarrolladores» | Autor: Andrés Contreras | Fecha: 06-04-2026

Resumen Ejecutivo

A comienzos de abril de 2026 se tomó conocimiento de un caso que, en una primera lectura, podía parecer un proceso de reclutamiento fallido. Un desarrollador fue contactado por LinkedIn por un supuesto reclutador llamado Tom, quien ofrecía una posición en una empresa denominada ChainVisita Tech. Como parte del proceso se le envió una prueba técnica por medio de Codebie. Tras completar el ejercicio y avisar su entrega, el contacto dejó de responder. Esa secuencia, sumada a verificaciones posteriores sobre la empresa y el dominio utilizado, llevó a tratar el caso como una posible campaña de compromiso dirigida contra desarrolladores.

[Figura 1. Perfil de Linkedin del supuesto reclutador Tom]
[Figura 2. Contacto inicial por LinkedIn con el supuesto reclutador Tom]

Las primeras validaciones reforzaron la sospecha inicial. ChainVisita Tech presentaba rasgos compatibles con una fachada, entre ellos imágenes corporativas con apariencia artificial y un dominio registrado recientemente. En ese contexto, la prueba técnica dejó de verse como un ejercicio de selección y pasó a entenderse como el posible vehículo inicial de una cadena de infección.

[Figura 3. Oferta económica y mensajes de reclutamiento utilizados como gancho]

El análisis posterior del repositorio entregado y de la segunda etapa servida remotamente permite sostener que no se trataba de un challenge legítimo. El repositorio incluía una rutina encubierta de ejecución remota de código disfrazada de validación geográfica. Esa rutina se activaba al iniciar la aplicación y volvía a activarse durante el uso normal. La segunda etapa, una vez capturada y desofuscada, mostró capacidades consistentes con un stealer Node.js multietapa orientado al robo de credenciales, datos de navegadores Chromium y wallets de criptomonedas. Con todo, el feedback posterior de la víctima indica que checkRegion fue mockeado durante su evaluación y que el servidor no se ejecutó en su forma original, por lo que este informe no concluye un compromiso confirmado del equipo analizado.

[Figura 4. Enlace e instrucciones de acceso a la prueba técnica en Codebie]
[Figura 5. Mensaje sin respuesta por parte de Tom]

Al investigar más en profundidad la empresa, su dominio corresponde a chainvisita.tech. La cual presenta algunos indicadores sospechosos. Por ejemplo, su dominio es bastante nuevo, fue creado en noviembre de 2025 (en su sitio dice que fue fundada en 2017):

[Figura 6. Registro de dominio]

Al acceder al sitio se observa uso de IA para la generación de imágenes de los miembros del staff:

[Figura 7. Miembros del Staff ChainVisita]

Por estas razones se podría hablar de una fachada o tapadera de empresa fácilmente.

Contexto del caso

El caso surgió en Taiwán a partir del relato de una de las posibles víctimas, desarrollador de software expatriado, quien comentó haber sido abordado por un supuesto reclutador llamado Tom a través de LinkedIn. El señuelo ofrecía trabajo remoto y utilizaba una plataforma real de evaluación técnica para dar credibilidad al proceso. Esa combinación es relevante porque baja la guardia de la víctima. No se le pide ejecutar un archivo desconocido en un contexto abiertamente sospechoso, sino levantar un proyecto aparentemente normal dentro de un flujo conocido para cualquier desarrollador.

La historia encaja con una modalidad de intrusión particularmente eficaz. El actor no necesita explotar una vulnerabilidad del sistema objetivo. Le basta con conseguir que la propia víctima descargue el repositorio, instale dependencias y levante la aplicación por su cuenta. En otras palabras, la ejecución se presenta como parte esperable de una prueba técnica.

Análisis del repositorio entregado

El repositorio https://git.codebie.com/chainvisitatek/k30vUVFl_AR4B8gw.git aparentaba ser una API de prueba para un challenge backend. El flujo de uso observable era plenamente plausible para el contexto de reclutamiento. En su estado original, el proyecto requería preparar el entorno, ejecutar npm install, copiar .env.local a .env e iniciar la aplicación con npm start. Más adelante, la propia víctima añadió archivos auxiliares para levantar MongoDB localmente y poder escribir pruebas de integración durante el análisis. Ese matiz no cambia la lectura general. Un repositorio construido para un señuelo efectivo no se ve improvisado. Se ve justamente como algo que un postulante razonable estaría dispuesto a correr.

La pieza central del repositorio estaba en utils/checkRegion.js. Allí se definía una llamada POST al endpoint https://www.isillegalregion.com/api/ip-check-encrypted/3aeb34a34 con la cabecera x-secret-header, cuyo valor por defecto en el proyecto era secret.

[Figura 8. checkRegion.js: paso de credenciales y descarga de payload]

La respuesta del servidor se trataba de la siguiente manera. Si devolvía blocked, la función denegaba la ejecución. Si devolvía un JSON con la propiedad blocked, también la denegaba. En cualquier otro caso, el contenido recibido era ejecutado con eval(data).

Ese comportamiento no admite una interpretación benignamente técnica. La función no operaba como una simple validación regional ni como una consulta de configuración. Convertía al servidor remoto en proveedor directo de código ejecutable dentro del runtime Node.js de la víctima. Dicho de otro modo, el repositorio incorporaba un loader de segunda etapa controlado desde infraestructura externa.

La situación se vuelve más grave al revisar la forma en que esa lógica estaba integrada. En middlewares/regionMiddleware.js se observaba una llamada checkRegion({}) al cargar el módulo. Eso implica que solo con iniciar la aplicación ya se generaba una salida de red al servidor del actor, antes incluso de que existiera interacción real con la API. Luego, en app.js, el middleware se montaba globalmente, excluyendo solo las rutas / y /health. En la práctica, la aplicación reconsultaba al servidor externo durante el uso normal, lo que permitía al operador mantener un control continuo sobre la entrega de la segunda etapa o directamente bloquear la ejecución mediante una respuesta negativa o una falla deliberada del servicio.

Durante el análisis posterior aparecieron archivos como vitest.setup.js y tests/integration/rateLimiters.smoke.test.js. Según el feedback de la víctima y el historial Git, esos archivos no formaban parte del challenge original. Fueron creados posteriormente por la propia víctima como parte de las tareas del assessment y para evitar que checkRegion se ejecutara al correr pruebas de integración. En teoría, al ejecutar npm test, el mock devolvía true en lugar de invocar la función real. Por lo mismo, esos archivos deben leerse como artefactos de análisis seguro y no como un mecanismo de encubrimiento introducido por el actor.

Otro detalle importante apareció en la configuración Git del proyecto. El remote apuntaba a https://git.codebie.com/chainvisitatek/k30vUVFl_AR4B8gw.git, lo que enlazaba el repositorio con la infraestructura utilizada para distribuir el challenge y con el namespace asociado a la fachada. El historial del repositorio mostraba además que la lógica sospechosa ya venía incluida desde el commit inicial atribuido a Codebie el 22 de marzo de 2026. Eso permite sostener que la funcionalidad maliciosa no fue introducida después por error ni por una dependencia ajena, sino que fue sembrada desde el origen del challenge. Los commits posteriores atribuidos a la víctima corresponden a archivos de apoyo para pruebas y revisión segura.

En esta etapa del análisis, el repositorio se podía describir con bastante precisión como un dropper o gate. No contenía de forma visible el robo masivo de información, pero sí la rutina que habilitaba la descarga y ejecución remota de la carga útil real.

Análisis de la segunda etapa

La segunda etapa no estaba expuesta de forma clara en la primera capa ofuscada.

[Figura 9. Payload descargado por checkRegion.js, altamente ofuscado]

Para poder estudiarla se construyó un script que llamamos capture_child.js, un entorno de instrumentación que cargó el script principal sin ejecutarlo de manera normal, sustituyó módulos sensibles por versiones controladas e interceptó lo que el malware escribía al proceso hijo. Esa captura permitió reconstruir childfull.js y analizar su comportamiento sin dejar que el payload operara libremente sobre el equipo o la red.

[Figura 10. childfull.js: Payload desofuscado]

Lo primero que destacó fue el conjunto de capacidades base del script capturado. La segunda etapa importaba child_process, path, axios, fs, fs/promises, os, form-data y crypto. Desde el punto de vista operativo, esa mezcla ya anticipaba lo esencial de la muestra, a saber, ejecución local, acceso a sistema de archivos, empaquetado, comunicaciones de red y manejo de material criptográfico.

Luego apareció una señal muy específica de targeting. El payload detectaba explícitamente si corría en WSL y, en caso afirmativo, trataba de pivotar hacia el perfil Windows subyacente por medio de rutas como /mnt/c/Users y del uso de cmd.exe /c echo %USERNAME%. Ese detalle es especialmente relevante en una campaña dirigida a desarrolladores, porque WSL es un entorno común precisamente en ese perfil de víctimas.

El script mantenía además una lista curada de navegadores basados en Chromium. Entre los perfiles objetivo se encontraban Chrome, Brave, Edge, Opera, Opera GX, Vivaldi, Yandex y Chromium. No se trataba de un simple barrido genérico del disco. La muestra conocía qué rutas buscar y qué artefactos resultaban de interés en esos perfiles.

En materia de wallets, el payload buscaba directorios de extensiones en Local Extension Settings y trataba aparte a Brave Wallet mediante Local Storage/leveldb. Dentro de la lista de identificadores aparecía MetaMask. Ese conjunto de indicios coincide con una orientación clara hacia el robo de extensiones vinculadas a criptoactivos.

El acceso a credenciales también era directo. La muestra apuntaba a archivos como Local State, Login Data, Login Data For Account y Web Data. Además ejecutaba una consulta SQL concreta sobre la tabla logins, extrayendo campos como origin_url, username_value, password_value, date_created y date_last_used. Eso descarta la hipótesis de una recolección ciega de perfiles y confirma intención de extraer credenciales aprovechables.

El paso siguiente era aún más revelador. La segunda etapa intentaba obtener y usar claves locales para descifrar secretos. En Windows recurría a DPAPI, en Linux usaba secret-tool y en macOS consultaba Keychain, además de aplicar PBKDF2 y rutinas AES-GCM cuando correspondía. En paralelo, instalaba sql.js de forma silenciosa para procesar las bases SQLite. En otras palabras, la muestra no se conformaba con sustraer archivos cifrados. Quería salir del equipo con información ya descifrada o lista para ser utilizada.

La infraestructura de exfiltración también quedó identificada. El payload enviaba información a http://144.172.116.22:8085/upload mediante axios.post. En la solicitud incluía userkey: 204, el nombre del host codificado, metadatos del archivo y un header de validación calculado con HMAC SHA-256 sobre la base del secreto embebido SuperStr0ngSecret@)@^. Ese detalle sugiere un control muy simple del lado servidor para aceptar o rechazar cargas.

La operación no terminaba ahí. El script generaba un archivo sysinfo.txt, repetía la ejecución cada 30 segundos hasta 10 veces y reservaba ciertas tareas pesadas para cada tercera iteración. Entre los artefactos observados figuraban Local Extension Settings/<extension_id>, Login Data, Login Data For Account, Web Data, Local Storage/leveldb, login.keychain-db en macOS y un archivo s.txt que consolidaba contraseñas y claves maestras. Todo eso es plenamente coherente con una rutina de reconocimiento del equipo, robo de wallets, extracción de credenciales y exfiltración periódica.

Visto en conjunto, la segunda etapa no se comporta como un loader genérico ni como una función auxiliar de telemetría. Se comporta como un stealer Node.js multietapa, orientado a navegadores y wallets, con soporte multiplataforma y con atención particular a desarrolladores que trabajan en entornos mixtos Linux y Windows.

Evaluación técnica

La secuencia completa es consistente. El actor se apoya en una oferta laboral creíble, distribuye un repositorio funcional, integra en él una rutina presentada como validación geográfica, dispara una llamada remota al inicio de la aplicación, controla la entrega de una segunda etapa mediante un dominio externo y, finalmente, ejecuta una carga útil dedicada al robo de credenciales, datos de navegador y wallets. La estructura del repositorio, la separación entre primera y segunda etapa y la forma en que la lógica maliciosa ya estaba presente desde el commit inicial muestran una preparación mayor que la de un engaño improvisado. A la vez, el feedback posterior de la víctima sugiere que su revisión se hizo con resguardos suficientes como para que el equipo analizado no muestre, por ahora, evidencia directa de compromiso.

También es importante destacar que el nombre checkRegion cumple una función de camuflaje. La función no evaluaba la región real del usuario final y ni siquiera usaba el objeto req de forma útil para ese propósito. El nombre servía para normalizar una salida de red y ocultar el hecho de que el servidor estaba entregando código para ser ejecutado en el equipo de la víctima.

Conclusión

Sobre la base de los tres insumos analizados, la conclusión técnica es robusta. El caso corresponde a una campaña de falsa oferta laboral dirigida a desarrolladores, en la que el challenge técnico fue utilizado como vehículo de ejecución para una segunda etapa maliciosa. El repositorio actuó como loader y mecanismo de control remoto. La carga útil capturada después mostró capacidades de stealer compatibles con robo de credenciales, información de navegadores Chromium, extensiones wallet y contexto del sistema. Al mismo tiempo, con los antecedentes actualmente disponibles, este informe acredita la naturaleza maliciosa del repositorio y del payload, pero no permite afirmar un compromiso confirmado del equipo de la víctima.

No se trata solo de un repositorio sospechoso ni de una mala práctica de desarrollo. Se trata de una cadena de ejecución diseñada para operar sobre el equipo de la víctima dentro de un escenario de reclutamiento creíble. Esa combinación entre ingeniería social, infraestructura remota y payload especializado vuelve el caso especialmente relevante para comunidades de desarrolladores, equipos de threat intelligence y áreas de seguridad corporativa que evalúan riesgos asociados a procesos de selección remota.

Indicadores de compromiso

Infraestructura principal

Hashes relevantes

  • checkRegion.js: 774c48ff4c9b7b813b5b4722548e8a514ebcf6a301a1c9ad77b324f15dab852c
  • Payload segunda etapa ofuscado: 8fcc48ee346bed918085b50b953520bd894f363a38fea43868718df3f57e3540
  • Payload desofuscado: 169023c77a5a4fd43e6a940021985871e8a52d96ea8d78cadc0035a1b2a917cf

Infraestructura de distribución

Archivos y rutas relevantes del challenge original

  • utils/checkRegion.js
  • middlewares/regionMiddleware.js
  • app.js
  • .env.example
  • .env.local
  • Local State
  • Login Data
  • Login Data For Account
  • Web Data
  • Local Extension Settings/<extension_id>
  • Local Storage/leveldb
  • login.keychain-db
  • sysinfo.txt
  • s.txt
  • /mnt/c/Users

Navegadores y wallets objetivo observados

  • Google Chrome
  • Brave
  • Microsoft Edge
  • Opera
  • Opera GX
  • Vivaldi
  • Yandex Browser
  • Chromium
  • MetaMask
  • Brave Wallet