SecureNexus GRC
SECURENEXUS
  • Home
  • Blog
  • Case Studies
  • About
Get Started
SecureNexus GRCSECURENEXUS

Empowering digital organizations with unified security — through connected insights, trusted expertise, and end-to-end coverage.

A venture of

X-Biz TechVentureswww.xbizventures.com

Services

  • Regulatory Consulting
  • Red Teaming
  • Cloud Security
  • Security Operations
  • Security Training
  • Product Advisory

Products

  • Perimeter (ASM)
  • Cloud Security Posture Management
  • Vulnerability Management
  • SOVA (SCA)
  • Third Party Risk Management

Company

  • About Us
  • Contact
  • Blog
  • Case Studies

Resources

  • Security Assessment
  • Breach Probability

Contact

[email protected]
+91 1800-266-8575

Certifications & Compliance

Certifications and Empanelment — D.U.N.S Registered, ISO 9001:2015, BQC, IAF, ISO 27001, Nasscom, ESC, CERT-IN Empanelled
Offices

Mumbai (HQ)

118-120 IJMIMA Complex, Mindspace, Malad West, Mumbai 400064

Pune (GCC)

Unit 2-B, 1st Floor, Cerebrum IT Park, Kalyani Nagar, Pune 411014

Mumbai (Tech & Innovation)

315, 3rd Floor, Lodha Supremus, Andheri East, Mumbai 400069

Dubai

M35, Warba Centre, Al Muraqqabat, Deira, Dubai

X-Biz TechVentures

© 2026 X-Biz TechVentures Pvt. Ltd. All rights reserved.

HomeBlogInside forge-jsx: Anatomy of a Multi-Platform npm RAT Masquerading as an Autodesk Forge SDK
Security
Share

Inside forge-jsx: Anatomy of a Multi-Platform npm RAT Masquerading as an Autodesk Forge SDK

Yash Kumar
2026-04-20
10 min read
SOVA
SecureNexus SOVA
Supply Chain
npm malware
Dependency Risk
SBOM
CBOM
Malware Analysis
RAT
Infostealer
Threat Intelligence
DevSecOps
Postinstall Attack
Inside forge-jsx: Anatomy of a Multi-Platform npm RAT Masquerading as an Autodesk Forge SDK

npm package [email protected] — marketed as a Node.js integration layer for Autodesk Forge — is a multi-platform RAT and infostealer. This technical breakdown walks through the postinstall kill chain, the LaunchAgent/systemd/Task Scheduler persistence primitives, the .env and shell-history harvesting modules, and the AES-256-GCM-obfuscated C2 blob, with SecureNexus SOVA analysis evidence.

Inside forge-jsx: Anatomy of a Multi-Platform npm RAT Masquerading as an Autodesk Forge SDK

By the SecureNexus SOVA research team — April 20, 2026

npm package [email protected] claims to be a Node.js integration layer for Autodesk Forge. It isn't. Multiple supply-chain scanners have independently flagged it as malicious; SecureNexus SOVA's autonomous pipeline concurs with a verdict of malicious at 0.97 confidence and an overall recommendation of block. This post walks through the evidence SOVA surfaced — the code paths, signals, and runtime behavior that make this package a purpose-built RAT.

If your CI pipeline ran npm install forge-jsx at any point in the last 13 days, skip to the response section first, then come back.

What SecureNexus SOVA's Pipeline Saw

SOVA enriches every published package through multiple stages of static analysis, behavioral signal extraction, and automated reasoning. The raw numbers on [email protected] were loud on their own.

DimensionObservation
SOVA verdictmalicious (confidence 0.97)
Risk score32
Files scanned103
Files flagged71
Capability buckets flagged maliciousnetwork, filesystem, shell, code_execution, crypto, install_hooks, env_read
Maintainer trust score0.541
Overall recommendationblock — malicious code detected
Publisherjohnceballos0716 (Gmail), single maintainer, no repository

