@marketfront: 25 npm Packages Reuse a Known Lure

9 min read

Table of Contents

TL;DR

On July 1, 2026, the npm user marketfront batch-published 25 packages into the @marketfront scope within a roughly three-minute window, all at version 7.0.0. Every package carries a postinstall credential harvester and an identical README line: Internal package — Platform Engineering Team. That line is not a signature of one account. It is a reusable dependency confusion lure template SafeDep has tracked across a series of disposable npm accounts (mr.4nd3r50n, pik-libs, t-in-one, emcd-vue), documented in the oob.moika.tech campaign report, and marketfront is the latest to reuse it. The marker repeats across every wave, but the payload behind it does not. It has shifted from a broad process.env beacon into a targeted credential-file harvester with an RC4-hidden command-and-control host.

25 npm packages compromised in this campaign.
This campaign

Impact:

  • On install, the payload reads roughly 20 credential and secret files including ~/.ssh, ~/.aws/credentials, ~/.kube/config, ~/.docker/config.json, ~/.npmrc, ~/.netrc, ~/.pgpass, ~/.git-credentials, ~/.env, and shell history, then exfiltrates them.
  • Any developer workstation or CI runner that resolves an internal-looking @marketfront name from the public registry executes the harvester before control returns to the build.
  • The 25 packages use e-commerce and marketing frontend component names as cover, which points at a specific organization’s internal package namespace rather than a generic squat.

Indicators of Compromise:

  • npm scope: @marketfront, 25 packages at version 7.0.0, npm user marketfront ([email protected]), published 2026-07-01
  • README marker: Internal package — Platform Engineering Team
  • package.json author: <Scope> Platform Engineering <platform@<scope>.io>
  • Install hook: postinstall: node scripts/postinstall.js, obfuscator.io-style single-line payload
  • Exfiltration: gzip-compressed HTTPS POST with an X-Secret header to the path /api/v1/events, plus a DNS resolver beacon
  • The command-and-control host sits behind an RC4 plus XOR layer and was not statically resolved. No C2 domain is published here because none was recovered without executing the payload.

The reused marker

SafeDep first documented this lure template in the oob.moika.tech campaign, which tied together four npm accounts (mr.4nd3r50n, pik-libs, t-in-one, emcd-vue) publishing across scopes such as @cloudplatform-single-spa, @t-in-one, and @emcd-vue. Microsoft and Sonatype reported overlapping waves of the same dependency-confusion activity, describing the same author strings ending in “Platform Engineering” and the same X-Secret header convention.

The @marketfront scope, published July 1, is the next rotation. The registry has already pulled the packages, so their pages return 404. The lure template survives in a place that is harder to take down: the still-live @emcd-vue scope, the direct predecessor, republished with fresh version numbers (@emcd-vue/[email protected], @emcd-vue/[email protected], @emcd-vue/[email protected]). The @emcd-vue artifacts are byte-for-byte instances of the same template, so the metadata and payload snippets below are pulled from that live source and cross-referenced against SafeDep’s static analysis of the @marketfront batch.

The @marketfront wave

The 25 package names read like the internal frontend modules of an online marketplace: @marketfront/header, @marketfront/footer, @marketfront/navbar, @marketfront/bannerpopup, @marketfront/customdealsfeed, @marketfront/fashiononboardingpopup, @marketfront/livestreampreviewpopup, @marketfront/designsystemdevtool. This is the same targeting logic as the earlier waves. The names mirror what a specific organization’s private package registry would contain, so a build that is missing the private version resolves the public malicious one instead.

SafeDep’s analysis confirmed that the decoded payload is identical across the sampled packages in the batch, consistent with a scripted publish rather than per-package development. The scope was created on the same day at 2026-07-01T22:59:33Z and populated in one burst.

The metadata fingerprint

The lure lives entirely in the package metadata and README. Here is the manifest from the live predecessor, unchanged in structure from what SafeDep analyzed in @marketfront:

// @emcd-vue/[email protected] — package/package.json
{
"name": "@emcd-vue/auth",
"version": "7.1.0",
"description": "Internal structured logger with log levels, context and remote drain support",
"main": "dist/index.js",
"scripts": {
"build": "tsc --noEmit || true",
"test": "node test/index.test.js",
"postinstall": "node scripts/postinstall.js",
"prepublishOnly": "echo 'Building...'"
},
"author": "Emcd-Vue Platform Engineering <[email protected]>",
"license": "UNLICENSED",
"private": false,
"repository": { "type": "git", "url": "git+https://github.emcd-vue.io/platform/auth.git" },
"bugs": { "url": "https://jira.emcd-vue.io/projects/PLATFORM" },
"homepage": "https://docs.emcd-vue.io/platform/auth"
}

The author, repository.url, bugs.url, and homepage fields are parameterized by scope name. Swap emcd-vue for marketfront and the fields regenerate. The description strings are drawn from a fixed pool that the earlier waves used verbatim, for example Internal structured logger with log levels, context and remote drain support and Internal configuration loader with env, vault and remote config support.

