registry  /  pm2-orbit  /  1.3.1

pm2-orbit@1.3.1

High-performance PM2 monitoring dashboard — event-driven, 1000+ processes, < 150KB

AI Security Review

scanned 2d ago · by lpm-firewall-ai

No confirmed malicious attack surface was established. The package is a PM2 monitoring dashboard with local server APIs and optional user-configured notifications.

Static reason
High-risk behavior combination matched malicious policy.; previous stored version diff introduced dangerous source
Trigger
npm install prints PM2 guidance; pm2-orbit CLI starts the dashboard and may install pm2 if missing
Impact
User may run a local monitoring server, store package settings/history under ~/.pm2-orbit, and send alerts to configured endpoints; no source-backed exfiltration or hijack behavior found.
Mechanism
local PM2 dashboard with optional CLI dependency installation and configurable alert webhooks
Rationale
Static source inspection shows lifecycle code only prints PM2 installation guidance, while the CLI's child_process use is a fixed, user-invoked global pm2 install for a PM2 dashboard. The server/UI code exposes local monitoring APIs and user-configured notification channels without hardcoded exfiltration, persistence outside the product contract, destructive behavior, or AI-agent control-surface mutation.
Evidence
package.jsonbin/pm2-orbit.jsdist/server.jsdist-ui/assets/index-V_LzcrdQ.jsREADME.md~/.pm2-orbit/history.db~/.pm2-orbit/alerts.json
Network endpoints1
registry.npmjs.org/pm2-orbit/latest

Decision evidence

public snapshot
AI called this Clean at 90.0% confidence as Benign with low false-positive risk.
Evidence for block
  • package.json has postinstall, but it only checks require.resolve('pm2') and prints install guidance
  • bin/pm2-orbit.js contains CLI-triggered execSync('npm install -g pm2') when pm2 is missing
  • dist/server.js can POST alert payloads to user-configured WEBHOOK_URL, SLACK_WEBHOOK_URL, DISCORD_WEBHOOK_URL
Evidence against
  • package.json postinstall does not auto-install dependencies or run package code
  • bin/pm2-orbit.js child_process use is fixed to pm2 and occurs during user-invoked CLI startup
  • dist/server.js implements local Fastify PM2 monitoring APIs, WebSocket/SSE logs, and ~/.pm2-orbit history/settings storage
  • dist-ui/assets/index-V_LzcrdQ.js uses same-origin /api and /ws calls; webhook URLs are user-entered settings, not hardcoded exfiltration
  • Only hardcoded external lookup found is package-aligned update check to https://registry.npmjs.org/pm2-orbit/latest
  • No AI-agent control-surface writes, persistence hooks, destructive actions, credential harvesting, or remote payload loading found
Behavioral surface
Source
ChildProcessCryptoEnvironmentVarsEvalFilesystemNetworkWebSocket
Supply chain
HighEntropyStringsMinifiedObfuscatedProtestwareUrlStrings
ManifestNo manifest risk signals triggered.
scanned 9 file(s), 2.21 MB of source, external domains: 127.0.0.1, accounts.google.com, api.nodemailer.com, discord.com, ethereal.email, fastify.dev, github.com, hooks.slack.com, json-schema.org, localhost.com, mail.google.com, nodemailer.com, plus-innovations.com, pm2.io, pm2.keymetrics.io, raw.githubusercontent.com, react.dev, registry.npmjs.org, systeminformation.io, www.buymeacoffee.com, www.w3.org, your-webhook-endpoint.com

Source & flagged code

11 flagged · loading source
package.jsonView file
scripts.postinstall = node -e "try{require.resolve('pm2')}catch{console.log('\n ℹ Install pm2 for process monitoring: npm install -g pm2\n')}"
Critical
Red Install Lifecycle Script

Install-time lifecycle script matches a deterministic static-gate block pattern.

package.jsonView on unpkg
scripts.postinstall = node -e "try{require.resolve('pm2')}catch{console.log('\n ℹ Install pm2 for process monitoring: npm install -g pm2\n')}"
High
Install Time Lifecycle Scripts