Ten SOVA signals lit up simultaneously: crypto, env_read, filesystem, network, shell, dynamic code execution, endpoint inventory, hardcoded endpoint, hidden dependency, and npm install-hook presence. A legitimate SDK typically lights one or two of those — a thin HTTP client might tick network and env_read for config. Seven capability buckets with simultaneous malicious-intent classification is a pattern SOVA only sees in RATs and infostealers.

Loading image…
SecureNexus SOVA pipeline: 103 files scanned, 71 flagged, 7-of-7 capability buckets malicious, confidence 0.97, overall BLOCK.
SecureNexus SOVA pipeline: 103 files scanned, 71 flagged, 7-of-7 capability buckets malicious, confidence 0.97, overall BLOCK.

The Install-Time Trigger

The entire attack chain starts in package/package.json line 17:

Code
"postinstall": "node scripts/postinstall-clipboard-event.mjs && node scripts/ensure-dist.mjs && node scripts/postinstall-bootstrap.mjs && node scripts/postinstall-agent.mjs"

SOVA flagged this immediately as an install-time code-execution pattern. Four chained postinstall scripts are already unusual; pairing them with spawnSync and spawn from node:child_process imports in every one of those scripts — ensure-dist.mjs:12, postinstall-agent.mjs:14, postinstall-bootstrap.mjs:16, restart-agent.mjs:11 — is not how node-gyp rebuild works. This is a pre-main code-execution chain that runs before the developer has looked at a single file.

Multi-Platform Persistence

The strongest tell that this is a RAT, not a developer convenience, is how it plants itself on each OS. SOVA surfaced these paths under filesystem capability with malicious intent.

macOS — package/dist/autostart/darwin.js:54

Code
return path.join(process.env.HOME || os.homedir(),
                 "Library", "LaunchAgents",
                 constants_1.MACOS_PLIST_FILENAME);

The package writes a LaunchAgent plist into the user's ~/Library/LaunchAgents/ directory. LaunchAgents start automatically at login and run under the user's identity — a classic user-land persistence primitive.

Linux — package/dist/autostart/linux.js:54

JavaScript
const home = process.env.HOME || process.env.USERPROFILE || os.homedir();

The Linux path installs a systemd user unit under $XDG_CONFIG_HOME/systemd/user/. The companion module autostart/agentEnvFile.js reads XDG_RUNTIME_DIR, DISPLAY, WAYLAND_DISPLAY, DBUS_SESSION_BUS_ADDRESS, and XAUTHORITY — everything it needs to attach to an active graphical session.

Windows — handled via a Task Scheduler registration using the same spawnSync pattern from the postinstall chain. The process.env.SystemRoot || C:\Windows reference in dist/clipboardExec.js:46 confirms Windows as an intended target.

All three persistence primitives are silent, survive reboot, and do not require administrator rights.

Loading image…
forge-jsx kill chain: postinstall fan-out → LaunchAgent / systemd / Task Scheduler → .env + shell history + clipboard harvest → AES-wrapped C2 exfil.
forge-jsx kill chain: postinstall fan-out → LaunchAgent / systemd / Task Scheduler → .env + shell history + clipboard harvest → AES-wrapped C2 exfil.

Data Collection: What It Actually Steals

SOVA flagged 13 files under environment-read capability alone. The patterns are not the benign process.env.NODE_ENV or process.env.PATH accesses SOVA whitelists — they read very specific, non-standard variables that an SDK has no business touching.

Code
// dist/autostart/agentEnvFile.js:205
const bundleKey = (process.env.FORGE_JS_BUNDLE_KEY || "").trim();

// dist/deploymentDefaults.js:51
const envKey = process.env.FORGE_JS_BUNDLE_KEY?.trim();

// dist/cli-agent.js:11
const have = (process.env.FORGE_JS_SYNC_URL || "").trim() ||
             (process.env.CFGMGR_API_URL || "").trim();

On top of that, three modules scan the host filesystem for credentials:

Code
// dist/shellHistoryScan.js:97 — walks $HOME for .bash_history, .zsh_history, etc.
const docs = process.env.USERPROFILE || process.env.HOME || home;