The README does the social engineering:

# @emcd-vue/auth — package/README.md
> **Internal package** — Platform Engineering Team
> Docs: https://docs.emcd-vue.io/platform/auth
> Issues: https://jira.emcd-vue.io/projects/PLATFORM
## Installation
# Make sure .npmrc points to the internal registry:
# registry=https://npm.emcd-vue.io
## Telemetry
On install, this package sends anonymous telemetry to telemetry.emcd-vue.io
for environment compatibility monitoring.

The .npmrc comment and the telemetry paragraph do the social engineering. The .npmrc comment tells the developer to point at a private registry, which is the correct security practice, so the package reads as a legitimate internal artifact that is already published where it should be. The telemetry paragraph pre-explains the outbound network request an alert reviewer might notice during install, framing exfiltration as authorized monitoring. The decoy domains (docs.emcd-vue.io, jira.emcd-vue.io, npm.emcd-vue.io) do not resolve. They exist only to make the metadata look like real internal tooling.

The shipped dist/index.js is a stub. It re-exports a source file the package does not include:

// @emcd-vue/[email protected] — package/dist/index.js
'use strict';
module.exports = require('../src/index.js');

Requiring the package at runtime would throw, because ../src/index.js is not in the tarball. The library is a decoy, and the payload runs entirely from the install hook.

The payload

Every active package declares the payload through the postinstall lifecycle hook shown in the manifest above. npm runs scripts/postinstall.js immediately after the package is placed on disk, before the developer or CI runner regains control.

The script is a single line of roughly 160 KB of obfuscator.io-style output. It opens with the standard string-table rotation preamble and a custom base64 alphabet:

// @emcd-vue/[email protected] — package/scripts/postinstall.js (excerpt)
'use strict';(function(a,b){var a0b3={a:0x58,b:0xae,c:'\x28\x66\x31\x77',...};
...while(!![]){try{var d=-parseInt(Y(0x135,'\x38\x35\x5a\x46'))/... if(d===b)break;
else c['push'](c['shift']());}catch(e){c['push'](c['shift']());}}}(a0d,-0x22f4b+...));

The alphabet embedded in the string decoder is abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRST UVWXYZ0123456789+/=, a lowercase-first reordering of standard base64. Statically base64-decoding the string table with that alphabet recovers primitives such as charCodeAt and fromCharCode, which confirms the runtime char-code string building, but the sensitive strings do not fall out. They sit behind a second RC4 layer keyed per string, which is why the credential-file paths and the exfiltration endpoint are not visible to a plain string dump. This matches the obfuscation class SafeDep flagged on the @marketfront batch.

SafeDep decoded the behavior statically. The payload dynamically requires fs, os, http, https, zlib, path, and dns, reads roughly 20 credential and secret files, and exfiltrates them:

  • SSH keys (~/.ssh)
  • Cloud credentials (~/.aws/credentials, ~/.kube/config, ~/.docker/config.json)
  • Registry and package tokens (~/.npmrc)
  • Network and database secrets (~/.netrc, ~/.pgpass)
  • Git credentials (~/.git-credentials)
  • Environment files and shell history (~/.env, ~/.bash_history)

The collected data is gzip-compressed and sent over an HTTPS POST with a custom X-Secret header to the path /api/v1/events, alongside a DNS resolver beacon. The command-and-control host is concealed behind an RC4 plus XOR layer around an embedded configuration blob. SafeDep did not resolve it without executing the code, and this post does not fabricate one.

How the payload evolved under a constant lure

The lure template is the stable element across the campaign. The payload is not. Across the four waves, what runs behind the same README changed in a deliberate progression:

WaveScope(s)Version patternPayload behavior
May 27, 2026@cloudplatform-single-spa, @mlspace, @car-loans and others99.99.99Cleartext constants, downloads a second stage, POSTs full process.env to oob.moika.tech/report
May 29, 2026@t-in-one, @capibar.chat, @sber-ecom-core5.7.1, 99.5.xSame behavior, three-layer obfuscation, functional kill switch
June 1, 2026@emcd-vue6.4.8, 7.1.7WaCk/JScrambler obfuscation, home-directory persistence, FUSION_ second-stage handshake
July 1, 2026@marketfront, @emcd-vue (republished)7.0.0, 7.xTargeted credential-file harvester, gzip POST to /api/v1/events, RC4-hidden C2

The version numbers also matured. The first wave used the unmistakable 99.99.99. The @marketfront wave uses 7.0.0, and the republished @emcd-vue packages use 7.1.0 and 7.2.0, which read like ordinary releases from a maintained project. Version-anomaly heuristics that catch triple-nines do not fire on these.

Two things held constant through all four waves: the Internal package — Platform Engineering Team README marker with its scope-parameterized decoy domains, and the X-Secret header on the exfiltration request. The README string is the cheapest part of the operation to change, and the actor never bothered with it, while the payload, the endpoint, the persistence strategy, and the version scheme all rotated. That makes the marker a durable pivot for hunting even as everything technical underneath it moves.

