pkgxray 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/auditor.js +39 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pkgxray",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Zero-dep local CLI and MCP server that scans npm packages and AI-agent extensions for supply-chain risk. OSV vuln pre-check, sandboxed quarantine, tarball-integrity verification, calibrated static heuristics.",
5
5
  "license": "MIT",
6
6
  "author": "Jack Adams-Lovell",
package/src/auditor.js CHANGED
@@ -57,19 +57,54 @@ const PERSISTENCE_REGEXES = [
57
57
  const EXEC_REGEX = /\b(?:child_process\.(?:exec|execSync|spawn|spawnSync|fork)|require\(['"]child_process['"]\)|os\.system\(|subprocess\.(?:Popen|run|call|check_output)|Runtime\.getRuntime\(\)\.exec)/;
58
58
  const DYNAMIC_EVAL_REGEX = /\b(?:eval\s*\(|new\s+Function\s*\(|vm\.runIn[A-Za-z]+Context\b)/;
59
59
 
60
- const NETWORK_REGEX = /\b(?:fetch\s*\(|axios\.[a-z]+\s*\(|got\s*\(|node-fetch|undici|https?\.request\s*\(|XMLHttpRequest|new\s+WebSocket|requests\.[a-z]+\s*\(|urllib(?:\.request)?|net\/http)/i;
60
+ const NETWORK_REGEX = /\b(?:fetch\s*\(|axios\.[a-z]+\s*\(|got\s*\(|node-fetch|undici|https?\.(?:request|get|post|put|delete)\s*\(|XMLHttpRequest|new\s+WebSocket|requests\.[a-z]+\s*\(|urllib(?:\.request)?|net\/http|httpx\.[a-z]+\s*\()/i;
61
61
  const SHELL_NETWORK_REGEX = /(?:^|[\s;&|`$(])(?:curl|wget|Invoke-WebRequest)\s/m;
62
62
 
63
- const URL_SHORTENER_PATTERNS = [
63
+ // Domains that are almost never legitimate destinations from production code.
64
+ // Three buckets: URL shorteners (data hiding), paste/webhook services
65
+ // (drop sites), and OAST/tunneling services (Burp Collaborator-style
66
+ // out-of-band callbacks used in dependency-confusion PoCs and credential
67
+ // staging). A real library would not call any of these.
68
+ const EXFIL_AND_CALLBACK_DOMAINS = [
69
+ // URL shorteners
64
70
  "bit.ly",
65
71
  "tinyurl.com",
66
72
  "t.co/",
67
73
  "goo.gl",
74
+ "is.gd",
75
+ "ow.ly",
76
+ // Paste / drop sites
68
77
  "pastebin.com",
69
78
  "hastebin",
79
+ "transfer.sh",
80
+ // Webhooks
70
81
  "webhook.site",
71
82
  "discord.com/api/webhooks",
72
- "hooks.slack.com"
83
+ "hooks.slack.com",
84
+ "discordapp.com/api/webhooks",
85
+ // OAST / collaborator services (Burp, Caido, ProjectDiscovery)
86
+ "oast.live",
87
+ "oast.fun",
88
+ "oast.online",
89
+ "oast.pro",
90
+ "oast.me",
91
+ "oast.site",
92
+ "oastify.com",
93
+ "interact.sh",
94
+ "burpcollaborator.net",
95
+ // Pipe / request inspector services
96
+ "requestbin.com",
97
+ "requestbin.net",
98
+ "pipedream.net",
99
+ "pipedream.com",
100
+ "rce.ee",
101
+ // Tunneling / reverse proxies
102
+ "ngrok-free.app",
103
+ "ngrok.io",
104
+ "serveo.net",
105
+ "lhr.life",
106
+ "loca.lt",
107
+ "trycloudflare.com"
73
108
  ];
74
109
 
75
110
  // Directive phrases targeting an LLM / auditor. Kept narrow on purpose — generic
@@ -538,7 +573,7 @@ function inspectExecNetworkCombinations(file, content, lower, findings) {
538
573
  const hasDynamicEval = DYNAMIC_EVAL_REGEX.test(content);
539
574
  const hasNetwork = NETWORK_REGEX.test(content) || SHELL_NETWORK_REGEX.test(content);
540
575
  const hardcodedIp = findPublicIpInCode(content);
541
- const shortener = URL_SHORTENER_PATTERNS.find((pattern) => lower.includes(pattern));
576
+ const shortener = EXFIL_AND_CALLBACK_DOMAINS.find((pattern) => lower.includes(pattern));
542
577
  const hasBulkEnv = BULK_ENV_REGEXES.some((re) => re.test(content));
543
578
 
544
579
  // HIGH: real exfil/loader signal — execution OR network plus a hardcoded IP /