// dist/envScan.js — recursive .env discovery; also tripped SOVA's dynamic-code rule
// dist/clientId.js:54 — user profile enumeration
const prof = (process.env.USERPROFILE || "").trim();

And two modules — dist/clipboardEventWatcher.js and dist/clipboardNapi.js — implement clipboard capture. Both pull in transitive native modules that were not declared in package.json, which SOVA raised as a hidden-dependency finding. That pattern is textbook wallet-clipper / credential-grabber behavior.

C2 Obfuscation: AES-256-GCM Over Hardcoded Bytes

SOVA tagged package/scripts/encode-deployment.mjs:22 with crypto capability and flagged its intent as malicious. The module imports node:crypto and builds a blob SOVA identified as deploymentCipherData — an AES-256-GCM-encrypted structure containing the C2 host, port, and shared secret. The unwrap key is pulled from the environment at runtime:

Code
// dist/deploymentDefaults.js:51
const envKey = process.env.FORGE_JS_BUNDLE_KEY?.trim();

That design defeats naive static analysis: grepping the package for an IP or a domain returns nothing. The endpoint only materializes in memory after the crypto unwrap, keyed on an env var the attacker sets during the first-run handshake.

Exfiltration itself runs through two transports:

Code
// dist/hfUpload.js:107
const res = await fetch(input, init);

// dist/relayServer.js — WebSocket relay (node:http + ws)

The dist/agentRunner.js:113 string reveals the kill-switch intentionally built into the malware: setting FORGE_JS_DISABLE_SYNC=1 mutes the sync loop. That variable exists so the operator can selectively silence the agent during sandbox analysis.

Code
// dist/agentRunner.js:113
"Set FORGE_JS_SYNC_URL (or CFGMGR_API_URL), and avoid FORGE_JS_DISABLE_SYNC=1 / "
Loading image…
C2 obfuscation: deploymentCipherData blob shows no IP or domain to static analysis; AES-256-GCM unwrap with FORGE_JS_BUNDLE_KEY reveals the host at runtime.
C2 obfuscation: deploymentCipherData blob shows no IP or domain to static analysis; AES-256-GCM unwrap with FORGE_JS_BUNDLE_KEY reveals the host at runtime.

Publisher and Manifest Red Flags

SOVA evaluates signals that have nothing to do with source code — publisher history, release cadence, manifest hygiene — and for forge-jsx the picture is damning:

SignalFinding
Maintainer concentrationSingle maintainer (bus factor 1)
Source transparencyNo declared repository — source cannot be independently verified
Install scriptsFour-command postinstall chain, not a native build
Release hygieneNo CHANGELOG, no LICENSE file, no SECURITY.md, no CODEOWNERS
Quality signalsNo tests shipped

SOVA's maintainer trust model returned 0.541 — pulled down by history 0.4, diversity 0.3, longevity 0.4, geography 0.3. Publisher country is unknown. Every maintainer-trust axis that SOVA measures is in the bottom third, and the package was published rapid-fire across twelve versions in thirteen days by an account with no prior ecosystem footprint.

The Brand-Jacking Angle

Autodesk retired the Forge brand years ago and rebranded to Autodesk Platform Services (APS). A package named forge-jsx in 2026 exploits two things at once: developers who still search for forge npm out of muscle memory, and the fact that there is no canonical npm package named @autodesk/forge today to collide against. The scoped twin @johntaohunter/forge-jsx publishes the same payload under a different namespace — a common tactic to survive takedowns on one of the two names.

Realistic Attack Scenario