Detection guidance

The README marker is worth hunting on, but it is a weak primary detector. npm’s search index does not index README bodies, and it deprioritizes brand-new zero-download packages, which is how a freshly batch-published scope looks in its first hours. A full-text search for the marker will miss a scope published minutes ago.

The dependable detector is the metadata and behavioral fingerprint, which survives the payload rotation:

  • postinstall: node scripts/postinstall.js shipping a single-line obfuscator.io payload, next to a dist/index.js that re-exports a source file absent from the tarball
  • an author field ending in Platform Engineering with github.<scope>.io, jira.<scope>.io, and docs.<scope>.io decoy domains
  • a description drawn from the fixed “Internal … loader / logger / client” pool
  • outbound install-time traffic carrying an X-Secret header

Mitigations

  1. Lock every internal scope to a private registry in .npmrc. Without a scope-locked registry, npm resolves to the public version when the private one is unavailable, which is the entire mechanism this campaign depends on.
  2. If any @marketfront package at 7.0.0 was installed on a workstation or CI runner, treat the host as credential-compromised. Rotate SSH keys, cloud credentials (~/.aws, ~/.kube, ~/.docker), npm tokens, git credentials, and any secrets present in ~/.env or the shell environment.
  3. Check network logs for install-time HTTPS POSTs carrying an X-Secret header to a /api/v1/events path, and for unexpected DNS resolver activity during npm install.
  4. Add the metadata and behavioral fingerprint above to standing triage rules so the next scope rotation is flagged automatically rather than rediscovered by hand.
  5. Run vet against your lockfiles to surface malicious packages before the next install cycle.

Affected packages

All 25 @marketfront packages were batch-published at version 7.0.0 and carry the credential harvester. Use the checker above or the list below.

marketfront-campaign-packages.csv
ecosystem name version npm_user has_postinstall_payload published
1 npm @marketfront/actualordersnippetpopup 7.0.0 marketfront yes 2026-07-01
2 npm @marketfront/advertisingdevtool 7.0.0 marketfront yes 2026-07-01
3 npm @marketfront/bannerpopup 7.0.0 marketfront yes 2026-07-01
4 npm @marketfront/baobabtech 7.0.0 marketfront yes 2026-07-01
5 npm @marketfront/basemarkettemplate 7.0.0 marketfront yes 2026-07-01
6 npm @marketfront/blenderdevtool 7.0.0 marketfront yes 2026-07-01
7 npm @marketfront/captchaservice 7.0.0 marketfront yes 2026-07-01
8 npm @marketfront/changefilter 7.0.0 marketfront yes 2026-07-01
9 npm @marketfront/commonecommerce 7.0.0 marketfront yes 2026-07-01
10 npm @marketfront/customdealsfeed 7.0.0 marketfront yes 2026-07-01
11 npm @marketfront/designsystemdevtool 7.0.0 marketfront yes 2026-07-01
12 npm @marketfront/devtoolsloader 7.0.0 marketfront yes 2026-07-01
13 npm @marketfront/digitalherobannercarousel 7.0.0 marketfront yes 2026-07-01
14 npm @marketfront/dynamicpageparams 7.0.0 marketfront yes 2026-07-01
15 npm @marketfront/errorcounter 7.0.0 marketfront yes 2026-07-01
16 npm @marketfront/fashiononboardingpopup 7.0.0 marketfront yes 2026-07-01
17 npm @marketfront/fingerprint 7.0.0 marketfront yes 2026-07-01
18 npm @marketfront/footer 7.0.0 marketfront yes 2026-07-01
19 npm @marketfront/gotoauthpopup 7.0.0 marketfront yes 2026-07-01
20 npm @marketfront/header 7.0.0 marketfront yes 2026-07-01
21 npm @marketfront/infopopup 7.0.0 marketfront yes 2026-07-01
22 npm @marketfront/livestreampreviewpopup 7.0.0 marketfront yes 2026-07-01
23 npm @marketfront/madvpopup 7.0.0 marketfront yes 2026-07-01
24 npm @marketfront/mychatspreloader 7.0.0 marketfront yes 2026-07-01
25 npm @marketfront/navbar 7.0.0 marketfront yes 2026-07-01
25 rows
| 6 columns
  • npm
  • malware
  • supply-chain
  • dependency-confusion

Author

Kunal Singh

Kunal Singh

safedep.io

Share

The Latest from SafeDep blogs

Follow for the latest updates and insights on open source security & engineering

MYRA: A Full Linux RAT Distributed via npm

MYRA: A Full Linux RAT Distributed via npm

The npm package apintergrationpost is a red team RAT called MYRA with native C rootkit, triple persistence, fileless execution, live screen streaming, and process masquerade. This analysis documents...

SafeDep Team
Background
SafeDep Logo

Ship Code.

Not Malware.

Start free with open source tools on your machine. Scale to a unified platform for your organization.