@sentinel-atl/scanner 0.3.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 (42) hide show
  1. package/README.md +104 -0
  2. package/dist/dependency-scanner.d.ts +22 -0
  3. package/dist/dependency-scanner.d.ts.map +1 -0
  4. package/dist/dependency-scanner.js +70 -0
  5. package/dist/dependency-scanner.js.map +1 -0
  6. package/dist/index.d.ts +24 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +24 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/package-resolver.d.ts +30 -0
  11. package/dist/package-resolver.d.ts.map +1 -0
  12. package/dist/package-resolver.js +105 -0
  13. package/dist/package-resolver.js.map +1 -0
  14. package/dist/pattern-scanner.d.ts +30 -0
  15. package/dist/pattern-scanner.d.ts.map +1 -0
  16. package/dist/pattern-scanner.js +178 -0
  17. package/dist/pattern-scanner.js.map +1 -0
  18. package/dist/permission-scanner.d.ts +28 -0
  19. package/dist/permission-scanner.d.ts.map +1 -0
  20. package/dist/permission-scanner.js +100 -0
  21. package/dist/permission-scanner.js.map +1 -0
  22. package/dist/publisher-scanner.d.ts +56 -0
  23. package/dist/publisher-scanner.d.ts.map +1 -0
  24. package/dist/publisher-scanner.js +238 -0
  25. package/dist/publisher-scanner.js.map +1 -0
  26. package/dist/scanner.d.ts +61 -0
  27. package/dist/scanner.d.ts.map +1 -0
  28. package/dist/scanner.js +71 -0
  29. package/dist/scanner.js.map +1 -0
  30. package/dist/stc.d.ts +88 -0
  31. package/dist/stc.d.ts.map +1 -0
  32. package/dist/stc.js +115 -0
  33. package/dist/stc.js.map +1 -0
  34. package/dist/tool-prober.d.ts +46 -0
  35. package/dist/tool-prober.d.ts.map +1 -0
  36. package/dist/tool-prober.js +158 -0
  37. package/dist/tool-prober.js.map +1 -0
  38. package/dist/trust-score.d.ts +26 -0
  39. package/dist/trust-score.d.ts.map +1 -0
  40. package/dist/trust-score.js +65 -0
  41. package/dist/trust-score.js.map +1 -0
  42. package/package.json +52 -0