Package defines install-time lifecycle scripts.

package.jsonView on unpkg
bin/pm2-orbit.jsView file
matchType = previous_version_dangerous_delta matchedPackage = pm2-orbit@1.3.0 matchedIdentity = npm:cG0yLW9yYml0:1.3.0 similarity = 0.875 summary = stored previous version shares package body but lacks this dangerous source file
Critical
Previous Version Dangerous Delta

This package version adds a dangerous source file absent from the previous stored version; route for source-aware review.

bin/pm2-orbit.jsView on unpkg
67try { L68: const { execSync } = require('child_process'); L69: execSync(`npm install -g ${name}`, { stdio: 'inherit', timeout: 120000 });
High
Child Process

Package source references child process execution.

bin/pm2-orbit.jsView on unpkg · L67
dist/server.jsView file
28|| (${o} === "string" && ${n} && ${n} == +${n} && !(${n} % 1))`).assign(a,(0,Le._)`+${n}`);return;case"boolean":r.elseIf((0,Le._)`${n} === "false" || ${n} === 0 || ${n} === null`).... L29: || ${o} === "boolean" || ${n} === null`).assign(a,(0,Le._)`[${n}]`)}}}function Boe({gen:e,parentData:t,parentDataProperty:i},r){e.if((0,Le._)`${t} !== undefined`,()=>e.assign((0,Le... L30: missingProperty: ${r},
High
Eval

Package source references dynamic code evaluation.

dist/server.jsView on unpkg · L28
423globstar while`,A,ie,M,ce,Te),this.matchOne(A.slice(ie),M.slice(ce),j))return this.debug("globstar found match!",ie,I,Te),!0;if(Te==="."||Te===".."||!$.dot&&Te.charAt(0)==="."){thi... L424: >>> no match, partial?`,A,ie,M,ce),ie===I))}let Ae;if(typeof V=="string"?(Ae=oe===V,this.debug("string match",V,oe,Ae)):(Ae=V.test(oe),this.debug("pattern match",V,oe,Ae)),!Ae)retu... L425: <html lang="en"> ... L434: `;return[i,Buffer.byteLength(i)]}xW.createHtmlDocument=AAe});var wW=S((GHe,bW)=>{"use strict";function kAe(e,t){if(typeof e=="string")return[e];if(e===!1)return[];if(Array.isArray(... L435: at `+e[i].toString();return t}function BAe(e){if(!e)throw new TypeError("argument namespace is required");var t=Wy(),i=iu(t[1]),r=i[0];function n(s){Vy.call(n,s)}return n._file=r,n... L436: `,"utf8")}}}function iu(e){var t=e.getFileName()||"<anonymous>",i=e.getLineNumber(),r=e.getColumnNumber();e.isEval()&&(t=e.getEvalOrigin()+", "+t);var n=[t,i,r];return n.callSite=e... L437: at `+i[s].toString();return n}return t&&(n+=" at "+pO(t)),n}function WAe(e,t,i){var r="\x1B[36;1m"+this._namespace+"\x1B[22;39m \x1B[33;1mdeprecated\x1B[22;39m \x1B[0m"+e+"\x1B[39m... L438: \x1B[36mat `+i[n].toString(
High
Same File Env Network Execution

A single source file combines environment access, network access, and code or shell execution; review context before blocking.

dist/server.jsView on unpkg · L423
22${y}${O} L23: ${x}`),m.pop(),`{${O}}`}case"number":return isFinite(h)?String(h):t?t(h):"null";case"boolean":return h===!0?"true":"false";case"undefined":return;case"bigint":if(r)return String(h)... L24: `:` L25: `),q=jie.bind(null,{[w2]:"",[_2]:o,[E2]:N,[S2]:Ob,[Rb]:C,[T2]:P}),X="";p!==null&&(f===void 0?X=q(p):X=q(Object.assign({},p,{name:f})));let B=a instanceof Function?a:a?k2:nre,U=B().... L26: `:""},this._extScope=t,this._scope=new Wr.Scope({parent:t}),this._nodes=[new xw]}toString(){return this._root.render(this.opts)}name(t){return this._scope.name(t)}scopeName(t){retu... ... L28: || (${o} === "string" && ${n} && ${n} == +${n} && !(${n} % 1))`).assign(a,(0,Le._)`+${n}`);return;case"boolean":r.elseIf((0,Le._)`${n} === "false" || ${n} === 0 || ${n} === null`).... L29: || ${o} === "boolean" || ${n} === null`).assign(a,(0,Le._)`[${n}]`)}}}function Boe({gen:e,parentData:t,parentDataProperty:i},r){e.if((0,Le._)`${t} !== undefined`,()=>e.assign((0,Le... L30: missingProperty: ${r},
High
Command Output Exfiltration

Source combines command execution, command-output handling, and outbound requests; review data flow before blocking.

dist/server.jsView on unpkg · L22
2`;for(let s=0;s<r;++s){let o=e.nodes[s],a=t+(s===n?" ":"\u2502 ");i+=t,i+=s===n?"\u2514\u2500":"\u251C\u2500",i+=o.nodes.length===0?"\u2500 ":"\u252C ",i+=yA(o,a).slice(t.length+2... L3: `).slice(0,2).map(i=>i.trim()).join(" -- ")}EA.exports={getPluginName:tJ}});var wh=S((W$e,CA)=>{"use strict";function iJ(e){return e!==null&&typeof e=="object"&&typeof e.then=="fun... L4: causes have become circular...`;let r=qv(e);return r?(t.add(e),i+` L5: caused by: `+Ik(r,t)):i},jQ=e=>Ik(e,new Set),Lk=(e,t,i)=>{if(!Zu(e))return"";let r=i?"":e.message||"";if(t.has(e))return r+": ...";let n=qv(e);if(n){t.add(e);let s=typeof e.cause==... L6: ${x}`,_=`, ... L22: ${y}${O} L23: ${x}`),m.pop(),`{${O}}`}case"number":return isFinite(h)?String(h):t?t(h):"null";case"boolean":return h===!0?"true":"false";case"undefined":return;case"bigint":if(r)return String(h)... L24: `:` L25: `),q=jie.bind(null,{[w2]:"",[_2]:o,[E2]:N,[S2]:Ob,[Rb]:C,[T2]:P}),X="";p!==null&&(f===void 0?X=q(p):X=q(Object.assign({},p,{name:f})));let B=a instanceof Function?a:a?k2:nre,U=B().... L26: `:""},this._extScope=t,this._scope=new Wr.Scope({parent:t}),this._nodes=[new xw]}toString(){return this._root.render(this.opts)}name(t){retu
High
Sandbox Evasion Gated Capability

Source gates dangerous network, credential, or execution behavior behind CI, host, platform, time, or geo fingerprint checks.

dist/server.jsView on unpkg · L2
2`;for(let s=0;s<r;++s){let o=e.nodes[s],a=t+(s===n?" ":"\u2502 ");i+=t,i+=s===n?"\u2514\u2500":"\u251C\u2500",i+=o.nodes.length===0?"\u2500 ":"\u252C ",i+=yA(o,a).slice(t.length+2... L3: `).slice(0,2).map(i=>i.trim()).join(" -- ")}EA.exports={getPluginName:tJ}});var wh=S((W$e,CA)=>{"use strict";function iJ(e){return e!==null&&typeof e=="object"&&typeof e.then=="fun... L4: causes have become circular...`;let r=qv(e);return r?(t.add(e),i+` L5: caused by: `+Ik(r,t)):i},jQ=e=>Ik(e,new Set),Lk=(e,t,i)=>{if(!Zu(e))return"";let r=i?"":e.message||"";if(t.has(e))return r+": ...";let n=qv(e);if(n){t.add(e);let s=typeof e.cause==... L6: ${x}`,_=`, ... L22: ${y}${O} L23: ${x}`),m.pop(),`{${O}}`}case"number":return isFinite(h)?String(h):t?t(h):"null";case"boolean":return h===!0?"true":"false";case"undefined":return;case"bigint":if(r)return String(h)... L24: `:` L25: `),q=jie.bind(null,{[w2]:"",[_2]:o,[E2]:N,[S2]:Ob,[Rb]:C,[T2]:P}),X="";p!==null&&(f===void 0?X=q(p):X=q(Object.assign({},p,{name:f})));let B=a instanceof Function?a:a?k2:nre,U=B().... L26: `:""},this._extScope=t,this._scope=new Wr.Scope({parent:t}),this._nodes=[new xw]}toString(){return this._root.render(this.opts)}name(t){retu
Low
Weak Crypto

Package source references weak cryptographic algorithms.

dist/server.jsView on unpkg · L2
dist-ui/assets/index-V_LzcrdQ.jsView file
1import{j as i,_ as Dn}from"./cmdk-cQPtLM7A.js";import{r as zc,g as wp,a as b,b as K,B as wi,M as zx,c as Np,S as Ep,W as Tx,d as Cx,C as Ax,e as zp,f as Mx,A as hc,N as Rx,H as Dx,... L2: * @license React ... L16: * LICENSE file in the root directory of this source tree. L17: */var Zh;function ab(){if(Zh)return ks;Zh=1;var s=tb(),o=zc(),u=$x();function c(e){var t="https://react.dev/errors/"+e;if(1<arguments.length){t+="?args[]="+encodeURIComponent(argum... L18: at`)?" (<anonymous>)":-1<a.stack.indexOf("@")?"@unknown:0:0":""}return` ... L23: Error generating stack: `+l.message+` L24: `+l.stack}}var Xn=Object.prototype.hasOwnProperty,ql=s.unstable_scheduleCallback,fa=s.unstable_cancelCallback,Is=s.unstable_shouldYield,ma=s.unstable_requestPaint,dt=s.unstable_now... L25: `).replace(K0,"")}function ih(e,t){return t=rh(t),rh(e)===t}function Ae(e,t,a,l,n,r){switch(a){case"children":typeof l=="string"?t==="body"||t==="textarea"&&l===""||Fl(e,l):(typeof... ... L54: `),$=new Blob([M],{type:"text/csv"}),Se=URL.createObjectURL($),Y=document.createElement("a");Y.href=Se,Y.download=`pm2-orbit-processes-${Date.now()}.csv`,Y.click(),URL.revokeObject... L55: `);for(const V of F)if(V)try{const
Critical
Credential Exfiltration

Source appears to send environment or credential material to an external endpoint.

dist-ui/assets/index-V_LzcrdQ.jsView on unpkg · L1
dist-ui/fonts/Exo-400.woff2View file
path = dist-ui/fonts/Exo-400.woff2 kind = high_entropy_blob sizeBytes = 21828 magicHex = [redacted]
High
Ships High Entropy Blob

Package ships high-entropy non-source blobs.

dist-ui/fonts/Exo-400.woff2View on unpkg

Findings

3 Critical7 High4 Medium7 Low
CriticalRed Install Lifecycle Scriptpackage.json
CriticalCredential Exfiltrationdist-ui/assets/index-V_LzcrdQ.js
CriticalPrevious Version Dangerous Deltabin/pm2-orbit.js
HighInstall Time Lifecycle Scriptspackage.json
HighChild Processbin/pm2-orbit.js
HighEvaldist/server.js
HighSame File Env Network Executiondist/server.js
HighCommand Output Exfiltrationdist/server.js
HighSandbox Evasion Gated Capabilitydist/server.js
HighShips High Entropy Blobdist-ui/fonts/Exo-400.woff2
MediumNetwork
MediumEnvironment Vars
MediumProtestware
MediumStructural Risk Force Deep Review
LowNon Install Lifecycle Scripts
LowScripts Present
LowWeak Cryptodist/server.js
LowFilesystem
LowObfuscated
LowHigh Entropy Strings
LowUrl Strings