codeprobe-scanner 1.0.13 → 1.0.15

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeprobe-scanner",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "Automated vulnerability scanner with exploit verification and video evidence",
5
5
  "type": "module",
6
6
  "bin": {
@@ -110,8 +110,8 @@ export async function scanCommand(args: string[]): Promise<void> {
110
110
  try {
111
111
  const engine = createEngine();
112
112
 
113
- // Run the actual engine scan (not mocked)
114
- const report = await engine.scan(repoPath);
113
+ // Run recursive scan to find all package.json files
114
+ const report = await engine.scanRecursive(repoPath);
115
115
 
116
116
  const duration = Date.now() - startTime;
117
117
 
@@ -4,7 +4,8 @@ import { createSandbox } from "./sandbox";
4
4
  import { createMatcher } from "./matcher";
5
5
  import { createPatcher } from "./patcher";
6
6
  import { createReportBuilder } from "./report";
7
- import { Report } from "../shared/types";
7
+ import { Report, ScanCVE } from "../shared/types";
8
+ import { findAllPackageJsons } from "../shared/file-scanner";
8
9
 
9
10
  export class CodeProbeEngine {
10
11
  private parser = createParser();
@@ -18,6 +19,66 @@ export class CodeProbeEngine {
18
19
  return this.sandbox.getVideoRecorder();
19
20
  }
20
21
 
22
+ async scanRecursive(rootPath: string): Promise<Report> {
23
+ const startTime = Date.now();
24
+
25
+ try {
26
+ // Find all package.json files
27
+ console.log("šŸ” Searching for package.json files...");
28
+ const packageJsonLocations = await findAllPackageJsons(rootPath);
29
+ console.log(` Found ${packageJsonLocations.length} package.json file(s)`);
30
+
31
+ if (packageJsonLocations.length === 0) {
32
+ throw new Error("No package.json files found in the repository");
33
+ }
34
+
35
+ // Scan each location
36
+ const allCves: ScanCVE[] = [];
37
+ const allDependencies: number[] = [];
38
+ const scannedLocations: string[] = [];
39
+
40
+ for (const location of packageJsonLocations) {
41
+ console.log(`\nšŸ“‚ Scanning: ${location.path}`);
42
+ try {
43
+ const report = await this.scan(location.path);
44
+ allCves.push(...report.scan.cves);
45
+ allDependencies.push(report.scan.total_dependencies);
46
+ scannedLocations.push(location.path);
47
+ } catch (error) {
48
+ console.warn(
49
+ ` āš ļø Skipped: ${error instanceof Error ? error.message : String(error)}`
50
+ );
51
+ }
52
+ }
53
+
54
+ // Aggregate results
55
+ const riskScore = this.matcher.calculateRiskScore(allCves);
56
+ const scanDuration = Date.now() - startTime;
57
+ const totalDependencies = allDependencies.reduce((a, b) => a + b, 0);
58
+
59
+ const report = await this.reportBuilder.buildReport(
60
+ rootPath,
61
+ allCves,
62
+ riskScore,
63
+ scanDuration,
64
+ totalDependencies
65
+ );
66
+
67
+ // Add metadata about scanned locations
68
+ (report as any).scanned_locations = scannedLocations;
69
+
70
+ await this.reportBuilder.saveReport(report);
71
+
72
+ return report;
73
+ } catch (error) {
74
+ throw new Error(
75
+ `Recursive scan failed: ${
76
+ error instanceof Error ? error.message : String(error)
77
+ }`
78
+ );
79
+ }
80
+ }
81
+
21
82
  async scan(repoPath: string): Promise<Report> {
22
83
  const startTime = Date.now();
23
84
 
@@ -1,3 +1,6 @@
1
+ import { mkdir, writeFile } from "fs/promises";
2
+ import { join } from "path";
3
+
1
4
  interface ExploitVideoRecord {
2
5
  cveId: string;
3
6
  package: string;
@@ -9,29 +12,18 @@ interface ExploitVideoRecord {
9
12
  }
10
13
 
11
14
  export class VideoDBRecorder {
12
- private videoDb: any = null;
13
- private apiKey: string;
14
15
  private recordedVideos: Map<string, ExploitVideoRecord> = new Map();
16
+ private proofsDir = ".proofs";
15
17
 
16
18
  constructor() {
17
- this.apiKey = process.env.VIDEODB_API_KEY || "";
18
- this.initializeVideoDB();
19
+ this.ensureProofsDir();
19
20
  }
20
21
 
21
- private initializeVideoDB(): void {
22
- if (!this.apiKey) {
23
- return;
24
- }
25
-
22
+ private async ensureProofsDir(): Promise<void> {
26
23
  try {
27
- const videodb = require("videodb");
28
- const Constructor = videodb.VideoDb || videodb.Connection || videodb.connect;
29
- if (typeof Constructor === "function") {
30
- this.videoDb = new Constructor({ apiKey: this.apiKey });
31
- console.log("[VideoDB] āœ“ Initialized - exploit recordings enabled");
32
- }
24
+ await mkdir(this.proofsDir, { recursive: true });
33
25
  } catch {
34
- // VideoDB unavailable, video recording disabled
26
+ // Directory might already exist
35
27
  }
36
28
  }
37
29
 
@@ -42,88 +34,61 @@ export class VideoDBRecorder {
42
34
  exploitOutput: string,
43
35
  duration: number = 15
44
36
  ): Promise<ExploitVideoRecord | null> {
45
- if (!this.videoDb) {
46
- console.warn(`[VideoDB] Skipping recording for ${cveId} - not initialized`);
47
- return null;
48
- }
49
-
50
37
  try {
51
- console.log(`[VideoDB] šŸŽ„ Recording exploit for ${cveId}...`);
52
-
53
- // Create collection for this CVE
54
- const collectionName = `codeprobe-${cveId.toLowerCase().replace("-", "_")}`;
55
-
56
- // Create metadata for the video
57
- const metadata = {
58
- cve_id: cveId,
59
- package: packageName,
60
- version: version,
61
- exploit_output: exploitOutput,
62
- timestamp: new Date().toISOString(),
63
- severity: "CRITICAL",
64
- type: "rce-verification",
65
- };
38
+ console.log(`[ProofRecorder] šŸŽ„ Recording proof for ${cveId}...`);
66
39
 
67
- // In real scenario, this would capture actual sandbox screen recording
68
- // For now, we create a metadata entry with exploitOutput as the video description
69
- const videoUrl = await this.uploadExploitRecord(
40
+ const proofPath = await this.saveProof(
70
41
  cveId,
71
42
  packageName,
72
43
  version,
73
- exploitOutput,
74
- collectionName,
75
- metadata
44
+ exploitOutput
76
45
  );
77
46
 
78
47
  const record: ExploitVideoRecord = {
79
48
  cveId,
80
49
  package: packageName,
81
50
  version,
82
- videoUrl,
51
+ videoUrl: proofPath,
83
52
  duration,
84
53
  timestamp: new Date().toISOString(),
85
54
  };
86
55
 
87
56
  this.recordedVideos.set(cveId, record);
88
- console.log(`[VideoDB] āœ“ Recorded: ${videoUrl}`);
57
+ console.log(`[ProofRecorder] āœ“ Saved: ${proofPath}`);
89
58
 
90
59
  return record;
91
60
  } catch (error) {
92
61
  console.warn(
93
- `[VideoDB] Failed to record ${cveId}: ${error instanceof Error ? error.message : String(error)}`
62
+ `[ProofRecorder] Failed to save proof for ${cveId}: ${error instanceof Error ? error.message : String(error)}`
94
63
  );
95
64
  return null;
96
65
  }
97
66
  }
98
67
 
99
- private async uploadExploitRecord(
68
+ private async saveProof(
100
69
  cveId: string,
101
70
  packageName: string,
102
71
  version: string,
103
- exploitOutput: string,
104
- collectionName: string,
105
- metadata: any
72
+ exploitOutput: string
106
73
  ): Promise<string> {
107
- // Create a reference URL that links to the video
108
- // In production, this would actually upload screen recording to VideoDB
109
- const videoId = `${cveId.toLowerCase()}_${Date.now()}`;
110
- const videoUrl = `https://console.videodb.io/videos/${videoId}`;
111
-
112
- // Store metadata in cache for later retrieval
113
- const cacheKey = `videodb_${cveId}`;
114
- if (typeof globalThis !== "undefined") {
115
- (globalThis as any)[cacheKey] = {
116
- cveId,
117
- packageName,
118
- version,
119
- exploitOutput,
120
- metadata,
121
- videoUrl,
122
- createdAt: new Date().toISOString(),
123
- };
124
- }
125
-
126
- return videoUrl;
74
+ await this.ensureProofsDir();
75
+
76
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
77
+ const filename = `${cveId}_${timestamp}.json`;
78
+ const filePath = join(this.proofsDir, filename);
79
+
80
+ const proofData = {
81
+ cveId,
82
+ package: packageName,
83
+ version,
84
+ exploitOutput,
85
+ savedAt: new Date().toISOString(),
86
+ severity: "CRITICAL",
87
+ type: "rce-verification",
88
+ };
89
+
90
+ await writeFile(filePath, JSON.stringify(proofData, null, 2));
91
+ return filePath;
127
92
  }
128
93
 
129
94
  getRecordedVideos(): ExploitVideoRecord[] {
@@ -0,0 +1,50 @@
1
+ import { readdir } from "fs/promises";
2
+ import { join } from "path";
3
+
4
+ export interface PackageJsonLocation {
5
+ path: string;
6
+ depth: number;
7
+ }
8
+
9
+ export async function findAllPackageJsons(
10
+ rootPath: string,
11
+ maxDepth: number = 3,
12
+ currentDepth: number = 0,
13
+ results: PackageJsonLocation[] = []
14
+ ): Promise<PackageJsonLocation[]> {
15
+ if (currentDepth > maxDepth) {
16
+ return results;
17
+ }
18
+
19
+ try {
20
+ const entries = await readdir(rootPath, { withFileTypes: true });
21
+
22
+ for (const entry of entries) {
23
+ // Skip node_modules, .git, and other common folders
24
+ if (
25
+ entry.name.startsWith(".") ||
26
+ entry.name === "node_modules" ||
27
+ entry.name === "dist" ||
28
+ entry.name === "build" ||
29
+ entry.name === "coverage"
30
+ ) {
31
+ continue;
32
+ }
33
+
34
+ const fullPath = join(rootPath, entry.name);
35
+
36
+ if (entry.isFile() && entry.name === "package.json") {
37
+ results.push({
38
+ path: rootPath,
39
+ depth: currentDepth,
40
+ });
41
+ } else if (entry.isDirectory()) {
42
+ await findAllPackageJsons(fullPath, maxDepth, currentDepth + 1, results);
43
+ }
44
+ }
45
+ } catch {
46
+ // Permission denied or other errors - skip
47
+ }
48
+
49
+ return results;
50
+ }