@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,172 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* VC-HALL-011: Middleware Assumed But Not Matching
|
|
3
|
-
*
|
|
4
|
-
* Detects routes that appear to expect middleware protection
|
|
5
|
-
* but are not covered by the middleware matcher patterns.
|
|
6
|
-
*
|
|
7
|
-
* Severity: High
|
|
8
|
-
* Category: hallucinations
|
|
9
|
-
* Confidence: 0.70
|
|
10
|
-
*/
|
|
11
|
-
import crypto from "node:crypto";
|
|
12
|
-
import { buildRouteMap, buildMiddlewareMap, isRouteCoveredByMiddleware, } from "../proof-trace-builder.js";
|
|
13
|
-
import { mineAllIntentClaims } from "../intent-miner.js";
|
|
14
|
-
const RULE_ID = "VC-HALL-011";
|
|
15
|
-
/**
|
|
16
|
-
* Signals that a route expects middleware protection
|
|
17
|
-
*/
|
|
18
|
-
const MIDDLEWARE_EXPECTATION_SIGNALS = [
|
|
19
|
-
// Comments
|
|
20
|
-
/middleware.*protect/i,
|
|
21
|
-
/protected\s*by\s*middleware/i,
|
|
22
|
-
/middleware\s*handles?\s*auth/i,
|
|
23
|
-
/auth\s*(is|handled)\s*(by|in)\s*middleware/i,
|
|
24
|
-
// Code patterns that suggest middleware dependency
|
|
25
|
-
/withMiddleware/,
|
|
26
|
-
/requireMiddleware/,
|
|
27
|
-
/middlewareProtected/,
|
|
28
|
-
];
|
|
29
|
-
export async function scanMiddlewareAssumedNotMatching(ctx) {
|
|
30
|
-
const findings = [];
|
|
31
|
-
// Build maps
|
|
32
|
-
const routes = buildRouteMap(ctx);
|
|
33
|
-
const middlewareMap = buildMiddlewareMap(ctx);
|
|
34
|
-
// If no middleware file exists, skip this scanner
|
|
35
|
-
if (middlewareMap.length === 0) {
|
|
36
|
-
return findings;
|
|
37
|
-
}
|
|
38
|
-
const allMatchers = middlewareMap.flatMap((m) => m.matchers);
|
|
39
|
-
const intentClaims = mineAllIntentClaims(ctx, routes);
|
|
40
|
-
// Find routes that expect middleware but aren't covered
|
|
41
|
-
for (const route of routes) {
|
|
42
|
-
const isCovered = isRouteCoveredByMiddleware(route.path, allMatchers);
|
|
43
|
-
if (isCovered)
|
|
44
|
-
continue;
|
|
45
|
-
// Check if this route has signals expecting middleware
|
|
46
|
-
const expectsMiddleware = checkMiddlewareExpectation(ctx, route, intentClaims);
|
|
47
|
-
if (expectsMiddleware.expected) {
|
|
48
|
-
findings.push({
|
|
49
|
-
id: generateFindingId(route),
|
|
50
|
-
severity: "high",
|
|
51
|
-
confidence: 0.7,
|
|
52
|
-
category: "hallucinations",
|
|
53
|
-
ruleId: RULE_ID,
|
|
54
|
-
title: `Route ${route.method} ${route.path} expects middleware but is not covered`,
|
|
55
|
-
description: generateDescription(route, middlewareMap[0], expectsMiddleware.reason),
|
|
56
|
-
evidence: [
|
|
57
|
-
{
|
|
58
|
-
file: route.file,
|
|
59
|
-
startLine: route.startLine,
|
|
60
|
-
endLine: route.endLine,
|
|
61
|
-
snippet: `export async function ${route.method}(request: Request)`,
|
|
62
|
-
label: "Route expecting middleware protection",
|
|
63
|
-
},
|
|
64
|
-
...(expectsMiddleware.evidenceLocation
|
|
65
|
-
? [
|
|
66
|
-
{
|
|
67
|
-
file: expectsMiddleware.evidenceLocation.file,
|
|
68
|
-
startLine: expectsMiddleware.evidenceLocation.line,
|
|
69
|
-
endLine: expectsMiddleware.evidenceLocation.line,
|
|
70
|
-
snippet: expectsMiddleware.evidenceSnippet || "",
|
|
71
|
-
label: "Signal expecting middleware",
|
|
72
|
-
},
|
|
73
|
-
]
|
|
74
|
-
: []),
|
|
75
|
-
{
|
|
76
|
-
file: middlewareMap[0].file,
|
|
77
|
-
startLine: middlewareMap[0].startLine,
|
|
78
|
-
endLine: middlewareMap[0].startLine,
|
|
79
|
-
snippet: `matcher: ${JSON.stringify(allMatchers)}`,
|
|
80
|
-
label: "Current middleware matcher (does not cover this route)",
|
|
81
|
-
},
|
|
82
|
-
],
|
|
83
|
-
remediation: {
|
|
84
|
-
recommendedFix: generateRemediation(route, allMatchers),
|
|
85
|
-
},
|
|
86
|
-
fingerprint: generateFingerprint(route),
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return findings;
|
|
91
|
-
}
|
|
92
|
-
function checkMiddlewareExpectation(ctx, route, claims) {
|
|
93
|
-
// Check intent claims for middleware protection
|
|
94
|
-
const middlewareClaims = claims.filter((c) => c.type === "MIDDLEWARE_PROTECTED" &&
|
|
95
|
-
(c.targetRouteId === route.routeId || c.scope === "global" || c.location.file === route.file));
|
|
96
|
-
if (middlewareClaims.length > 0) {
|
|
97
|
-
const claim = middlewareClaims[0];
|
|
98
|
-
return {
|
|
99
|
-
expected: true,
|
|
100
|
-
reason: "Intent claim indicates middleware protection expected",
|
|
101
|
-
evidenceLocation: {
|
|
102
|
-
file: claim.location.file,
|
|
103
|
-
line: claim.location.startLine,
|
|
104
|
-
},
|
|
105
|
-
evidenceSnippet: claim.textEvidence,
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
// Check source file for middleware expectation signals
|
|
109
|
-
const sourceFile = ctx.helpers.parseFile(require("path").join(ctx.repoRoot, route.file));
|
|
110
|
-
if (sourceFile) {
|
|
111
|
-
const fullText = sourceFile.getFullText();
|
|
112
|
-
for (const signal of MIDDLEWARE_EXPECTATION_SIGNALS) {
|
|
113
|
-
const match = fullText.match(signal);
|
|
114
|
-
if (match) {
|
|
115
|
-
const pos = match.index || 0;
|
|
116
|
-
const line = sourceFile.getLineAndColumnAtPos(pos).line;
|
|
117
|
-
return {
|
|
118
|
-
expected: true,
|
|
119
|
-
reason: "Code pattern suggests middleware protection expected",
|
|
120
|
-
evidenceLocation: {
|
|
121
|
-
file: route.file,
|
|
122
|
-
line,
|
|
123
|
-
},
|
|
124
|
-
evidenceSnippet: match[0],
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
// Check if auth claims exist but no auth check in handler
|
|
130
|
-
const authClaims = claims.filter((c) => c.type === "AUTH_ENFORCED" &&
|
|
131
|
-
c.source === "comment" &&
|
|
132
|
-
(c.targetRouteId === route.routeId || c.location.file === route.file));
|
|
133
|
-
if (authClaims.length > 0) {
|
|
134
|
-
// Check if the handler has its own auth check
|
|
135
|
-
const handlers = ctx.helpers.findRouteHandlers(sourceFile);
|
|
136
|
-
const handler = handlers.find((h) => h.method === route.method);
|
|
137
|
-
if (handler && !ctx.helpers.containsAuthCheck(handler.functionNode)) {
|
|
138
|
-
// Auth is claimed but not in handler - might expect middleware
|
|
139
|
-
const claim = authClaims[0];
|
|
140
|
-
return {
|
|
141
|
-
expected: true,
|
|
142
|
-
reason: "Auth claimed in comment but not in handler - may expect middleware",
|
|
143
|
-
evidenceLocation: {
|
|
144
|
-
file: claim.location.file,
|
|
145
|
-
line: claim.location.startLine,
|
|
146
|
-
},
|
|
147
|
-
evidenceSnippet: claim.textEvidence,
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
return { expected: false, reason: "" };
|
|
152
|
-
}
|
|
153
|
-
function generateDescription(route, middleware, reason) {
|
|
154
|
-
return (`The route ${route.method} ${route.path} shows signals that it expects middleware protection, ` +
|
|
155
|
-
`but the middleware matcher in ${middleware.file} does not cover this path. ` +
|
|
156
|
-
`${reason}. This could leave the route unprotected.`);
|
|
157
|
-
}
|
|
158
|
-
function generateRemediation(route, currentMatchers) {
|
|
159
|
-
const suggestedPattern = route.path.includes("/api/")
|
|
160
|
-
? "/api/:path*"
|
|
161
|
-
: `${route.path}/:path*`;
|
|
162
|
-
return (`Update the middleware matcher to include this route. ` +
|
|
163
|
-
`Current matchers: ${JSON.stringify(currentMatchers)}. ` +
|
|
164
|
-
`Consider adding "${suggestedPattern}" or add explicit auth in the handler.`);
|
|
165
|
-
}
|
|
166
|
-
function generateFindingId(route) {
|
|
167
|
-
return `f-${crypto.randomUUID().slice(0, 8)}`;
|
|
168
|
-
}
|
|
169
|
-
function generateFingerprint(route) {
|
|
170
|
-
const data = `${RULE_ID}:${route.file}:${route.method}:${route.path}`;
|
|
171
|
-
return `sha256:${crypto.createHash("sha256").update(data).digest("hex")}`;
|
|
172
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* VC-HALL-012: Validation Claimed But Missing/Ignored
|
|
3
|
-
*
|
|
4
|
-
* Detects routes where validation is claimed (via comments, imports,
|
|
5
|
-
* or identifiers) but is either not implemented or the validated
|
|
6
|
-
* result is not used.
|
|
7
|
-
*
|
|
8
|
-
* Severity: Medium
|
|
9
|
-
* Category: hallucinations
|
|
10
|
-
* Confidence: 0.80
|
|
11
|
-
*/
|
|
12
|
-
import type { Finding } from "@vibecheck/schema";
|
|
13
|
-
import type { ScanContext } from "../../scanners/types.js";
|
|
14
|
-
export declare function scanValidationClaimedMissing(ctx: ScanContext): Promise<Finding[]>;
|
|
15
|
-
//# sourceMappingURL=validation-claimed-missing.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"validation-claimed-missing.d.ts","sourceRoot":"","sources":["../../../src/phase3/scanners/validation-claimed-missing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAA0B,MAAM,yBAAyB,CAAC;AAMnF,wBAAsB,4BAA4B,CAChD,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,OAAO,EAAE,CAAC,CAmGpB"}
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* VC-HALL-012: Validation Claimed But Missing/Ignored
|
|
3
|
-
*
|
|
4
|
-
* Detects routes where validation is claimed (via comments, imports,
|
|
5
|
-
* or identifiers) but is either not implemented or the validated
|
|
6
|
-
* result is not used.
|
|
7
|
-
*
|
|
8
|
-
* Severity: Medium
|
|
9
|
-
* Category: hallucinations
|
|
10
|
-
* Confidence: 0.80
|
|
11
|
-
*/
|
|
12
|
-
import crypto from "node:crypto";
|
|
13
|
-
import path from "node:path";
|
|
14
|
-
import { buildRouteMap, buildAllProofTraces } from "../proof-trace-builder.js";
|
|
15
|
-
import { mineAllIntentClaims } from "../intent-miner.js";
|
|
16
|
-
const RULE_ID = "VC-HALL-012";
|
|
17
|
-
export async function scanValidationClaimedMissing(ctx) {
|
|
18
|
-
const findings = [];
|
|
19
|
-
// Build route map and proof traces
|
|
20
|
-
const routes = buildRouteMap(ctx);
|
|
21
|
-
const proofTraces = buildAllProofTraces(ctx, routes);
|
|
22
|
-
const intentClaims = mineAllIntentClaims(ctx, routes);
|
|
23
|
-
// Find validation claims
|
|
24
|
-
const validationClaims = intentClaims.filter((c) => c.type === "INPUT_VALIDATED");
|
|
25
|
-
// Group claims by file for efficiency
|
|
26
|
-
const claimsByFile = new Map();
|
|
27
|
-
for (const claim of validationClaims) {
|
|
28
|
-
const existing = claimsByFile.get(claim.location.file) || [];
|
|
29
|
-
existing.push(claim);
|
|
30
|
-
claimsByFile.set(claim.location.file, existing);
|
|
31
|
-
}
|
|
32
|
-
// Check each file with validation claims
|
|
33
|
-
for (const [file, claims] of claimsByFile) {
|
|
34
|
-
const sourceFile = ctx.helpers.parseFile(path.join(ctx.repoRoot, file));
|
|
35
|
-
if (!sourceFile)
|
|
36
|
-
continue;
|
|
37
|
-
// Find routes in this file
|
|
38
|
-
const fileRoutes = routes.filter((r) => r.file === file);
|
|
39
|
-
const handlers = ctx.helpers.findRouteHandlers(sourceFile);
|
|
40
|
-
for (const handler of handlers) {
|
|
41
|
-
const route = fileRoutes.find((r) => r.method === handler.method);
|
|
42
|
-
if (!route)
|
|
43
|
-
continue;
|
|
44
|
-
// Check if this handler should have validation
|
|
45
|
-
const relevantClaims = claims.filter((c) => c.targetRouteId === route.routeId ||
|
|
46
|
-
c.scope === "module" ||
|
|
47
|
-
c.scope === "global" ||
|
|
48
|
-
(c.location.startLine <= handler.startLine &&
|
|
49
|
-
c.location.endLine >= handler.startLine - 5) // Claim is near handler
|
|
50
|
-
);
|
|
51
|
-
if (relevantClaims.length === 0)
|
|
52
|
-
continue;
|
|
53
|
-
// Check actual validation status
|
|
54
|
-
const validationUsage = ctx.helpers.findValidationUsage(handler.functionNode);
|
|
55
|
-
// Case 1: No validation at all despite claims
|
|
56
|
-
if (validationUsage.length === 0) {
|
|
57
|
-
findings.push(createFinding(route, relevantClaims[0], "missing", "Validation is claimed but no validation library usage found in handler"));
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
// Case 2: Validation exists but result not assigned
|
|
61
|
-
const unassigned = validationUsage.filter((v) => !v.resultAssigned);
|
|
62
|
-
if (unassigned.length > 0) {
|
|
63
|
-
findings.push(createFinding(route, relevantClaims[0], "ignored_result", "Validation is called but the result is not assigned to a variable", {
|
|
64
|
-
file: route.file,
|
|
65
|
-
line: unassigned[0].line,
|
|
66
|
-
snippet: ctx.helpers.getNodeText(unassigned[0].node).slice(0, 100),
|
|
67
|
-
}));
|
|
68
|
-
continue;
|
|
69
|
-
}
|
|
70
|
-
// Case 3: Validation result assigned but raw body still used
|
|
71
|
-
const rawBodyUsed = validationUsage.filter((v) => v.rawBodyUsedAfter);
|
|
72
|
-
if (rawBodyUsed.length > 0) {
|
|
73
|
-
findings.push(createFinding(route, relevantClaims[0], "bypassed", "Validation is performed but raw request body is used afterward instead of validated data", {
|
|
74
|
-
file: route.file,
|
|
75
|
-
line: rawBodyUsed[0].line,
|
|
76
|
-
snippet: ctx.helpers.getNodeText(rawBodyUsed[0].node).slice(0, 100),
|
|
77
|
-
}));
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
// Also check for validation imports that are never used
|
|
82
|
-
findings.push(...checkUnusedValidationImports(ctx, routes, intentClaims));
|
|
83
|
-
return findings;
|
|
84
|
-
}
|
|
85
|
-
function createFinding(route, claim, issueType, description, additionalEvidence) {
|
|
86
|
-
const evidence = [
|
|
87
|
-
{
|
|
88
|
-
file: claim.location.file,
|
|
89
|
-
startLine: claim.location.startLine,
|
|
90
|
-
endLine: claim.location.endLine,
|
|
91
|
-
snippet: claim.textEvidence,
|
|
92
|
-
label: `Validation claim (${claim.source})`,
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
file: route.file,
|
|
96
|
-
startLine: route.startLine,
|
|
97
|
-
endLine: route.endLine,
|
|
98
|
-
snippet: `${route.method} ${route.path}`,
|
|
99
|
-
label: "Route handler",
|
|
100
|
-
},
|
|
101
|
-
];
|
|
102
|
-
if (additionalEvidence) {
|
|
103
|
-
evidence.push({
|
|
104
|
-
file: additionalEvidence.file,
|
|
105
|
-
startLine: additionalEvidence.line,
|
|
106
|
-
endLine: additionalEvidence.line,
|
|
107
|
-
snippet: additionalEvidence.snippet,
|
|
108
|
-
label: issueType === "ignored_result" ? "Unused validation call" : "Raw body usage",
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
return {
|
|
112
|
-
id: `f-${crypto.randomUUID().slice(0, 8)}`,
|
|
113
|
-
severity: "medium",
|
|
114
|
-
confidence: 0.8,
|
|
115
|
-
category: "hallucinations",
|
|
116
|
-
ruleId: RULE_ID,
|
|
117
|
-
title: generateTitle(route, issueType),
|
|
118
|
-
description,
|
|
119
|
-
evidence,
|
|
120
|
-
remediation: {
|
|
121
|
-
recommendedFix: generateRemediation(issueType),
|
|
122
|
-
},
|
|
123
|
-
fingerprint: generateFingerprint(route, issueType),
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
function generateTitle(route, issueType) {
|
|
127
|
-
switch (issueType) {
|
|
128
|
-
case "missing":
|
|
129
|
-
return `Validation claimed but missing in ${route.method} ${route.path}`;
|
|
130
|
-
case "ignored_result":
|
|
131
|
-
return `Validation result ignored in ${route.method} ${route.path}`;
|
|
132
|
-
case "bypassed":
|
|
133
|
-
return `Validation bypassed in ${route.method} ${route.path}`;
|
|
134
|
-
default:
|
|
135
|
-
return `Validation issue in ${route.method} ${route.path}`;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
function generateRemediation(issueType) {
|
|
139
|
-
switch (issueType) {
|
|
140
|
-
case "missing":
|
|
141
|
-
return ("Implement validation using Zod, Yup, or Joi. " +
|
|
142
|
-
"Example: `const validated = schema.parse(await request.json());` " +
|
|
143
|
-
"Then use `validated` instead of the raw request body.");
|
|
144
|
-
case "ignored_result":
|
|
145
|
-
return ("Assign the validation result to a variable and use it: " +
|
|
146
|
-
"`const validated = schema.parse(body);` " +
|
|
147
|
-
"Then pass `validated` to database operations.");
|
|
148
|
-
case "bypassed":
|
|
149
|
-
return ("Replace usage of raw `body`, `req.body`, or `request.json()` result " +
|
|
150
|
-
"with the validated data. Using raw input after validation defeats its purpose.");
|
|
151
|
-
default:
|
|
152
|
-
return "Ensure validation is properly implemented and the validated result is used.";
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
function checkUnusedValidationImports(ctx, routes, claims) {
|
|
156
|
-
const findings = [];
|
|
157
|
-
// Find import-based validation claims
|
|
158
|
-
const importClaims = claims.filter((c) => c.type === "INPUT_VALIDATED" && c.source === "import");
|
|
159
|
-
for (const claim of importClaims) {
|
|
160
|
-
const sourceFile = ctx.helpers.parseFile(path.join(ctx.repoRoot, claim.location.file));
|
|
161
|
-
if (!sourceFile)
|
|
162
|
-
continue;
|
|
163
|
-
// Check if validation schemas/methods are actually defined and used
|
|
164
|
-
const hasSchemas = ctx.helpers.hasValidationSchemas(sourceFile);
|
|
165
|
-
if (!hasSchemas) {
|
|
166
|
-
// Validation library imported but no schemas defined
|
|
167
|
-
const fileRoutes = routes.filter((r) => r.file === claim.location.file);
|
|
168
|
-
if (fileRoutes.length > 0) {
|
|
169
|
-
findings.push({
|
|
170
|
-
id: `f-${crypto.randomUUID().slice(0, 8)}`,
|
|
171
|
-
severity: "medium",
|
|
172
|
-
confidence: 0.7,
|
|
173
|
-
category: "hallucinations",
|
|
174
|
-
ruleId: RULE_ID,
|
|
175
|
-
title: `Validation library imported but no schemas defined in ${claim.location.file}`,
|
|
176
|
-
description: "A validation library is imported suggesting validation intent, " +
|
|
177
|
-
"but no validation schemas are defined in the file. " +
|
|
178
|
-
"This could be dead code or incomplete implementation.",
|
|
179
|
-
evidence: [
|
|
180
|
-
{
|
|
181
|
-
file: claim.location.file,
|
|
182
|
-
startLine: claim.location.startLine,
|
|
183
|
-
endLine: claim.location.endLine,
|
|
184
|
-
snippet: claim.textEvidence,
|
|
185
|
-
label: "Validation import",
|
|
186
|
-
},
|
|
187
|
-
],
|
|
188
|
-
remediation: {
|
|
189
|
-
recommendedFix: "Define validation schemas using the imported library, or remove the unused import.",
|
|
190
|
-
},
|
|
191
|
-
fingerprint: `sha256:${crypto
|
|
192
|
-
.createHash("sha256")
|
|
193
|
-
.update(`${RULE_ID}:${claim.location.file}:import_unused`)
|
|
194
|
-
.digest("hex")}`,
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
return findings;
|
|
200
|
-
}
|
|
201
|
-
function generateFingerprint(route, issueType) {
|
|
202
|
-
const data = `${RULE_ID}:${route.file}:${route.method}:${issueType}`;
|
|
203
|
-
return `sha256:${crypto.createHash("sha256").update(data).digest("hex")}`;
|
|
204
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { Finding } from "@vibecheck/schema";
|
|
2
|
-
import type { ScanContext } from "../types.js";
|
|
3
|
-
/**
|
|
4
|
-
* VC-ABUSE-001 to VC-ABUSE-004: Compute Abuse Detection
|
|
5
|
-
*
|
|
6
|
-
* Detects compute-intensive endpoints that may be vulnerable to abuse:
|
|
7
|
-
* - AI/LLM generation endpoints
|
|
8
|
-
* - Code execution endpoints
|
|
9
|
-
* - File processing endpoints
|
|
10
|
-
* - Expensive API endpoints
|
|
11
|
-
*
|
|
12
|
-
* Checks for missing enforcement:
|
|
13
|
-
* - Authentication
|
|
14
|
-
* - Rate limiting
|
|
15
|
-
* - Request size limits
|
|
16
|
-
* - Timeouts
|
|
17
|
-
* - Input validation
|
|
18
|
-
*/
|
|
19
|
-
export declare function scanComputeAbuse(context: ScanContext): Promise<Finding[]>;
|
|
20
|
-
//# sourceMappingURL=compute-abuse.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compute-abuse.d.ts","sourceRoot":"","sources":["../../../src/scanners/abuse/compute-abuse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAqC,MAAM,mBAAmB,CAAC;AACpF,OAAO,KAAK,EAAE,WAAW,EAA8B,MAAM,aAAa,CAAC;AAyW3E;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CA8H/E"}
|