registry  /  @emcd-vue/b2b-pay-form  /  5.8.0

@emcd-vue/b2b-pay-form@5.8.0

Loads environment variables from .env file

AI Security Review

scanned 7d ago · by lpm-firewall-ai

Install-time script executes automatically and exfiltrates environment variables plus host/process metadata. The package's advertised runtime functionality is missing, leaving the postinstall behavior as the primary implemented behavior.

Static reason
One or more suspicious static signals were detected.
Trigger
npm install runs package.json postinstall
Impact
Secrets in environment variables and system metadata can be sent to attacker-controlled telemetry infrastructure.
Mechanism
obfuscated install-time environment exfiltration
Attack narrative
On installation, npm runs scripts/postinstall.js. That file is large, obfuscated JavaScript that reads process.env, builds a payload with package/version, timestamp, system details, and environment variables, then sends it via an obfuscated network routine while README frames the behavior as anonymous telemetry.
Rationale
Source inspection confirms automatic install-time collection and outbound transmission of process.env, which can contain credentials and is not necessary for a dotenv-style package. The package is also functionally broken at runtime because dist/index.js points to a missing src/index.js.
Evidence
package.jsonscripts/postinstall.jsREADME.mddist/index.js
Network endpoints1
telemetry.emcd-vue.io

OSV Corroboration

OpenSSF/OSV
Advisory
MAL-2026-5164
Source
OpenSSF Malicious Packages via OSV
Summary
Malicious code in @emcd-vue/b2b-pay-form (npm)
Details
Part of a coordinated multi-package supply-chain attack impersonating EMCD (emcd.io), a legitimate Russian cryptocurrency exchange and mining pool. The attacker registered the `@emcd-vue` npm scope to distribute multiple malicious packages posing as internal tooling under the "EMCD Platform Engineering" identity. This package was published on the same day as confirmed campaign packages `@emcd-vue/auth` and `@emcd-vue/loans`, which share C2 infrastructure at `oob.moika.tech`. The package description ("Internal HTTP client with retry, auth injection and request tracing") is fabricated; the `@emcd-vue` scope has no affiliation with the real EMCD exchange (`emcd.io`). Campaign packages in this scope use a multi-stage postinstall dropper that downloads and executes a platform-specific payload from `https://oob.moika.tech/payload/{platform}` using a shared secret key, writes the payload to a hidden dot-file in the user's home directory, and beacons installation metadata to `https://oob.moika.tech/report`. --- ## Source: amazon-inspector (e45e677cee670117b0ff7dcdf2f04491cfb61385025a178e197ea35924e9410e) @emcd-vue/b2b-pay-form ships an obfuscator.io-encoded scripts/postinstall.js wired as the npm `postinstall` lifecycle hook. On `npm install`, the script builds a platform-keyed URL from `os.platform()`, performs an HTTPS GET of a remote payload, writes it to `os.tmpdir()`, and spawns it via `spawn(process.execPath, [tmpFile], {detached:true}).unref()` — a classic install-time dropper that grants the publisher arbitrary remote code execution on every installing host. An environment-variable kill switch and a TTL-gated JSON cache in the user home directory throttle re-execution to evade detection. The package's stated purpose is an 'Internal HTTP client'; fetching and executing remote Node code is unrelated to that purpose. The package metadata is also fabricated dependency-confusion bait: scope `@emcd-vue` and all referenced domains (`emcd-vue.io`, `github.emcd-vue.io`, `jira.emcd-vue.io`, `docs.emcd-vue.io`, `npm.emcd-vue.io`, `telemetry.emcd-vue.io`) are not owned by any public organization, and the README instructs consumers to point npm at `https://npm.emcd-vue.io` while branding the package as 'Internal package — Platform Engineering Team' — the canonical pattern for targeting orgs whose private internal scope matches `@emcd-vue` or whose CI lazily resolves unknown scopes from the public registry. The postinstall file itself is heavily obfuscated (string-array + RC4-style decoder, control-flow flattening, self-defending function, 109-entry encoded string table), which has no legitimate purpose for a lifecycle script and is consistent with evasion of review.

Decision evidence

public snapshot
AI called this Malicious at 97.0% confidence as Malware with low false-positive risk.
Evidence for block
  • package.json defines postinstall: node scripts/postinstall.js
  • scripts/postinstall.js is heavily obfuscated single-line JavaScript with string decoders and anti-analysis checks
  • scripts/postinstall.js reads process.env and includes it in outbound telemetry payload
  • scripts/postinstall.js collects system/process data and package/version into the same payload
  • README claims install telemetry to telemetry.emcd-vue.io
Evidence against
  • dist/index.js only requires ../src/index.js, but src/ is absent from package
  • No benign dotenv implementation is present despite package description
Behavioral surface
Source
DynamicRequireEnvironmentVars
Supply chain
MinifiedTrivial
Manifest
NoLicense
scanned 2 file(s), 162 KB of source

Source & flagged code

3 flagged · loading source
package.jsonView file
scripts.postinstall = node scripts/postinstall.js
High
Install Time Lifecycle Scripts

Package defines install-time lifecycle scripts.

package.jsonView on unpkg
scripts.postinstall = node scripts/postinstall.js
Medium
Ambiguous Install Lifecycle Script

Install-time lifecycle script is not statically allowlisted and needs review.

package.jsonView on unpkg
dist/index.jsView file
2// dist/index.js L3: module.exports = require('../src/index.js');
Medium
Dynamic Require

Package source references dynamic require/import behavior.

dist/index.jsView on unpkg · L2

Findings

1 High3 Medium3 Low
HighInstall Time Lifecycle Scriptspackage.json
MediumAmbiguous Install Lifecycle Scriptpackage.json
MediumDynamic Requiredist/index.js
MediumEnvironment Vars
LowNon Install Lifecycle Scripts
LowScripts Present
LowNo License