Picture a DevOps engineer at a fintech working on a BIM-integration prototype. They remember using Forge APIs years ago, run npm install forge-jsx on their laptop, and move on. Within seconds:

  1. The postinstall chain drops a LaunchAgent into ~/Library/LaunchAgents/.
  2. shellHistoryScan.js walks ~/.zsh_history — capturing every aws configure, kubectl, ssh, and gh auth command they ever ran, along with the arguments.
  3. envScan.js recursively walks the home directory for .env files. It picks up the .env from a staging repo with AWS keys, and a .env.local from their personal side project with an OpenAI token.
  4. The clipboard watcher starts capturing anything copied — including 1Password unlock codes, AWS MFA tokens, and any API secret the engineer copies from a teammate's Slack.
  5. All of it is AES-256-GCM-encrypted and relayed over WebSocket to the operator.
  6. The LaunchAgent re-activates after every login. The engineer never sees a process name they don't recognize because cli-autostart.js hides under a generic node binary in their user session.

By the time the engineer reads a blog like this one, the credentials that matter are already elsewhere.

Detection and Response

Immediate containment

  • npm uninstall forge-jsx and npm uninstall @johntaohunter/forge-jsx
  • Grep every package-lock.json, pnpm-lock.yaml, yarn.lock, and npm-shrinkwrap.json across your org for the string forge-jsx
  • Rotate AWS access keys, GitHub PATs, npm tokens, OpenAI/HF tokens, and any credential that passed through an affected shell
  • On macOS, delete any plist from ~/Library/LaunchAgents/ that matches the MACOS_PLIST_FILENAME constant
  • On Linux, run systemctl --user list-units and remove any unit not placed by your configuration management
  • On Windows, audit Task Scheduler entries created in the install window

Operational detection at scale

SecureNexus SOVA customers had [email protected] marked block within minutes of the enriched scan completing, because the seven-capability pattern was already modeled in SOVA's default policy. Teams without that coverage typically detect postinstall RATs only after SIEM alerts on outbound WebSocket connections to new external IPs — by which point the credentials are gone.

Key Takeaways

  • Seven malicious-intent capability buckets in one package is a RAT, not an SDK. One or two fire in legitimate packages; seven does not.
  • Postinstall chains are pre-main code execution. Treat every postinstall-enabled dependency as supply-chain code that runs before your code review does.
  • Static obfuscation is now standard in npm malware. forge-jsx keeps its C2 inside an AES-GCM blob unwrapped at runtime. Scanners that only grep for IPs and domains will miss it.
  • Maintainer trust is a first-class signal. A 13-day-old account with no repo, twelve versions, and a trust score of 0.541 is the entire package review by itself.
  • Brand-jacking retired names is a durable technique. Forge is gone from Autodesk's marketing but not from developer muscle memory. Expect more of these.

How SecureNexus SOVA Helps

Traditional SCA tools catch packages after a CVE or advisory is published. forge-jsx had neither. SOVA is built to catch this class of threat on day zero:

  • Every published package is enriched within minutes — static analysis runs on the actual shipped code, not just the manifest.
  • Capability-intent classification scores each file across crypto, network, shell, filesystem, env_read, install_hooks, and dynamic_code. Seven malicious buckets at once is a signature no real SDK produces.
  • Install-hook policy blocks preinstall / install / postinstall scripts from low-trust maintainers at lockfile-resolution time — before npm install ever runs the hook.
  • Maintainer trust scoring composes history, diversity, longevity, and geography signals. A 13-day-old account with twelve rapid versions is gated automatically.
  • Typosquat and brand-jacking detection tracks retired brands and canonical namespaces — a forge-jsx with no @autodesk scope gets flagged on name alone.
  • CBOM-continuous monitoring re-scores every dependency on every new version. Capability drift between 1.0.10 and 1.0.11 would have alerted before the update reached your build.

Any one of those layers would have stopped forge-jsx before it touched a SOVA-protected lockfile.

About the Author

Yash Kumar
Lead - Research & Innovation

Yash Kumar is a Lead in Research & Innovation, focused on exploring emerging technologies and turning ideas into practical solutions. He works on driving experimentation, strategic insights, and new initiatives that help organizations stay ahead of industry trends.

Perimeter

Intelligence-driven attack surface management

Learn More

VM

Centralized vulnerability management & remediation

Learn More
View all products

Need Expert Security Guidance?

Our cybersecurity experts are here to help you implement the strategies discussed in this article.

Get Expert Consultation Explore Our Products