@quantracode/vibecheck 0.0.1 → 0.0.2
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/README.md +6 -6
- package/dist/index.d.ts +0 -2
- package/dist/index.js +7902 -8
- package/package.json +13 -7
- package/dist/__tests__/cli.test.d.ts +0 -2
- package/dist/__tests__/cli.test.d.ts.map +0 -1
- package/dist/__tests__/cli.test.js +0 -243
- package/dist/__tests__/fixtures/safe-app/app/api/users/route.js +0 -36
- package/dist/__tests__/fixtures/vulnerable-app/app/api/users/route.js +0 -28
- package/dist/__tests__/fixtures/vulnerable-app/lib/config.d.ts +0 -4
- package/dist/__tests__/fixtures/vulnerable-app/lib/config.d.ts.map +0 -1
- package/dist/__tests__/fixtures/vulnerable-app/lib/config.js +0 -6
- package/dist/__tests__/scanners/env-config.test.d.ts +0 -2
- package/dist/__tests__/scanners/env-config.test.d.ts.map +0 -1
- package/dist/__tests__/scanners/env-config.test.js +0 -142
- package/dist/__tests__/scanners/nextjs-middleware.test.d.ts +0 -2
- package/dist/__tests__/scanners/nextjs-middleware.test.d.ts.map +0 -1
- package/dist/__tests__/scanners/nextjs-middleware.test.js +0 -193
- package/dist/__tests__/scanners/scanner-packs.test.d.ts +0 -2
- package/dist/__tests__/scanners/scanner-packs.test.d.ts.map +0 -1
- package/dist/__tests__/scanners/scanner-packs.test.js +0 -126
- package/dist/__tests__/scanners/unused-security-imports.test.d.ts +0 -2
- package/dist/__tests__/scanners/unused-security-imports.test.d.ts.map +0 -1
- package/dist/__tests__/scanners/unused-security-imports.test.js +0 -145
- package/dist/commands/demo-artifact.d.ts +0 -7
- package/dist/commands/demo-artifact.d.ts.map +0 -1
- package/dist/commands/demo-artifact.js +0 -322
- package/dist/commands/evaluate.d.ts +0 -30
- package/dist/commands/evaluate.d.ts.map +0 -1
- package/dist/commands/evaluate.js +0 -258
- package/dist/commands/explain.d.ts +0 -12
- package/dist/commands/explain.d.ts.map +0 -1
- package/dist/commands/explain.js +0 -214
- package/dist/commands/index.d.ts +0 -7
- package/dist/commands/index.d.ts.map +0 -1
- package/dist/commands/index.js +0 -6
- package/dist/commands/intent.d.ts +0 -21
- package/dist/commands/intent.d.ts.map +0 -1
- package/dist/commands/intent.js +0 -192
- package/dist/commands/scan.d.ts +0 -44
- package/dist/commands/scan.d.ts.map +0 -1
- package/dist/commands/scan.js +0 -497
- package/dist/commands/waivers.d.ts +0 -30
- package/dist/commands/waivers.d.ts.map +0 -1
- package/dist/commands/waivers.js +0 -249
- package/dist/index.d.ts.map +0 -1
- package/dist/phase3/index.d.ts +0 -11
- package/dist/phase3/index.d.ts.map +0 -1
- package/dist/phase3/index.js +0 -12
- package/dist/phase3/intent-miner.d.ts +0 -32
- package/dist/phase3/intent-miner.d.ts.map +0 -1
- package/dist/phase3/intent-miner.js +0 -323
- package/dist/phase3/proof-trace-builder.d.ts +0 -42
- package/dist/phase3/proof-trace-builder.d.ts.map +0 -1
- package/dist/phase3/proof-trace-builder.js +0 -441
- package/dist/phase3/scanners/auth-by-ui-server-gap.d.ts +0 -15
- package/dist/phase3/scanners/auth-by-ui-server-gap.d.ts.map +0 -1
- package/dist/phase3/scanners/auth-by-ui-server-gap.js +0 -237
- package/dist/phase3/scanners/comment-claim-unproven.d.ts +0 -14
- package/dist/phase3/scanners/comment-claim-unproven.d.ts.map +0 -1
- package/dist/phase3/scanners/comment-claim-unproven.js +0 -161
- package/dist/phase3/scanners/index.d.ts +0 -31
- package/dist/phase3/scanners/index.d.ts.map +0 -1
- package/dist/phase3/scanners/index.js +0 -40
- package/dist/phase3/scanners/middleware-assumed-not-matching.d.ts +0 -14
- package/dist/phase3/scanners/middleware-assumed-not-matching.d.ts.map +0 -1
- package/dist/phase3/scanners/middleware-assumed-not-matching.js +0 -172
- package/dist/phase3/scanners/validation-claimed-missing.d.ts +0 -15
- package/dist/phase3/scanners/validation-claimed-missing.d.ts.map +0 -1
- package/dist/phase3/scanners/validation-claimed-missing.js +0 -204
- package/dist/scanners/abuse/compute-abuse.d.ts +0 -20
- package/dist/scanners/abuse/compute-abuse.d.ts.map +0 -1
- package/dist/scanners/abuse/compute-abuse.js +0 -509
- package/dist/scanners/abuse/index.d.ts +0 -12
- package/dist/scanners/abuse/index.d.ts.map +0 -1
- package/dist/scanners/abuse/index.js +0 -15
- package/dist/scanners/auth/index.d.ts +0 -5
- package/dist/scanners/auth/index.d.ts.map +0 -1
- package/dist/scanners/auth/index.js +0 -10
- package/dist/scanners/auth/middleware-gap.d.ts +0 -22
- package/dist/scanners/auth/middleware-gap.d.ts.map +0 -1
- package/dist/scanners/auth/middleware-gap.js +0 -203
- package/dist/scanners/auth/unprotected-api-route.d.ts +0 -12
- package/dist/scanners/auth/unprotected-api-route.d.ts.map +0 -1
- package/dist/scanners/auth/unprotected-api-route.js +0 -126
- package/dist/scanners/config/index.d.ts +0 -5
- package/dist/scanners/config/index.d.ts.map +0 -1
- package/dist/scanners/config/index.js +0 -10
- package/dist/scanners/config/insecure-defaults.d.ts +0 -12
- package/dist/scanners/config/insecure-defaults.d.ts.map +0 -1
- package/dist/scanners/config/insecure-defaults.js +0 -77
- package/dist/scanners/config/undocumented-env.d.ts +0 -24
- package/dist/scanners/config/undocumented-env.d.ts.map +0 -1
- package/dist/scanners/config/undocumented-env.js +0 -159
- package/dist/scanners/crypto/index.d.ts +0 -6
- package/dist/scanners/crypto/index.d.ts.map +0 -1
- package/dist/scanners/crypto/index.js +0 -11
- package/dist/scanners/crypto/jwt-decode-unverified.d.ts +0 -14
- package/dist/scanners/crypto/jwt-decode-unverified.d.ts.map +0 -1
- package/dist/scanners/crypto/jwt-decode-unverified.js +0 -87
- package/dist/scanners/crypto/math-random-tokens.d.ts +0 -13
- package/dist/scanners/crypto/math-random-tokens.d.ts.map +0 -1
- package/dist/scanners/crypto/math-random-tokens.js +0 -80
- package/dist/scanners/crypto/weak-hashing.d.ts +0 -11
- package/dist/scanners/crypto/weak-hashing.d.ts.map +0 -1
- package/dist/scanners/crypto/weak-hashing.js +0 -95
- package/dist/scanners/env-config.d.ts +0 -24
- package/dist/scanners/env-config.d.ts.map +0 -1
- package/dist/scanners/env-config.js +0 -164
- package/dist/scanners/hallucinations/index.d.ts +0 -4
- package/dist/scanners/hallucinations/index.d.ts.map +0 -1
- package/dist/scanners/hallucinations/index.js +0 -8
- package/dist/scanners/hallucinations/unused-security-imports.d.ts +0 -36
- package/dist/scanners/hallucinations/unused-security-imports.d.ts.map +0 -1
- package/dist/scanners/hallucinations/unused-security-imports.js +0 -309
- package/dist/scanners/helpers/ast-helpers.d.ts +0 -6
- package/dist/scanners/helpers/ast-helpers.d.ts.map +0 -1
- package/dist/scanners/helpers/ast-helpers.js +0 -945
- package/dist/scanners/helpers/context-builder.d.ts +0 -17
- package/dist/scanners/helpers/context-builder.d.ts.map +0 -1
- package/dist/scanners/helpers/context-builder.js +0 -148
- package/dist/scanners/helpers/index.d.ts +0 -3
- package/dist/scanners/helpers/index.d.ts.map +0 -1
- package/dist/scanners/helpers/index.js +0 -2
- package/dist/scanners/index.d.ts +0 -30
- package/dist/scanners/index.d.ts.map +0 -1
- package/dist/scanners/index.js +0 -102
- package/dist/scanners/middleware/index.d.ts +0 -4
- package/dist/scanners/middleware/index.d.ts.map +0 -1
- package/dist/scanners/middleware/index.js +0 -7
- package/dist/scanners/middleware/missing-rate-limit.d.ts +0 -13
- package/dist/scanners/middleware/missing-rate-limit.d.ts.map +0 -1
- package/dist/scanners/middleware/missing-rate-limit.js +0 -140
- package/dist/scanners/network/cors-misconfiguration.d.ts +0 -14
- package/dist/scanners/network/cors-misconfiguration.d.ts.map +0 -1
- package/dist/scanners/network/cors-misconfiguration.js +0 -89
- package/dist/scanners/network/index.d.ts +0 -7
- package/dist/scanners/network/index.d.ts.map +0 -1
- package/dist/scanners/network/index.js +0 -18
- package/dist/scanners/network/missing-timeout.d.ts +0 -15
- package/dist/scanners/network/missing-timeout.d.ts.map +0 -1
- package/dist/scanners/network/missing-timeout.js +0 -93
- package/dist/scanners/network/open-redirect.d.ts +0 -15
- package/dist/scanners/network/open-redirect.d.ts.map +0 -1
- package/dist/scanners/network/open-redirect.js +0 -88
- package/dist/scanners/network/ssrf-prone-fetch.d.ts +0 -12
- package/dist/scanners/network/ssrf-prone-fetch.d.ts.map +0 -1
- package/dist/scanners/network/ssrf-prone-fetch.js +0 -90
- package/dist/scanners/nextjs-middleware.d.ts +0 -26
- package/dist/scanners/nextjs-middleware.d.ts.map +0 -1
- package/dist/scanners/nextjs-middleware.js +0 -246
- package/dist/scanners/privacy/debug-flags.d.ts +0 -13
- package/dist/scanners/privacy/debug-flags.d.ts.map +0 -1
- package/dist/scanners/privacy/debug-flags.js +0 -124
- package/dist/scanners/privacy/index.d.ts +0 -6
- package/dist/scanners/privacy/index.d.ts.map +0 -1
- package/dist/scanners/privacy/index.js +0 -11
- package/dist/scanners/privacy/over-broad-response.d.ts +0 -15
- package/dist/scanners/privacy/over-broad-response.d.ts.map +0 -1
- package/dist/scanners/privacy/over-broad-response.js +0 -109
- package/dist/scanners/privacy/sensitive-logging.d.ts +0 -11
- package/dist/scanners/privacy/sensitive-logging.d.ts.map +0 -1
- package/dist/scanners/privacy/sensitive-logging.js +0 -78
- package/dist/scanners/types.d.ts +0 -456
- package/dist/scanners/types.d.ts.map +0 -1
- package/dist/scanners/types.js +0 -16
- package/dist/scanners/unused-security-imports.d.ts +0 -34
- package/dist/scanners/unused-security-imports.d.ts.map +0 -1
- package/dist/scanners/unused-security-imports.js +0 -206
- package/dist/scanners/uploads/index.d.ts +0 -5
- package/dist/scanners/uploads/index.d.ts.map +0 -1
- package/dist/scanners/uploads/index.js +0 -9
- package/dist/scanners/uploads/missing-constraints.d.ts +0 -15
- package/dist/scanners/uploads/missing-constraints.d.ts.map +0 -1
- package/dist/scanners/uploads/missing-constraints.js +0 -109
- package/dist/scanners/uploads/public-path.d.ts +0 -11
- package/dist/scanners/uploads/public-path.d.ts.map +0 -1
- package/dist/scanners/uploads/public-path.js +0 -87
- package/dist/scanners/validation/client-side-only.d.ts +0 -14
- package/dist/scanners/validation/client-side-only.d.ts.map +0 -1
- package/dist/scanners/validation/client-side-only.js +0 -140
- package/dist/scanners/validation/ignored-validation.d.ts +0 -12
- package/dist/scanners/validation/ignored-validation.d.ts.map +0 -1
- package/dist/scanners/validation/ignored-validation.js +0 -119
- package/dist/scanners/validation/index.d.ts +0 -5
- package/dist/scanners/validation/index.d.ts.map +0 -1
- package/dist/scanners/validation/index.js +0 -9
- package/dist/utils/exclude-patterns.d.ts +0 -35
- package/dist/utils/exclude-patterns.d.ts.map +0 -1
- package/dist/utils/exclude-patterns.js +0 -78
- package/dist/utils/file-utils.d.ts +0 -37
- package/dist/utils/file-utils.d.ts.map +0 -1
- package/dist/utils/file-utils.js +0 -77
- package/dist/utils/fingerprint.d.ts +0 -25
- package/dist/utils/fingerprint.d.ts.map +0 -1
- package/dist/utils/fingerprint.js +0 -28
- package/dist/utils/git-info.d.ts +0 -14
- package/dist/utils/git-info.d.ts.map +0 -1
- package/dist/utils/git-info.js +0 -55
- package/dist/utils/index.d.ts +0 -4
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -3
- package/dist/utils/progress.d.ts +0 -42
- package/dist/utils/progress.d.ts.map +0 -1
- package/dist/utils/progress.js +0 -165
- package/dist/utils/sarif-formatter.d.ts +0 -92
- package/dist/utils/sarif-formatter.d.ts.map +0 -1
- package/dist/utils/sarif-formatter.js +0 -172
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { ScanContext, FileProgressCallback } from "../types.js";
|
|
2
|
-
/**
|
|
3
|
-
* Options for building scan context
|
|
4
|
-
*/
|
|
5
|
-
export interface ScanContextOptions {
|
|
6
|
-
/** Additional glob patterns to exclude */
|
|
7
|
-
excludePatterns?: string[];
|
|
8
|
-
/** Include test files in scan */
|
|
9
|
-
includeTests?: boolean;
|
|
10
|
-
/** Progress callback for file processing */
|
|
11
|
-
onFileProgress?: FileProgressCallback;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Build a complete ScanContext for scanner use
|
|
15
|
-
*/
|
|
16
|
-
export declare function buildScanContext(repoRoot: string, options?: ScanContextOptions): Promise<ScanContext>;
|
|
17
|
-
//# sourceMappingURL=context-builder.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"context-builder.d.ts","sourceRoot":"","sources":["../../../src/scanners/helpers/context-builder.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAA0E,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAE7I;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,0CAA0C;IAC1C,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,iCAAiC;IACjC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,4CAA4C;IAC5C,cAAc,CAAC,EAAE,oBAAoB,CAAC;CACvC;AAyKD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,WAAW,CAAC,CAmBtB"}
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { findFiles, readJsonSync, resolvePath, fileExists, readFileSync } from "../../utils/file-utils.js";
|
|
2
|
-
import { createAstHelpers } from "./ast-helpers.js";
|
|
3
|
-
import { mergeExcludes, normalizePatterns } from "../../utils/exclude-patterns.js";
|
|
4
|
-
/**
|
|
5
|
-
* Detect framework from package.json dependencies
|
|
6
|
-
*/
|
|
7
|
-
function detectFramework(deps, devDeps) {
|
|
8
|
-
const allDeps = { ...deps, ...devDeps };
|
|
9
|
-
if (allDeps["next"])
|
|
10
|
-
return "next";
|
|
11
|
-
if (allDeps["express"])
|
|
12
|
-
return "express";
|
|
13
|
-
if (allDeps["fastify"])
|
|
14
|
-
return "fastify";
|
|
15
|
-
if (allDeps["koa"])
|
|
16
|
-
return "koa";
|
|
17
|
-
return "unknown";
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Build file index for quick lookups
|
|
21
|
-
*/
|
|
22
|
-
async function buildFileIndex(repoRoot, options = {}) {
|
|
23
|
-
// Build exclude patterns from defaults + custom
|
|
24
|
-
const customExcludes = options.excludePatterns ?? [];
|
|
25
|
-
const ignorePatterns = normalizePatterns(mergeExcludes(customExcludes, { includeTests: options.includeTests }));
|
|
26
|
-
// Find all source files
|
|
27
|
-
const allSourceFiles = await findFiles(["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"], { cwd: repoRoot, ignore: ignorePatterns });
|
|
28
|
-
// TypeScript files only
|
|
29
|
-
const tsTsxFiles = allSourceFiles.filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
30
|
-
// Config files
|
|
31
|
-
const configFiles = await findFiles([".env*", "**/*.config.*", "**/config.*"], { cwd: repoRoot, ignore: ignorePatterns });
|
|
32
|
-
// Next.js route files (App Router)
|
|
33
|
-
const routeFiles = await findFiles(["**/route.ts", "**/route.js", "src/**/route.ts", "src/**/route.js"], { cwd: repoRoot, ignore: ignorePatterns });
|
|
34
|
-
// API route files specifically
|
|
35
|
-
const apiRouteFiles = routeFiles.filter((f) => f.includes("/api/") || f.includes("\\api\\"));
|
|
36
|
-
// Find middleware file
|
|
37
|
-
let middlewareFile;
|
|
38
|
-
const middlewareCandidates = [
|
|
39
|
-
"middleware.ts",
|
|
40
|
-
"middleware.js",
|
|
41
|
-
"src/middleware.ts",
|
|
42
|
-
"src/middleware.js",
|
|
43
|
-
];
|
|
44
|
-
for (const candidate of middlewareCandidates) {
|
|
45
|
-
if (fileExists(resolvePath(repoRoot, candidate))) {
|
|
46
|
-
middlewareFile = candidate;
|
|
47
|
-
break;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return {
|
|
51
|
-
allSourceFiles,
|
|
52
|
-
tsTsxFiles,
|
|
53
|
-
configFiles,
|
|
54
|
-
routeFiles,
|
|
55
|
-
middlewareFile,
|
|
56
|
-
apiRouteFiles,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Build repository metadata from package.json
|
|
61
|
-
*/
|
|
62
|
-
function buildRepoMeta(repoRoot) {
|
|
63
|
-
const pkgPath = resolvePath(repoRoot, "package.json");
|
|
64
|
-
const pkg = readJsonSync(pkgPath);
|
|
65
|
-
const dependencies = pkg?.dependencies ?? {};
|
|
66
|
-
const devDependencies = pkg?.devDependencies ?? {};
|
|
67
|
-
const allDeps = { ...dependencies, ...devDependencies };
|
|
68
|
-
return {
|
|
69
|
-
dependencies,
|
|
70
|
-
devDependencies,
|
|
71
|
-
framework: detectFramework(dependencies, devDependencies),
|
|
72
|
-
hasTypeScript: Boolean(allDeps["typescript"]),
|
|
73
|
-
hasNextAuth: Boolean(allDeps["next-auth"]),
|
|
74
|
-
hasPrisma: Boolean(allDeps["prisma"] || allDeps["@prisma/client"]),
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Build framework hints from dependencies
|
|
79
|
-
*/
|
|
80
|
-
function buildFrameworkHints(repoRoot, deps, devDeps) {
|
|
81
|
-
const allDeps = { ...deps, ...devDeps };
|
|
82
|
-
return {
|
|
83
|
-
isNext: Boolean(allDeps["next"]),
|
|
84
|
-
isExpress: Boolean(allDeps["express"]),
|
|
85
|
-
hasPrisma: Boolean(allDeps["prisma"] || allDeps["@prisma/client"]),
|
|
86
|
-
hasNextAuth: Boolean(allDeps["next-auth"]),
|
|
87
|
-
hasMulter: Boolean(allDeps["multer"]),
|
|
88
|
-
hasFormidable: Boolean(allDeps["formidable"]),
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Parse Prisma schema file if it exists
|
|
93
|
-
*/
|
|
94
|
-
function parsePrismaSchema(repoRoot) {
|
|
95
|
-
const schemaPath = resolvePath(repoRoot, "prisma/schema.prisma");
|
|
96
|
-
const content = readFileSync(schemaPath);
|
|
97
|
-
if (!content)
|
|
98
|
-
return undefined;
|
|
99
|
-
const models = new Map();
|
|
100
|
-
const sensitiveFieldPatterns = /password|hash|token|secret|apikey|api_key|private_key|credential/i;
|
|
101
|
-
// Parse model blocks
|
|
102
|
-
const modelRegex = /model\s+(\w+)\s*\{([^}]+)\}/g;
|
|
103
|
-
let match;
|
|
104
|
-
while ((match = modelRegex.exec(content)) !== null) {
|
|
105
|
-
const modelName = match[1];
|
|
106
|
-
const modelBody = match[2];
|
|
107
|
-
// Extract field names (first word on each non-empty line)
|
|
108
|
-
const fields = [];
|
|
109
|
-
const lines = modelBody.split("\n");
|
|
110
|
-
for (const line of lines) {
|
|
111
|
-
const trimmed = line.trim();
|
|
112
|
-
if (!trimmed || trimmed.startsWith("//") || trimmed.startsWith("@@"))
|
|
113
|
-
continue;
|
|
114
|
-
const fieldMatch = trimmed.match(/^(\w+)\s+/);
|
|
115
|
-
if (fieldMatch) {
|
|
116
|
-
fields.push(fieldMatch[1]);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
const hasSensitiveFields = fields.some((f) => sensitiveFieldPatterns.test(f));
|
|
120
|
-
models.set(modelName.toLowerCase(), {
|
|
121
|
-
name: modelName,
|
|
122
|
-
fields,
|
|
123
|
-
hasSensitiveFields,
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
return { models };
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Build a complete ScanContext for scanner use
|
|
130
|
-
*/
|
|
131
|
-
export async function buildScanContext(repoRoot, options = {}) {
|
|
132
|
-
const [fileIndex, repoMeta] = await Promise.all([
|
|
133
|
-
buildFileIndex(repoRoot, options),
|
|
134
|
-
Promise.resolve(buildRepoMeta(repoRoot)),
|
|
135
|
-
]);
|
|
136
|
-
const helpers = createAstHelpers(repoRoot, fileIndex.allSourceFiles.length, options.onFileProgress);
|
|
137
|
-
const frameworkHints = buildFrameworkHints(repoRoot, repoMeta.dependencies, repoMeta.devDependencies);
|
|
138
|
-
const prismaSchemaInfo = parsePrismaSchema(repoRoot);
|
|
139
|
-
return {
|
|
140
|
-
repoRoot,
|
|
141
|
-
fileIndex,
|
|
142
|
-
repoMeta,
|
|
143
|
-
helpers,
|
|
144
|
-
frameworkHints,
|
|
145
|
-
prismaSchemaInfo,
|
|
146
|
-
onFileProgress: options.onFileProgress,
|
|
147
|
-
};
|
|
148
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scanners/helpers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/scanners/index.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
export * from "./types.js";
|
|
2
|
-
export { buildScanContext, createAstHelpers, type ScanContextOptions } from "./helpers/index.js";
|
|
3
|
-
export { authPack } from "./auth/index.js";
|
|
4
|
-
export { validationPack } from "./validation/index.js";
|
|
5
|
-
export { privacyPack } from "./privacy/index.js";
|
|
6
|
-
export { configPack } from "./config/index.js";
|
|
7
|
-
export { networkPack } from "./network/index.js";
|
|
8
|
-
export { hallucinationsPack } from "./hallucinations/index.js";
|
|
9
|
-
export { middlewarePack } from "./middleware/index.js";
|
|
10
|
-
export { cryptoPack } from "./crypto/index.js";
|
|
11
|
-
export { uploadsPack } from "./uploads/index.js";
|
|
12
|
-
export { abusePack } from "./abuse/index.js";
|
|
13
|
-
import type { ScannerPack, Scanner } from "./types.js";
|
|
14
|
-
/**
|
|
15
|
-
* All available scanner packs
|
|
16
|
-
*/
|
|
17
|
-
export declare const ALL_SCANNER_PACKS: ScannerPack[];
|
|
18
|
-
/**
|
|
19
|
-
* All available scanners (flattened from packs)
|
|
20
|
-
*/
|
|
21
|
-
export declare const ALL_SCANNERS: Scanner[];
|
|
22
|
-
/**
|
|
23
|
-
* Get a scanner pack by ID
|
|
24
|
-
*/
|
|
25
|
-
export declare function getScannerPack(id: string): ScannerPack | undefined;
|
|
26
|
-
/**
|
|
27
|
-
* Get all rule IDs covered by the scanners
|
|
28
|
-
*/
|
|
29
|
-
export declare const SUPPORTED_RULES: readonly ["VC-AUTH-001", "VC-AUTH-INFO-001", "VC-MW-001", "VC-VAL-001", "VC-VAL-002", "VC-PRIV-001", "VC-PRIV-002", "VC-PRIV-003", "VC-CONFIG-001", "VC-CONFIG-002", "VC-NET-001", "VC-NET-002", "VC-NET-003", "VC-NET-004", "VC-HALL-001", "VC-HALL-002", "VC-HALL-010", "VC-HALL-011", "VC-HALL-012", "VC-AUTH-010", "VC-RATE-001", "VC-CRYPTO-001", "VC-CRYPTO-002", "VC-CRYPTO-003", "VC-UP-001", "VC-UP-002", "VC-ABUSE-001", "VC-ABUSE-002", "VC-ABUSE-003", "VC-ABUSE-004"];
|
|
30
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scanners/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAC;AAG3B,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAGjG,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG7C,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAkBvD;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,WAAW,EAc1C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,OAAO,EAAuD,CAAC;AAE1F;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAElE;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,odA2ClB,CAAC"}
|
package/dist/scanners/index.js
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
// Export types
|
|
2
|
-
export * from "./types.js";
|
|
3
|
-
// Export helpers
|
|
4
|
-
export { buildScanContext, createAstHelpers } from "./helpers/index.js";
|
|
5
|
-
// Export scanner packs
|
|
6
|
-
export { authPack } from "./auth/index.js";
|
|
7
|
-
export { validationPack } from "./validation/index.js";
|
|
8
|
-
export { privacyPack } from "./privacy/index.js";
|
|
9
|
-
export { configPack } from "./config/index.js";
|
|
10
|
-
export { networkPack } from "./network/index.js";
|
|
11
|
-
export { hallucinationsPack } from "./hallucinations/index.js";
|
|
12
|
-
export { middlewarePack } from "./middleware/index.js";
|
|
13
|
-
export { cryptoPack } from "./crypto/index.js";
|
|
14
|
-
export { uploadsPack } from "./uploads/index.js";
|
|
15
|
-
export { abusePack } from "./abuse/index.js";
|
|
16
|
-
import { authPack } from "./auth/index.js";
|
|
17
|
-
import { validationPack } from "./validation/index.js";
|
|
18
|
-
import { privacyPack } from "./privacy/index.js";
|
|
19
|
-
import { configPack } from "./config/index.js";
|
|
20
|
-
import { networkPack } from "./network/index.js";
|
|
21
|
-
import { hallucinationsPack } from "./hallucinations/index.js";
|
|
22
|
-
import { middlewarePack } from "./middleware/index.js";
|
|
23
|
-
import { cryptoPack } from "./crypto/index.js";
|
|
24
|
-
import { uploadsPack } from "./uploads/index.js";
|
|
25
|
-
import { abusePack } from "./abuse/index.js";
|
|
26
|
-
// Phase 3 scanners
|
|
27
|
-
import { hallucinationsPack as hallucinationsPackPhase3, authPackPhase3, } from "../phase3/index.js";
|
|
28
|
-
/**
|
|
29
|
-
* All available scanner packs
|
|
30
|
-
*/
|
|
31
|
-
export const ALL_SCANNER_PACKS = [
|
|
32
|
-
authPack,
|
|
33
|
-
validationPack,
|
|
34
|
-
privacyPack,
|
|
35
|
-
configPack,
|
|
36
|
-
networkPack,
|
|
37
|
-
hallucinationsPack,
|
|
38
|
-
middlewarePack,
|
|
39
|
-
cryptoPack,
|
|
40
|
-
uploadsPack,
|
|
41
|
-
abusePack,
|
|
42
|
-
// Phase 3 packs
|
|
43
|
-
hallucinationsPackPhase3,
|
|
44
|
-
authPackPhase3,
|
|
45
|
-
];
|
|
46
|
-
/**
|
|
47
|
-
* All available scanners (flattened from packs)
|
|
48
|
-
*/
|
|
49
|
-
export const ALL_SCANNERS = ALL_SCANNER_PACKS.flatMap((pack) => pack.scanners);
|
|
50
|
-
/**
|
|
51
|
-
* Get a scanner pack by ID
|
|
52
|
-
*/
|
|
53
|
-
export function getScannerPack(id) {
|
|
54
|
-
return ALL_SCANNER_PACKS.find((pack) => pack.id === id);
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Get all rule IDs covered by the scanners
|
|
58
|
-
*/
|
|
59
|
-
export const SUPPORTED_RULES = [
|
|
60
|
-
// Auth pack
|
|
61
|
-
"VC-AUTH-001",
|
|
62
|
-
"VC-AUTH-INFO-001",
|
|
63
|
-
"VC-MW-001",
|
|
64
|
-
// Validation pack
|
|
65
|
-
"VC-VAL-001",
|
|
66
|
-
"VC-VAL-002",
|
|
67
|
-
// Privacy pack
|
|
68
|
-
"VC-PRIV-001",
|
|
69
|
-
"VC-PRIV-002",
|
|
70
|
-
"VC-PRIV-003",
|
|
71
|
-
// Config pack
|
|
72
|
-
"VC-CONFIG-001",
|
|
73
|
-
"VC-CONFIG-002",
|
|
74
|
-
// Network pack
|
|
75
|
-
"VC-NET-001",
|
|
76
|
-
"VC-NET-002",
|
|
77
|
-
"VC-NET-003",
|
|
78
|
-
"VC-NET-004",
|
|
79
|
-
// Hallucinations pack (Phase 1-2)
|
|
80
|
-
"VC-HALL-001",
|
|
81
|
-
"VC-HALL-002",
|
|
82
|
-
// Hallucinations pack (Phase 3)
|
|
83
|
-
"VC-HALL-010",
|
|
84
|
-
"VC-HALL-011",
|
|
85
|
-
"VC-HALL-012",
|
|
86
|
-
// Auth pack (Phase 3)
|
|
87
|
-
"VC-AUTH-010",
|
|
88
|
-
// Middleware pack
|
|
89
|
-
"VC-RATE-001",
|
|
90
|
-
// Crypto pack
|
|
91
|
-
"VC-CRYPTO-001",
|
|
92
|
-
"VC-CRYPTO-002",
|
|
93
|
-
"VC-CRYPTO-003",
|
|
94
|
-
// Uploads pack
|
|
95
|
-
"VC-UP-001",
|
|
96
|
-
"VC-UP-002",
|
|
97
|
-
// Abuse pack
|
|
98
|
-
"VC-ABUSE-001",
|
|
99
|
-
"VC-ABUSE-002",
|
|
100
|
-
"VC-ABUSE-003",
|
|
101
|
-
"VC-ABUSE-004",
|
|
102
|
-
];
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scanners/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,eAAO,MAAM,cAAc,EAAE,WAI5B,CAAC;AAEF,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { Finding } from "@vibecheck/schema";
|
|
2
|
-
import type { ScanContext } from "../types.js";
|
|
3
|
-
/**
|
|
4
|
-
* VC-RATE-001: Missing rate limiting on public state-changing endpoints
|
|
5
|
-
*
|
|
6
|
-
* Only consider POST/PUT/PATCH/DELETE route handlers that:
|
|
7
|
-
* - appear unauthenticated (no auth check)
|
|
8
|
-
* - AND include a sink: DB write, email send, payment, or login/signup keywords
|
|
9
|
-
*
|
|
10
|
-
* If no rate-limit signals found in handler or middleware, flag it.
|
|
11
|
-
*/
|
|
12
|
-
export declare function scanMissingRateLimit(context: ScanContext): Promise<Finding[]>;
|
|
13
|
-
//# sourceMappingURL=missing-rate-limit.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"missing-rate-limit.d.ts","sourceRoot":"","sources":["../../../src/scanners/middleware/missing-rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAgB/C;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAkInF"}
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import { resolvePath } from "../../utils/file-utils.js";
|
|
2
|
-
import { generateFingerprint, generateFindingId } from "../../utils/fingerprint.js";
|
|
3
|
-
const RULE_ID = "VC-RATE-001";
|
|
4
|
-
/**
|
|
5
|
-
* State-changing HTTP methods
|
|
6
|
-
*/
|
|
7
|
-
const STATE_CHANGING_METHODS = ["POST", "PUT", "PATCH", "DELETE"];
|
|
8
|
-
/**
|
|
9
|
-
* Keywords that suggest sensitive operations
|
|
10
|
-
*/
|
|
11
|
-
const SENSITIVE_SINK_PATTERNS = /create|insert|update|delete|send|email|mail|payment|charge|login|signup|register|auth|password|reset/i;
|
|
12
|
-
/**
|
|
13
|
-
* VC-RATE-001: Missing rate limiting on public state-changing endpoints
|
|
14
|
-
*
|
|
15
|
-
* Only consider POST/PUT/PATCH/DELETE route handlers that:
|
|
16
|
-
* - appear unauthenticated (no auth check)
|
|
17
|
-
* - AND include a sink: DB write, email send, payment, or login/signup keywords
|
|
18
|
-
*
|
|
19
|
-
* If no rate-limit signals found in handler or middleware, flag it.
|
|
20
|
-
*/
|
|
21
|
-
export async function scanMissingRateLimit(context) {
|
|
22
|
-
const { repoRoot, fileIndex, helpers } = context;
|
|
23
|
-
const findings = [];
|
|
24
|
-
// Check if middleware has rate limiting
|
|
25
|
-
let middlewareHasRateLimit = false;
|
|
26
|
-
if (fileIndex.middlewareFile) {
|
|
27
|
-
const middlewarePath = resolvePath(repoRoot, fileIndex.middlewareFile);
|
|
28
|
-
const middlewareSource = helpers.parseFile(middlewarePath);
|
|
29
|
-
if (middlewareSource) {
|
|
30
|
-
middlewareHasRateLimit = helpers.hasRateLimitSignals(middlewareSource);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
// If middleware already has rate limiting, skip this scanner
|
|
34
|
-
if (middlewareHasRateLimit) {
|
|
35
|
-
return findings;
|
|
36
|
-
}
|
|
37
|
-
// Scan API route files
|
|
38
|
-
for (const relPath of fileIndex.apiRouteFiles) {
|
|
39
|
-
const absPath = resolvePath(repoRoot, relPath);
|
|
40
|
-
const sourceFile = helpers.parseFile(absPath);
|
|
41
|
-
if (!sourceFile)
|
|
42
|
-
continue;
|
|
43
|
-
// Check if file has rate limiting
|
|
44
|
-
const fileHasRateLimit = helpers.hasRateLimitSignals(sourceFile);
|
|
45
|
-
if (fileHasRateLimit)
|
|
46
|
-
continue;
|
|
47
|
-
const handlers = helpers.findRouteHandlers(sourceFile);
|
|
48
|
-
for (const handler of handlers) {
|
|
49
|
-
// Only check state-changing methods
|
|
50
|
-
if (!STATE_CHANGING_METHODS.includes(handler.method)) {
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
// Check for auth - only flag unauthenticated endpoints
|
|
54
|
-
const hasAuth = helpers.containsAuthCheck(handler.functionNode);
|
|
55
|
-
if (hasAuth)
|
|
56
|
-
continue;
|
|
57
|
-
// Find sensitive sinks
|
|
58
|
-
const dbSinks = helpers.findDbSinks(handler.functionNode);
|
|
59
|
-
const handlerText = helpers.getNodeText(handler.functionNode);
|
|
60
|
-
const hasSensitiveSink = dbSinks.length > 0 || SENSITIVE_SINK_PATTERNS.test(handlerText);
|
|
61
|
-
if (!hasSensitiveSink)
|
|
62
|
-
continue;
|
|
63
|
-
const evidence = [
|
|
64
|
-
{
|
|
65
|
-
file: relPath,
|
|
66
|
-
startLine: handler.startLine,
|
|
67
|
-
endLine: handler.endLine,
|
|
68
|
-
snippet: handlerText.slice(0, 200) + "...",
|
|
69
|
-
label: `Unauthenticated ${handler.method} handler without rate limiting`,
|
|
70
|
-
},
|
|
71
|
-
];
|
|
72
|
-
// Add sink evidence
|
|
73
|
-
if (dbSinks.length > 0) {
|
|
74
|
-
evidence.push({
|
|
75
|
-
file: relPath,
|
|
76
|
-
startLine: dbSinks[0].line,
|
|
77
|
-
endLine: dbSinks[0].line,
|
|
78
|
-
snippet: dbSinks[0].snippet,
|
|
79
|
-
label: `Sensitive operation: ${dbSinks[0].kind}.${dbSinks[0].operation}`,
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
const fingerprint = generateFingerprint({
|
|
83
|
-
ruleId: RULE_ID,
|
|
84
|
-
file: relPath,
|
|
85
|
-
symbol: handler.method,
|
|
86
|
-
startLine: handler.startLine,
|
|
87
|
-
});
|
|
88
|
-
findings.push({
|
|
89
|
-
id: generateFindingId({
|
|
90
|
-
ruleId: RULE_ID,
|
|
91
|
-
file: relPath,
|
|
92
|
-
symbol: handler.method,
|
|
93
|
-
startLine: handler.startLine,
|
|
94
|
-
}),
|
|
95
|
-
ruleId: RULE_ID,
|
|
96
|
-
title: `Missing rate limiting on public ${handler.method} endpoint`,
|
|
97
|
-
description: `This public (unauthenticated) ${handler.method} handler performs sensitive operations but lacks rate limiting. Without rate limiting, attackers can abuse this endpoint for credential stuffing, brute force attacks, or denial of service by overwhelming your resources.`,
|
|
98
|
-
severity: "medium",
|
|
99
|
-
confidence: 0.65,
|
|
100
|
-
category: "middleware",
|
|
101
|
-
evidence,
|
|
102
|
-
remediation: {
|
|
103
|
-
recommendedFix: `Add rate limiting to protect against abuse. Consider using @upstash/ratelimit for serverless, or express-rate-limit for Express apps.`,
|
|
104
|
-
patch: `// Using @upstash/ratelimit with Vercel KV:
|
|
105
|
-
import { Ratelimit } from "@upstash/ratelimit";
|
|
106
|
-
import { kv } from "@vercel/kv";
|
|
107
|
-
|
|
108
|
-
const ratelimit = new Ratelimit({
|
|
109
|
-
redis: kv,
|
|
110
|
-
limiter: Ratelimit.slidingWindow(10, "60 s"), // 10 requests per minute
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
export async function POST(request: Request) {
|
|
114
|
-
const ip = request.headers.get("x-forwarded-for") ?? "127.0.0.1";
|
|
115
|
-
const { success, limit, reset, remaining } = await ratelimit.limit(ip);
|
|
116
|
-
|
|
117
|
-
if (!success) {
|
|
118
|
-
return new Response("Too Many Requests", {
|
|
119
|
-
status: 429,
|
|
120
|
-
headers: {
|
|
121
|
-
"X-RateLimit-Limit": limit.toString(),
|
|
122
|
-
"X-RateLimit-Remaining": remaining.toString(),
|
|
123
|
-
"X-RateLimit-Reset": reset.toString(),
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// ... rest of handler
|
|
129
|
-
}`,
|
|
130
|
-
},
|
|
131
|
-
links: {
|
|
132
|
-
owasp: "https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html",
|
|
133
|
-
cwe: "https://cwe.mitre.org/data/definitions/770.html",
|
|
134
|
-
},
|
|
135
|
-
fingerprint,
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return findings;
|
|
140
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { Finding } from "@vibecheck/schema";
|
|
2
|
-
import type { ScanContext } from "../types.js";
|
|
3
|
-
/**
|
|
4
|
-
* VC-NET-003: Over-permissive CORS with credentials
|
|
5
|
-
*
|
|
6
|
-
* Detects CORS configurations that combine:
|
|
7
|
-
* - allowCredentials: true (or "Access-Control-Allow-Credentials: true")
|
|
8
|
-
* AND
|
|
9
|
-
* - allowOrigin: "*" (or reflects arbitrary origin unsafely)
|
|
10
|
-
*
|
|
11
|
-
* Two-signal: must see both wildcard origin AND credentials enabled
|
|
12
|
-
*/
|
|
13
|
-
export declare function scanCorsMisconfiguration(context: ScanContext): Promise<Finding[]>;
|
|
14
|
-
//# sourceMappingURL=cors-misconfiguration.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cors-misconfiguration.d.ts","sourceRoot":"","sources":["../../../src/scanners/network/cors-misconfiguration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM/C;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAkFvF"}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { resolvePath } from "../../utils/file-utils.js";
|
|
2
|
-
import { generateFingerprint, generateFindingId } from "../../utils/fingerprint.js";
|
|
3
|
-
const RULE_ID = "VC-NET-003";
|
|
4
|
-
/**
|
|
5
|
-
* VC-NET-003: Over-permissive CORS with credentials
|
|
6
|
-
*
|
|
7
|
-
* Detects CORS configurations that combine:
|
|
8
|
-
* - allowCredentials: true (or "Access-Control-Allow-Credentials: true")
|
|
9
|
-
* AND
|
|
10
|
-
* - allowOrigin: "*" (or reflects arbitrary origin unsafely)
|
|
11
|
-
*
|
|
12
|
-
* Two-signal: must see both wildcard origin AND credentials enabled
|
|
13
|
-
*/
|
|
14
|
-
export async function scanCorsMisconfiguration(context) {
|
|
15
|
-
const { repoRoot, fileIndex, helpers } = context;
|
|
16
|
-
const findings = [];
|
|
17
|
-
// Scan all source files for CORS configuration
|
|
18
|
-
for (const relPath of fileIndex.allSourceFiles) {
|
|
19
|
-
const absPath = resolvePath(repoRoot, relPath);
|
|
20
|
-
const sourceFile = helpers.parseFile(absPath);
|
|
21
|
-
if (!sourceFile)
|
|
22
|
-
continue;
|
|
23
|
-
const corsConfigs = helpers.findCorsConfig(sourceFile);
|
|
24
|
-
for (const config of corsConfigs) {
|
|
25
|
-
// Two-signal: only flag when BOTH wildcard origin AND credentials
|
|
26
|
-
if (!config.hasWildcardOrigin || !config.hasCredentials) {
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
const evidence = [
|
|
30
|
-
{
|
|
31
|
-
file: relPath,
|
|
32
|
-
startLine: config.line,
|
|
33
|
-
endLine: config.line,
|
|
34
|
-
snippet: config.snippet,
|
|
35
|
-
label: `CORS with origin: "${config.originValue}" and credentials: ${config.credentialsValue}`,
|
|
36
|
-
},
|
|
37
|
-
];
|
|
38
|
-
const fingerprint = generateFingerprint({
|
|
39
|
-
ruleId: RULE_ID,
|
|
40
|
-
file: relPath,
|
|
41
|
-
symbol: "cors",
|
|
42
|
-
startLine: config.line,
|
|
43
|
-
});
|
|
44
|
-
findings.push({
|
|
45
|
-
id: generateFindingId({
|
|
46
|
-
ruleId: RULE_ID,
|
|
47
|
-
file: relPath,
|
|
48
|
-
symbol: "cors",
|
|
49
|
-
startLine: config.line,
|
|
50
|
-
}),
|
|
51
|
-
ruleId: RULE_ID,
|
|
52
|
-
title: "Over-permissive CORS with credentials",
|
|
53
|
-
description: `The CORS configuration allows credentials (cookies, auth headers) to be sent with requests from any origin (*). This is dangerous because it allows any website to make authenticated requests to your API on behalf of logged-in users, enabling CSRF-like attacks. Browsers will actually block this specific combination, but the intent suggests a security misunderstanding.`,
|
|
54
|
-
severity: "high",
|
|
55
|
-
confidence: 0.9,
|
|
56
|
-
category: "network",
|
|
57
|
-
evidence,
|
|
58
|
-
remediation: {
|
|
59
|
-
recommendedFix: `When using credentials, you must specify explicit allowed origins instead of "*". Use an allowlist of trusted domains.`,
|
|
60
|
-
patch: `// Instead of:
|
|
61
|
-
// cors({ origin: "*", credentials: true })
|
|
62
|
-
|
|
63
|
-
// Use an allowlist:
|
|
64
|
-
const allowedOrigins = [
|
|
65
|
-
'https://app.example.com',
|
|
66
|
-
'https://admin.example.com',
|
|
67
|
-
];
|
|
68
|
-
|
|
69
|
-
app.use(cors({
|
|
70
|
-
origin: (origin, callback) => {
|
|
71
|
-
if (!origin || allowedOrigins.includes(origin)) {
|
|
72
|
-
callback(null, true);
|
|
73
|
-
} else {
|
|
74
|
-
callback(new Error('Not allowed by CORS'));
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
credentials: true,
|
|
78
|
-
}));`,
|
|
79
|
-
},
|
|
80
|
-
links: {
|
|
81
|
-
cwe: "https://cwe.mitre.org/data/definitions/942.html",
|
|
82
|
-
owasp: "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/07-Testing_Cross_Origin_Resource_Sharing",
|
|
83
|
-
},
|
|
84
|
-
fingerprint,
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
return findings;
|
|
89
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { ScannerPack } from "../types.js";
|
|
2
|
-
export declare const networkPack: ScannerPack;
|
|
3
|
-
export { scanSsrfProneFetch } from "./ssrf-prone-fetch.js";
|
|
4
|
-
export { scanOpenRedirect } from "./open-redirect.js";
|
|
5
|
-
export { scanCorsMisconfiguration } from "./cors-misconfiguration.js";
|
|
6
|
-
export { scanMissingTimeout } from "./missing-timeout.js";
|
|
7
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scanners/network/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM/C,eAAO,MAAM,WAAW,EAAE,WASzB,CAAC;AAEF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { scanSsrfProneFetch } from "./ssrf-prone-fetch.js";
|
|
2
|
-
import { scanOpenRedirect } from "./open-redirect.js";
|
|
3
|
-
import { scanCorsMisconfiguration } from "./cors-misconfiguration.js";
|
|
4
|
-
import { scanMissingTimeout } from "./missing-timeout.js";
|
|
5
|
-
export const networkPack = {
|
|
6
|
-
id: "network",
|
|
7
|
-
name: "Network Security",
|
|
8
|
-
scanners: [
|
|
9
|
-
scanSsrfProneFetch,
|
|
10
|
-
scanOpenRedirect,
|
|
11
|
-
scanCorsMisconfiguration,
|
|
12
|
-
scanMissingTimeout,
|
|
13
|
-
],
|
|
14
|
-
};
|
|
15
|
-
export { scanSsrfProneFetch } from "./ssrf-prone-fetch.js";
|
|
16
|
-
export { scanOpenRedirect } from "./open-redirect.js";
|
|
17
|
-
export { scanCorsMisconfiguration } from "./cors-misconfiguration.js";
|
|
18
|
-
export { scanMissingTimeout } from "./missing-timeout.js";
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Finding } from "@vibecheck/schema";
|
|
2
|
-
import type { ScanContext } from "../types.js";
|
|
3
|
-
/**
|
|
4
|
-
* VC-NET-004: Missing request timeout on outbound calls
|
|
5
|
-
*
|
|
6
|
-
* Detects axios/fetch usage without explicit timeout:
|
|
7
|
-
* - axios(...) without timeout option
|
|
8
|
-
* - fetch(...) without AbortController / timeout wrapper
|
|
9
|
-
*
|
|
10
|
-
* Precision rule:
|
|
11
|
-
* - Only flag when outbound call is inside a route handler (app/api/**) AND
|
|
12
|
-
* - Call appears to hit non-localhost URL (string literal starting http)
|
|
13
|
-
*/
|
|
14
|
-
export declare function scanMissingTimeout(context: ScanContext): Promise<Finding[]>;
|
|
15
|
-
//# sourceMappingURL=missing-timeout.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"missing-timeout.d.ts","sourceRoot":"","sources":["../../../src/scanners/network/missing-timeout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM/C;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAqFjF"}
|