package/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # @sentinel-atl/scanner
2
+
3
+ MCP server security scanner — npm audit meets AI agent trust verification.
4
+
5
+ Analyzes MCP server packages for dependency vulnerabilities, dangerous code patterns, permission requirements, and publisher identity. Produces a 0–100 trust score and can issue/verify Sentinel Trust Certificates (STCs).
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @sentinel-atl/scanner
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```ts
16
+ import { scan, issueSTC } from '@sentinel-atl/scanner';
17
+
18
+ // Full security scan
19
+ const report = await scan({ packageName: 'some-mcp-server' });
20
+ console.log(report.trustScore.overall); // 0-100
21
+ console.log(report.trustScore.grade); // A-F
22
+
23
+ // Issue a Sentinel Trust Certificate
24
+ const stc = await issueSTC({
25
+ issuer: { did: 'did:key:z6Mk...' },
26
+ subject: { packageName: 'some-mcp-server', packageVersion: '1.0.0' },
27
+ findings: report.findings,
28
+ });
29
+ ```
30
+
31
+ ## Security Analysis
32
+
33
+ The scanner runs 4 sub-scanners and aggregates results into a single trust score:
34
+
35
+ ### 1. Dependency Vulnerabilities
36
+
37
+ ```ts
38
+ import { scanDependencies } from '@sentinel-atl/scanner';
39
+ const result = await scanDependencies('/path/to/package');
40
+ // Integrates with npm audit
41
+ ```
42
+
43
+ ### 2. Code Pattern Analysis
44
+
45
+ ```ts
46
+ import { scanCodePatterns } from '@sentinel-atl/scanner';
47
+ const result = await scanCodePatterns('/path/to/package');
48
+ // Detects: eval, child_process, fs, net, exfiltration, obfuscation
49
+ ```
50
+
51
+ ### 3. Permission Analysis
52
+
53
+ ```ts
54
+ import { scanPermissions } from '@sentinel-atl/scanner';
55
+ const result = await scanPermissions('/path/to/package');
56
+ // Analyzes: filesystem, network, process, crypto, environment, native
57
+ ```
58
+
59
+ ### 4. Publisher Identity
60
+
61
+ ```ts
62
+ import { scanPublisher } from '@sentinel-atl/scanner';
63
+ const result = await scanPublisher('express');
64
+ // Checks npm registry: maintainers, downloads, repository presence
65
+ ```
66
+
67
+ ## Trust Score
68
+
69
+ ```ts
70
+ import { computeTrustScore } from '@sentinel-atl/scanner';
71
+
72
+ const score = computeTrustScore(findings);
73
+ // { overall: 82, grade: 'B', breakdown: { dependencies, codePatterns, permissions, publisher } }
74
+ ```
75
+
76
+ Grading scale: **A** (90–100), **B** (80–89), **C** (70–79), **D** (60–69), **F** (0–59).
77
+
78
+ ## Sentinel Trust Certificates (STC)
79
+
80
+ STCs are signed attestations of a scan result — the core artifact of the Sentinel trust ecosystem.
81
+
82
+ ```ts
83
+ import { issueSTC, verifySTC } from '@sentinel-atl/scanner';
84
+
85
+ // Issue
86
+ const stc = await issueSTC({ issuer, subject, findings });
87
+
88
+ // Verify
89
+ const result = verifySTC(stc);
90
+ // { valid: true, expired: false, ... }
91
+ ```
92
+
93
+ ## MCP Tool Probing
94
+
95
+ ```ts
96
+ import { probeTools } from '@sentinel-atl/scanner';
97
+
98
+ const result = await probeTools('http://localhost:4000/sse');
99
+ // Returns tool definitions with permission analysis
100
+ ```
101
+
102
+ ## License
103
+
104
+ MIT
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Dependency scanner — checks for known vulnerabilities via npm audit.
3
+ */
4
+ import type { Finding } from './scanner.js';
5
+ export interface VulnerablePackage {
6
+ name: string;
7
+ severity: 'critical' | 'high' | 'moderate' | 'low' | 'info';
8
+ title: string;
9
+ url?: string;
10
+ range?: string;
11
+ fixAvailable: boolean;
12
+ }
13
+ export interface DependencyScanResult {
14
+ vulnerabilities: VulnerablePackage[];
15
+ totalDependencies: number;
16
+ findings: Finding[];
17
+ }
18
+ /**
19
+ * Run `npm audit --json` against a package directory and parse results.
20
+ */
21
+ export declare function scanDependencies(packagePath: string): Promise<DependencyScanResult>;
22
+ //# sourceMappingURL=dependency-scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-scanner.d.ts","sourceRoot":"","sources":["../src/dependency-scanner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,KAAK,GAAG,MAAM,CAAC;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,eAAe,EAAE,iBAAiB,EAAE,CAAC;IACrC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAoDzF"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Dependency scanner — checks for known vulnerabilities via npm audit.
3
+ */
4
+ import { execFile } from 'node:child_process';
5
+ import { existsSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ /**
8
+ * Run `npm audit --json` against a package directory and parse results.
9
+ */
10
+ export async function scanDependencies(packagePath) {
11
+ const findings = [];
12
+ const vulnerabilities = [];
13
+ // Check if package-lock.json exists (npm audit requires it)
14
+ const lockPath = join(packagePath, 'package-lock.json');
15
+ if (!existsSync(lockPath)) {
16
+ return { vulnerabilities: [], totalDependencies: 0, findings };
17
+ }
18
+ try {
19
+ const auditOutput = await runNpmAudit(packagePath);
20
+ const audit = JSON.parse(auditOutput);
21
+ const totalDependencies = audit.metadata?.totalDependencies ?? 0;
22
+ // Parse npm audit v2 format
23
+ if (audit.vulnerabilities) {
24
+ for (const [name, info] of Object.entries(audit.vulnerabilities)) {
25
+ const vuln = {
26
+ name,
27
+ severity: info.severity ?? 'info',
28
+ title: info.via?.[0]?.title ?? info.via?.[0] ?? 'Unknown vulnerability',
29
+ url: info.via?.[0]?.url,
30
+ range: info.range,
31
+ fixAvailable: !!info.fixAvailable,
32
+ };
33
+ vulnerabilities.push(vuln);
34
+ const severityMap = {
35
+ critical: 'critical',
36
+ high: 'high',
37
+ moderate: 'medium',
38
+ low: 'low',
39
+ info: 'info',
40
+ };
41
+ findings.push({
42
+ severity: severityMap[vuln.severity] ?? 'info',
43
+ category: 'vulnerability',
44
+ title: `Vulnerable dependency: ${name}`,
45
+ description: typeof vuln.title === 'string' ? vuln.title : `Vulnerability in ${name}`,
46
+ evidence: vuln.url,
47
+ });
48
+ }
49
+ }
50
+ return { vulnerabilities, totalDependencies, findings };
51
+ }
52
+ catch {
53
+ // npm audit failed — could be no lockfile, network issue, etc.
54
+ return { vulnerabilities: [], totalDependencies: 0, findings };
55
+ }
56
+ }
57
+ function runNpmAudit(cwd) {
58
+ return new Promise((resolve, reject) => {
59
+ execFile('npm', ['audit', '--json', '--omit=dev'], { cwd, maxBuffer: 10 * 1024 * 1024 }, (error, stdout) => {
60
+ // npm audit exits with non-zero when vulnerabilities exist, but still outputs JSON
61
+ if (stdout) {
62
+ resolve(stdout);
63
+ }
64
+ else {
65
+ reject(error ?? new Error('npm audit produced no output'));
66
+ }
67
+ });
68
+ });
69
+ }
70
+ //# sourceMappingURL=dependency-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-scanner.js","sourceRoot":"","sources":["../src/dependency-scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @sentinel-atl/scanner — MCP Server Security Scanner
3
+ *
4
+ * "npm audit for MCP servers."
5
+ *
6
+ * Static analysis engine that scans MCP server packages for:
7
+ * 1. Dependency vulnerabilities (npm audit integration)
8
+ * 2. Dangerous code patterns (eval, child_process, fs, net, exfiltration)
9
+ * 3. Obfuscation detection (encoded payloads, minified code in src)
10
+ * 4. Permission scope analysis (what system resources does it access?)
11
+ * 5. Publisher identity verification (npm registry checks)
12
+ *
13
+ * Produces a TrustScore (0-100) and a ScanReport with detailed findings.
14
+ */
15
+ export { scan, type ScanOptions, type ScanReport, type TrustScore, type Finding, type FindingSeverity, type FindingCategory, } from './scanner.js';
16
+ export { scanDependencies, type DependencyScanResult, type VulnerablePackage, } from './dependency-scanner.js';
17
+ export { scanCodePatterns, type PatternScanResult, type CodePattern, type PatternCategory, } from './pattern-scanner.js';
18
+ export { scanPermissions, type PermissionScanResult, type DetectedPermission, type PermissionKind, } from './permission-scanner.js';
19
+ export { computeTrustScore, type ScoreBreakdown, } from './trust-score.js';
20
+ export { issueSTC, verifySTC, type SentinelTrustCertificate, type STCIssuer, type STCSubject, type STCFindingSummary, type STCProof, type STCVerifyResult, type IssueSTCOptions, } from './stc.js';
21
+ export { resolvePackage, cleanupPackage, type ResolvedPackage, } from './package-resolver.js';
22
+ export { probeTools, type ToolProbeResult, type MCPTool, type ProbeOptions, } from './tool-prober.js';
23
+ export { scanPublisher, type PublisherInfo, type PublisherScanResult, } from './publisher-scanner.js';
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,IAAI,EACJ,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,GACvB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,gBAAgB,EAChB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,eAAe,GACrB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,eAAe,EACf,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,cAAc,GACpB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,iBAAiB,EACjB,KAAK,cAAc,GACpB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,QAAQ,EACR,SAAS,EACT,KAAK,wBAAwB,EAC7B,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,cAAc,EACd,cAAc,EACd,KAAK,eAAe,GACrB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,UAAU,EACV,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,YAAY,GAClB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,aAAa,EACb,KAAK,aAAa,EAClB,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @sentinel-atl/scanner — MCP Server Security Scanner
3
+ *
4
+ * "npm audit for MCP servers."
5
+ *
6
+ * Static analysis engine that scans MCP server packages for:
7
+ * 1. Dependency vulnerabilities (npm audit integration)
8
+ * 2. Dangerous code patterns (eval, child_process, fs, net, exfiltration)
9
+ * 3. Obfuscation detection (encoded payloads, minified code in src)
10
+ * 4. Permission scope analysis (what system resources does it access?)
11
+ * 5. Publisher identity verification (npm registry checks)
12
+ *
13
+ * Produces a TrustScore (0-100) and a ScanReport with detailed findings.
14
+ */
15
+ export { scan, } from './scanner.js';
16
+ export { scanDependencies, } from './dependency-scanner.js';
17
+ export { scanCodePatterns, } from './pattern-scanner.js';
18
+ export { scanPermissions, } from './permission-scanner.js';
19
+ export { computeTrustScore, } from './trust-score.js';
20
+ export { issueSTC, verifySTC, } from './stc.js';
21
+ export { resolvePackage, cleanupPackage, } from './package-resolver.js';
22
+ export { probeTools, } from './tool-prober.js';
23
+ export { scanPublisher, } from './publisher-scanner.js';
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,IAAI,GAOL,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,gBAAgB,GAGjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,gBAAgB,GAIjB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,eAAe,GAIhB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,iBAAiB,GAElB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,QAAQ,EACR,SAAS,GAQV,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,cAAc,EACd,cAAc,GAEf,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,UAAU,GAIX,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,aAAa,GAGd,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * NPM package resolver — download and extract npm packages for scanning.
3
+ *
4
+ * Supports:
5
+ * - npm package names: "@modelcontextprotocol/server-filesystem"
6
+ * - npm package@version: "@scope/name@1.2.3"
7
+ * - Local paths: "./my-server" or "/abs/path"
8
+ * - GitHub URLs (future): "github:user/repo"
9
+ */
10
+ export interface ResolvedPackage {
11
+ /** Absolute path to the extracted package directory */
12
+ path: string;
13
+ /** Package name from package.json */
14
+ name: string;
15
+ /** Package version from package.json */
16
+ version: string;
17
+ /** Source type */
18
+ source: 'npm' | 'local';
19
+ /** Whether we need to clean up (true for npm downloads) */
20
+ isTemporary: boolean;
21
+ }
22
+ /**
23
+ * Resolve a package specifier to a local directory ready for scanning.
24
+ */
25
+ export declare function resolvePackage(specifier: string): Promise<ResolvedPackage>;
26
+ /**
27
+ * Clean up a temporary package directory.
28
+ */
29
+ export declare function cleanupPackage(resolved: ResolvedPackage): Promise<void>;
30
+ //# sourceMappingURL=package-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-resolver.d.ts","sourceRoot":"","sources":["../src/package-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB;IAClB,MAAM,EAAE,KAAK,GAAG,OAAO,CAAC;IACxB,2DAA2D;IAC3D,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAmBhF;AA6CD;;GAEG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAM7E"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * NPM package resolver — download and extract npm packages for scanning.
3
+ *
4
+ * Supports:
5
+ * - npm package names: "@modelcontextprotocol/server-filesystem"
6
+ * - npm package@version: "@scope/name@1.2.3"
7
+ * - Local paths: "./my-server" or "/abs/path"
8
+ * - GitHub URLs (future): "github:user/repo"
9
+ */
10
+ import { execFile } from 'node:child_process';
11
+ import { mkdtemp, readFile, rm } from 'node:fs/promises';
12
+ import { existsSync } from 'node:fs';
13
+ import { tmpdir } from 'node:os';
14
+ import { join, resolve, isAbsolute } from 'node:path';
15
+ /**
16
+ * Resolve a package specifier to a local directory ready for scanning.
17
+ */
18
+ export async function resolvePackage(specifier) {
19
+ // Check if it's a local path (starts with . or / or is absolute, or exists on disk)
20
+ const absPath = resolve(specifier);
21
+ if (specifier.startsWith('.') || specifier.startsWith('/') || isAbsolute(specifier) || existsSync(absPath)) {
22
+ if (!existsSync(absPath)) {
23
+ throw new Error(`Local path not found: ${absPath}`);
24
+ }
25
+ const pkg = await readPackageJson(absPath);
26
+ return {
27
+ path: absPath,
28
+ name: pkg.name ?? 'unknown',
29
+ version: pkg.version ?? '0.0.0',
30
+ source: 'local',
31
+ isTemporary: false,
32
+ };
33
+ }
34
+ // npm package
35
+ return resolveFromNpm(specifier);
36
+ }
37
+ /**
38
+ * Download a package from npm registry and extract it.
39
+ */
40
+ async function resolveFromNpm(specifier) {
41
+ const tmpDir = await mkdtemp(join(tmpdir(), 'sentinel-scan-'));
42
+ try {
43
+ // Use `npm pack` to download the tarball, then extract
44
+ await execPromise('npm', ['pack', specifier, '--pack-destination', tmpDir], { cwd: tmpDir });
45
+ // Find the .tgz file
46
+ const { readdir } = await import('node:fs/promises');
47
+ const files = await readdir(tmpDir);
48
+ const tgz = files.find(f => f.endsWith('.tgz'));
49
+ if (!tgz) {
50
+ throw new Error(`npm pack did not produce a tarball for: ${specifier}`);
51
+ }
52
+ // Extract
53
+ await execPromise('tar', ['xzf', join(tmpDir, tgz), '-C', tmpDir]);
54
+ // npm pack extracts to a `package/` subdirectory
55
+ const packageDir = join(tmpDir, 'package');
56
+ if (!existsSync(packageDir)) {
57
+ throw new Error('Extracted package directory not found');
58
+ }
59
+ const pkg = await readPackageJson(packageDir);
60
+ return {
61
+ path: packageDir,
62
+ name: pkg.name ?? specifier,
63
+ version: pkg.version ?? '0.0.0',
64
+ source: 'npm',
65
+ isTemporary: true,
66
+ };
67
+ }
68
+ catch (err) {
69
+ // Clean up on failure
70
+ await rm(tmpDir, { recursive: true, force: true }).catch(() => { });
71
+ throw new Error(`Failed to resolve npm package "${specifier}": ${err.message}`);
72
+ }
73
+ }
74
+ /**
75
+ * Clean up a temporary package directory.
76
+ */
77
+ export async function cleanupPackage(resolved) {
78
+ if (resolved.isTemporary) {
79
+ // Go up one directory from 'package/' to the tmp dir
80
+ const tmpDir = join(resolved.path, '..');
81
+ await rm(tmpDir, { recursive: true, force: true }).catch(() => { });
82
+ }
83
+ }
84
+ async function readPackageJson(dir) {
85
+ try {
86
+ const raw = await readFile(join(dir, 'package.json'), 'utf-8');
87
+ return JSON.parse(raw);
88
+ }
89
+ catch {
90
+ return {};
91
+ }
92
+ }
93
+ function execPromise(cmd, args, options) {
94
+ return new Promise((resolve, reject) => {
95
+ execFile(cmd, args, { ...options, maxBuffer: 10 * 1024 * 1024, timeout: 60_000 }, (error, stdout, stderr) => {
96
+ if (error) {
97
+ reject(new Error(`${cmd} ${args.join(' ')} failed: ${stderr || error.message}`));
98
+ }
99
+ else {
100
+ resolve(stdout);
101
+ }
102
+ });
103
+ });
104
+ }
105
+ //# sourceMappingURL=package-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-resolver.js","sourceRoot":"","sources":["../src/package-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Code pattern scanner — detects dangerous patterns via regex-based static analysis.
3
+ *
4
+ * Categories:
5
+ * - dangerous-pattern: eval(), new Function(), dynamic require
6
+ * - obfuscation: hex-encoded strings, base64 payloads, packed code
7
+ * - exfiltration: HTTP calls to external domains, DNS lookups, socket connections
8
+ */
9
+ import type { Finding } from './scanner.js';
10
+ export type PatternCategory = 'dangerous-pattern' | 'obfuscation' | 'exfiltration';
11
+ export interface CodePattern {
12
+ name: string;
13
+ category: PatternCategory;
14
+ severity: Finding['severity'];
15
+ pattern: RegExp;
16
+ description: string;
17
+ }
18
+ export interface PatternScanResult {
19
+ totalFiles: number;
20
+ totalLines: number;
21
+ matchedPatterns: Array<{
22
+ pattern: string;
23
+ file: string;
24
+ line: number;
25
+ evidence: string;
26
+ }>;
27
+ findings: Finding[];
28
+ }
29
+ export declare function scanCodePatterns(packagePath: string, extensions: string[]): Promise<PatternScanResult>;
30
+ //# sourceMappingURL=pattern-scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pattern-scanner.d.ts","sourceRoot":"","sources":["../src/pattern-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,MAAM,eAAe,GAAG,mBAAmB,GAAG,aAAa,GAAG,cAAc,CAAC;AAEnF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,KAAK,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAkGD,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAAE,GACnB,OAAO,CAAC,iBAAiB,CAAC,CAsD5B"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Code pattern scanner — detects dangerous patterns via regex-based static analysis.
3
+ *
4
+ * Categories:
5
+ * - dangerous-pattern: eval(), new Function(), dynamic require
6
+ * - obfuscation: hex-encoded strings, base64 payloads, packed code
7
+ * - exfiltration: HTTP calls to external domains, DNS lookups, socket connections
8
+ */
9
+ import { readFile, readdir } from 'node:fs/promises';
10
+ import { join, relative } from 'node:path';
11
+ // ─── Pattern Definitions ─────────────────────────────────────────────
12
+ const PATTERNS = [
13
+ // Dangerous execution patterns
14
+ {
15
+ name: 'eval-usage',
16
+ category: 'dangerous-pattern',
17
+ severity: 'critical',
18
+ pattern: /\beval\s*\(/g,
19
+ description: 'eval() can execute arbitrary code — a major security risk',
20
+ },
21
+ {
22
+ name: 'new-function',
23
+ category: 'dangerous-pattern',
24
+ severity: 'critical',
25
+ pattern: /new\s+Function\s*\(/g,
26
+ description: 'new Function() is equivalent to eval()',
27
+ },
28
+ {
29
+ name: 'dynamic-import-variable',
30
+ category: 'dangerous-pattern',
31
+ severity: 'high',
32
+ pattern: /import\s*\(\s*[^'"]/g,
33
+ description: 'Dynamic import with variable — could load arbitrary modules',
34
+ },
35
+ {
36
+ name: 'child-process-exec',
37
+ category: 'dangerous-pattern',
38
+ severity: 'high',
39
+ pattern: /(?:exec|execSync|spawn|spawnSync|fork)\s*\(/g,
40
+ description: 'Shell command execution detected',
41
+ },
42
+ {
43
+ name: 'process-env-access',
44
+ category: 'dangerous-pattern',
45
+ severity: 'medium',
46
+ pattern: /process\.env\[/g,
47
+ description: 'Dynamic environment variable access',
48
+ },
49
+ // Obfuscation patterns
50
+ {
51
+ name: 'hex-string-long',
52
+ category: 'obfuscation',
53
+ severity: 'high',
54
+ pattern: /["']\\x[0-9a-fA-F]{2}(?:\\x[0-9a-fA-F]{2}){7,}["']/g,
55
+ description: 'Long hex-encoded string — possible obfuscated payload',
56
+ },
57
+ {
58
+ name: 'base64-long-literal',
59
+ category: 'obfuscation',
60
+ severity: 'medium',
61
+ pattern: /atob\s*\(\s*["'][A-Za-z0-9+/=]{50,}["']\s*\)/g,
62
+ description: 'Base64 decode of a long literal — possible hidden payload',
63
+ },
64
+ {
65
+ name: 'char-code-array',
66
+ category: 'obfuscation',
67
+ severity: 'medium',
68
+ pattern: /String\.fromCharCode\s*\(\s*(?:\d+\s*,\s*){5,}/g,
69
+ description: 'String.fromCharCode with many values — possible obfuscation',
70
+ },
71
+ // Exfiltration patterns
72
+ {
73
+ name: 'fetch-external',
74
+ category: 'exfiltration',
75
+ severity: 'high',
76
+ pattern: /(?:fetch|axios|got|node-fetch|request)\s*\(\s*[`"']https?:\/\//g,
77
+ description: 'HTTP request to external URL',
78
+ },
79
+ {
80
+ name: 'dns-lookup',
81
+ category: 'exfiltration',
82
+ severity: 'medium',
83
+ pattern: /dns\.(?:lookup|resolve|resolve4|resolve6)\s*\(/g,
84
+ description: 'DNS lookup — could be used for DNS exfiltration',
85
+ },
86
+ {
87
+ name: 'websocket-connection',
88
+ category: 'exfiltration',
89
+ severity: 'medium',
90
+ pattern: /new\s+WebSocket\s*\(/g,
91
+ description: 'WebSocket connection — could be used for data exfiltration',
92
+ },
93
+ {
94
+ name: 'net-socket',
95
+ category: 'exfiltration',
96
+ severity: 'high',
97
+ pattern: /(?:net|tls)\.(?:createConnection|connect|createServer)\s*\(/g,
98
+ description: 'Low-level network socket — could send data anywhere',
99
+ },
100
+ ];
101
+ // ─── Scanner ─────────────────────────────────────────────────────────
102
+ export async function scanCodePatterns(packagePath, extensions) {
103
+ const files = await collectSourceFiles(packagePath, extensions);
104
+ const findings = [];
105
+ const matchedPatterns = [];
106
+ let totalLines = 0;
107
+ for (const filePath of files) {
108
+ const content = await readFile(filePath, 'utf-8');
109
+ const lines = content.split('\n');
110
+ totalLines += lines.length;
111
+ const relPath = relative(packagePath, filePath);
112
+ for (const pattern of PATTERNS) {
113
+ // Reset regex state
114
+ pattern.pattern.lastIndex = 0;
115
+ for (let i = 0; i < lines.length; i++) {
116
+ const line = lines[i];
117
+ // Reset for each line
118
+ pattern.pattern.lastIndex = 0;
119
+ if (pattern.pattern.test(line)) {
120
+ const trimmed = line.trim();
121
+ // Skip matches in comments
122
+ if (trimmed.startsWith('//') || trimmed.startsWith('*') || trimmed.startsWith('/*')) {
123
+ continue;
124
+ }
125
+ matchedPatterns.push({
126
+ pattern: pattern.name,
127
+ file: relPath,
128
+ line: i + 1,
129
+ evidence: trimmed.slice(0, 120),
130
+ });
131
+ findings.push({
132
+ severity: pattern.severity,
133
+ category: pattern.category,
134
+ title: `${pattern.name} in ${relPath}:${i + 1}`,
135
+ description: pattern.description,
136
+ file: relPath,
137
+ line: i + 1,
138
+ evidence: trimmed.slice(0, 120),
139
+ });
140
+ }
141
+ }
142
+ }
143
+ }
144
+ return {
145
+ totalFiles: files.length,
146
+ totalLines,
147
+ matchedPatterns,
148
+ findings,
149
+ };
150
+ }
151
+ // ─── File Collection ─────────────────────────────────────────────────
152
+ async function collectSourceFiles(dir, extensions, basePath) {
153
+ basePath ??= dir;
154
+ const files = [];
155
+ let entries;
156
+ try {
157
+ entries = await readdir(dir, { withFileTypes: true });
158
+ }
159
+ catch {
160
+ return files;
161
+ }
162
+ for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
163
+ const fullPath = join(dir, entry.name);
164
+ const relPath = relative(basePath, fullPath);
165
+ // Skip common non-source directories
166
+ if (entry.isDirectory()) {
167
+ if (['node_modules', 'dist', '.git', '.turbo', 'coverage', '__pycache__'].includes(entry.name)) {
168
+ continue;
169
+ }
170
+ files.push(...await collectSourceFiles(fullPath, extensions, basePath));
171
+ }
172
+ else if (entry.isFile() && extensions.some(ext => entry.name.endsWith(ext))) {
173
+ files.push(fullPath);
174
+ }
175
+ }
176
+ return files;
177
+ }
178
+ //# sourceMappingURL=pattern-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pattern-scanner.js","sourceRoot":"","sources":["../src/pattern-scanner.ts"],"names":[],"mappings":"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"}