npx-ray 1.0.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 (72) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +365 -0
  3. package/data/popular-packages.json +619 -0
  4. package/dist/cli.d.ts +9 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +261 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/diff.d.ts +21 -0
  9. package/dist/diff.d.ts.map +1 -0
  10. package/dist/diff.js +301 -0
  11. package/dist/diff.js.map +1 -0
  12. package/dist/extract.d.ts +18 -0
  13. package/dist/extract.d.ts.map +1 -0
  14. package/dist/extract.js +80 -0
  15. package/dist/extract.js.map +1 -0
  16. package/dist/github.d.ts +38 -0
  17. package/dist/github.d.ts.map +1 -0
  18. package/dist/github.js +132 -0
  19. package/dist/github.js.map +1 -0
  20. package/dist/mcp.d.ts +19 -0
  21. package/dist/mcp.d.ts.map +1 -0
  22. package/dist/mcp.js +219 -0
  23. package/dist/mcp.js.map +1 -0
  24. package/dist/registry.d.ts +19 -0
  25. package/dist/registry.d.ts.map +1 -0
  26. package/dist/registry.js +229 -0
  27. package/dist/registry.js.map +1 -0
  28. package/dist/reporter.d.ts +23 -0
  29. package/dist/reporter.d.ts.map +1 -0
  30. package/dist/reporter.js +208 -0
  31. package/dist/reporter.js.map +1 -0
  32. package/dist/scanners/binaries.d.ts +12 -0
  33. package/dist/scanners/binaries.d.ts.map +1 -0
  34. package/dist/scanners/binaries.js +80 -0
  35. package/dist/scanners/binaries.js.map +1 -0
  36. package/dist/scanners/dependencies.d.ts +14 -0
  37. package/dist/scanners/dependencies.d.ts.map +1 -0
  38. package/dist/scanners/dependencies.js +114 -0
  39. package/dist/scanners/dependencies.js.map +1 -0
  40. package/dist/scanners/hooks.d.ts +12 -0
  41. package/dist/scanners/hooks.d.ts.map +1 -0
  42. package/dist/scanners/hooks.js +126 -0
  43. package/dist/scanners/hooks.js.map +1 -0
  44. package/dist/scanners/ioc.d.ts +17 -0
  45. package/dist/scanners/ioc.d.ts.map +1 -0
  46. package/dist/scanners/ioc.js +414 -0
  47. package/dist/scanners/ioc.js.map +1 -0
  48. package/dist/scanners/obfuscation.d.ts +12 -0
  49. package/dist/scanners/obfuscation.d.ts.map +1 -0
  50. package/dist/scanners/obfuscation.js +227 -0
  51. package/dist/scanners/obfuscation.js.map +1 -0
  52. package/dist/scanners/secrets.d.ts +12 -0
  53. package/dist/scanners/secrets.d.ts.map +1 -0
  54. package/dist/scanners/secrets.js +173 -0
  55. package/dist/scanners/secrets.js.map +1 -0
  56. package/dist/scanners/static.d.ts +13 -0
  57. package/dist/scanners/static.d.ts.map +1 -0
  58. package/dist/scanners/static.js +138 -0
  59. package/dist/scanners/static.js.map +1 -0
  60. package/dist/scanners/typosquatting.d.ts +13 -0
  61. package/dist/scanners/typosquatting.d.ts.map +1 -0
  62. package/dist/scanners/typosquatting.js +102 -0
  63. package/dist/scanners/typosquatting.js.map +1 -0
  64. package/dist/scorer.d.ts +28 -0
  65. package/dist/scorer.d.ts.map +1 -0
  66. package/dist/scorer.js +139 -0
  67. package/dist/scorer.js.map +1 -0
  68. package/dist/types.d.ts +155 -0
  69. package/dist/types.d.ts.map +1 -0
  70. package/dist/types.js +5 -0
  71. package/dist/types.js.map +1 -0
  72. package/package.json +61 -0
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Dependency analysis scanner.
3
+ *
4
+ * Analyzes package.json dependencies for:
5
+ * - Dependency count (bloat detection)
6
+ * - Git URL dependencies (not pinned to registry)
7
+ * - Wildcard/unpinned version ranges
8
+ */
9
+ import { promises as fs } from 'node:fs';
10
+ import { join } from 'node:path';
11
+ const SCANNER_NAME = 'dependencies';
12
+ /** Thresholds for dependency count. */
13
+ const DEPS_WARNING = 20;
14
+ const DEPS_CRITICAL = 50;
15
+ /** Patterns that indicate a git URL dependency. */
16
+ const GIT_URL_PATTERNS = [
17
+ /^git(\+https?|ssh)?:\/\//,
18
+ /^github:/,
19
+ /^gitlab:/,
20
+ /^bitbucket:/,
21
+ /^https?:\/\/.*\.git$/,
22
+ /^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_-]+/, // shorthand user/repo
23
+ ];
24
+ /**
25
+ * Scan package.json dependencies.
26
+ */
27
+ export async function scanDependencies(pkgDir) {
28
+ const findings = [];
29
+ const pkgJsonPath = join(pkgDir, 'package.json');
30
+ let pkgJson;
31
+ try {
32
+ const raw = await fs.readFile(pkgJsonPath, 'utf-8');
33
+ pkgJson = JSON.parse(raw);
34
+ }
35
+ catch {
36
+ return {
37
+ name: SCANNER_NAME,
38
+ passed: true,
39
+ findings: [],
40
+ summary: 'No package.json found',
41
+ };
42
+ }
43
+ const deps = (pkgJson.dependencies || {});
44
+ const optionalDeps = (pkgJson.optionalDependencies || {});
45
+ const directCount = Object.keys(deps).length;
46
+ const optionalCount = Object.keys(optionalDeps).length;
47
+ const totalCount = directCount + optionalCount;
48
+ // Check dependency count thresholds
49
+ if (totalCount > DEPS_CRITICAL) {
50
+ findings.push({
51
+ scanner: SCANNER_NAME,
52
+ severity: 'critical',
53
+ message: `Extreme dependency count: ${totalCount} dependencies (threshold: ${DEPS_CRITICAL}) — dependency bloat`,
54
+ file: 'package.json',
55
+ evidence: `${directCount} direct + ${optionalCount} optional`,
56
+ });
57
+ }
58
+ else if (totalCount > DEPS_WARNING) {
59
+ findings.push({
60
+ scanner: SCANNER_NAME,
61
+ severity: 'warning',
62
+ message: `High dependency count: ${totalCount} dependencies (threshold: ${DEPS_WARNING})`,
63
+ file: 'package.json',
64
+ evidence: `${directCount} direct + ${optionalCount} optional`,
65
+ });
66
+ }
67
+ // Check each dependency for issues
68
+ const allDeps = { ...deps, ...optionalDeps };
69
+ for (const [name, version] of Object.entries(allDeps)) {
70
+ if (typeof version !== 'string')
71
+ continue;
72
+ // Unpinned wildcard
73
+ if (version === '*' || version === '' || version === 'latest') {
74
+ findings.push({
75
+ scanner: SCANNER_NAME,
76
+ severity: 'critical',
77
+ message: `Unpinned dependency: ${name}@"${version}" — accepts any version`,
78
+ file: 'package.json',
79
+ evidence: `"${name}": "${version}"`,
80
+ });
81
+ continue;
82
+ }
83
+ // Git URL dependencies
84
+ const isGitUrl = GIT_URL_PATTERNS.some(pattern => pattern.test(version));
85
+ if (isGitUrl) {
86
+ findings.push({
87
+ scanner: SCANNER_NAME,
88
+ severity: 'warning',
89
+ message: `Git URL dependency: ${name} — not pinned to npm registry`,
90
+ file: 'package.json',
91
+ evidence: `"${name}": "${version}"`,
92
+ });
93
+ }
94
+ }
95
+ const criticalCount = findings.filter(f => f.severity === 'critical').length;
96
+ const warningCount = findings.filter(f => f.severity === 'warning').length;
97
+ const passed = criticalCount === 0 && warningCount === 0;
98
+ let summary = `${directCount} direct, ${optionalCount} optional dependencies`;
99
+ if (criticalCount > 0 || warningCount > 0) {
100
+ const flags = [];
101
+ if (criticalCount > 0)
102
+ flags.push(`${criticalCount} critical`);
103
+ if (warningCount > 0)
104
+ flags.push(`${warningCount} warning`);
105
+ summary += ` (${flags.join(', ')})`;
106
+ }
107
+ return {
108
+ name: SCANNER_NAME,
109
+ passed,
110
+ findings,
111
+ summary,
112
+ };
113
+ }
114
+ //# sourceMappingURL=dependencies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencies.js","sourceRoot":"","sources":["../../src/scanners/dependencies.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Lifecycle hooks scanner.
3
+ *
4
+ * Checks package.json for lifecycle scripts (preinstall, postinstall, etc.)
5
+ * that could execute arbitrary code during npm install.
6
+ */
7
+ import type { ScannerResult } from '../types.js';
8
+ /**
9
+ * Scan package.json for lifecycle hook scripts.
10
+ */
11
+ export declare function scanHooks(pkgDir: string): Promise<ScannerResult>;
12
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/scanners/hooks.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAW,MAAM,aAAa,CAAC;AAyB1D;;GAEG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAmGtE"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Lifecycle hooks scanner.
3
+ *
4
+ * Checks package.json for lifecycle scripts (preinstall, postinstall, etc.)
5
+ * that could execute arbitrary code during npm install.
6
+ */
7
+ import { promises as fs } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ const SCANNER_NAME = 'hooks';
10
+ /** Lifecycle scripts that run automatically and are security-sensitive. */
11
+ const DANGEROUS_HOOKS = new Set([
12
+ 'preinstall',
13
+ 'install',
14
+ 'postinstall',
15
+ 'preuninstall',
16
+ 'uninstall',
17
+ 'postuninstall',
18
+ ]);
19
+ /** Shell commands that elevate a lifecycle script to critical severity. */
20
+ const SHELL_COMMANDS = [
21
+ 'curl',
22
+ 'wget',
23
+ 'bash',
24
+ 'sh -c',
25
+ 'node -e',
26
+ 'powershell',
27
+ 'cmd /c',
28
+ ];
29
+ /**
30
+ * Scan package.json for lifecycle hook scripts.
31
+ */
32
+ export async function scanHooks(pkgDir) {
33
+ const findings = [];
34
+ const pkgJsonPath = join(pkgDir, 'package.json');
35
+ let pkgJson;
36
+ try {
37
+ const raw = await fs.readFile(pkgJsonPath, 'utf-8');
38
+ pkgJson = JSON.parse(raw);
39
+ }
40
+ catch {
41
+ return {
42
+ name: SCANNER_NAME,
43
+ passed: true,
44
+ findings: [],
45
+ summary: 'No package.json found',
46
+ };
47
+ }
48
+ const scripts = pkgJson.scripts;
49
+ if (!scripts || typeof scripts !== 'object') {
50
+ return {
51
+ name: SCANNER_NAME,
52
+ passed: true,
53
+ findings: [],
54
+ summary: 'No scripts defined',
55
+ };
56
+ }
57
+ for (const [name, command] of Object.entries(scripts)) {
58
+ if (typeof command !== 'string')
59
+ continue;
60
+ // Handle 'prepare' script — info only (common for build steps)
61
+ if (name === 'prepare') {
62
+ findings.push({
63
+ scanner: SCANNER_NAME,
64
+ severity: 'info',
65
+ message: `"prepare" script defined: ${command}`,
66
+ file: 'package.json',
67
+ evidence: command,
68
+ });
69
+ continue;
70
+ }
71
+ // Only flag dangerous lifecycle hooks
72
+ if (!DANGEROUS_HOOKS.has(name))
73
+ continue;
74
+ // Check if the script contains shell commands (elevates to critical)
75
+ const hasShellCommand = SHELL_COMMANDS.some(cmd => command.toLowerCase().includes(cmd.toLowerCase()));
76
+ if (hasShellCommand) {
77
+ findings.push({
78
+ scanner: SCANNER_NAME,
79
+ severity: 'critical',
80
+ message: `"${name}" script executes shell commands: ${command}`,
81
+ file: 'package.json',
82
+ evidence: command,
83
+ });
84
+ }
85
+ else {
86
+ findings.push({
87
+ scanner: SCANNER_NAME,
88
+ severity: 'warning',
89
+ message: `"${name}" lifecycle script defined: ${command}`,
90
+ file: 'package.json',
91
+ evidence: command,
92
+ });
93
+ }
94
+ }
95
+ const criticalCount = findings.filter(f => f.severity === 'critical').length;
96
+ const warningCount = findings.filter(f => f.severity === 'warning').length;
97
+ const passed = criticalCount === 0 && warningCount === 0;
98
+ let summary;
99
+ if (findings.length === 0) {
100
+ summary = 'No lifecycle hooks found';
101
+ }
102
+ else {
103
+ const hookNames = findings
104
+ .filter(f => f.severity !== 'info')
105
+ .map(f => {
106
+ const match = f.message.match(/^"(\w+)"/);
107
+ return match ? match[1] : '';
108
+ })
109
+ .filter(Boolean);
110
+ if (hookNames.length > 0) {
111
+ summary = `Lifecycle hooks: ${hookNames.join(', ')}`;
112
+ if (criticalCount > 0)
113
+ summary += ` (${criticalCount} with shell commands)`;
114
+ }
115
+ else {
116
+ summary = 'Only benign lifecycle hooks (prepare)';
117
+ }
118
+ }
119
+ return {
120
+ name: SCANNER_NAME,
121
+ passed,
122
+ findings,
123
+ summary,
124
+ };
125
+ }
126
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/scanners/hooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * IOC (Indicators of Compromise) scanner.
3
+ *
4
+ * Extracts URLs and IP addresses from package source code and outputs
5
+ * them in defanged format to prevent accidental navigation/resolution.
6
+ *
7
+ * Defanging: http → hxxp, :// → [://], . in domains/IPs → [.]
8
+ */
9
+ import type { ScannerResult } from '../types.js';
10
+ /**
11
+ * Scan all files in a package directory for URLs and IP addresses.
12
+ * Includes a deobfuscation layer that decodes hex escapes, unicode
13
+ * escapes, String.fromCharCode, and base64 before scanning.
14
+ * Returns them in defanged format.
15
+ */
16
+ export declare function scanIoc(pkgDir: string): Promise<ScannerResult>;
17
+ //# sourceMappingURL=ioc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ioc.d.ts","sourceRoot":"","sources":["../../src/scanners/ioc.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAW,MAAM,aAAa,CAAC;AAqP1D;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAsMpE"}