xploitscan-shared-rules 1.2.1 → 1.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.
package/dist/index.d.cts CHANGED
@@ -1,3 +1,6 @@
1
+ import { ParseResult } from '@babel/parser';
2
+ import { File, Node, CallExpression, ObjectExpression, BinaryExpression } from '@babel/types';
3
+
1
4
  type Severity = "critical" | "high" | "medium" | "low" | "info";
2
5
  type Confidence = "high" | "medium" | "low";
3
6
  interface Finding {
@@ -209,6 +212,54 @@ declare const hardcodedVercelToken: CustomRule;
209
212
  declare const hardcodedSupabaseServiceRole: CustomRule;
210
213
  declare const hardcodedVaultToken: CustomRule;
211
214
  declare const hardcodedPineconeKey: CustomRule;
215
+ declare const hardcodedCohereKey: CustomRule;
216
+ declare const hardcodedReplicateKey: CustomRule;
217
+ declare const hardcodedMistralKey: CustomRule;
218
+ declare const hardcodedTogetherKey: CustomRule;
219
+ declare const hardcodedGroqKey: CustomRule;
220
+ declare const hardcodedFireworksKey: CustomRule;
221
+ declare const hardcodedPostmarkKey: CustomRule;
222
+ declare const hardcodedResendKey: CustomRule;
223
+ declare const hardcodedLoopsKey: CustomRule;
224
+ declare const hardcodedCloudflareToken: CustomRule;
225
+ declare const hardcodedFastlyToken: CustomRule;
226
+ declare const hardcodedNetlifyToken: CustomRule;
227
+ declare const hardcodedRailwayToken: CustomRule;
228
+ declare const hardcodedFlyToken: CustomRule;
229
+ declare const hardcodedAlgoliaAdminKey: CustomRule;
230
+ declare const hardcodedQdrantKey: CustomRule;
231
+ declare const hardcodedWeaviateKey: CustomRule;
232
+ declare const hardcodedLinearKey: CustomRule;
233
+ declare const hardcodedNotionKey: CustomRule;
234
+ declare const hardcodedDiscordToken: CustomRule;
235
+ declare const hardcodedIntercomToken: CustomRule;
236
+ declare const hardcodedSentryAuthToken: CustomRule;
237
+ declare const hardcodedLogtailToken: CustomRule;
238
+ declare const hardcodedHighlightKey: CustomRule;
239
+ declare const hardcodedPlivoToken: CustomRule;
240
+ declare const ghaPullRequestTargetCheckout: CustomRule;
241
+ declare const ghaPermissionsWriteAll: CustomRule;
242
+ declare const ghaExpressionInjection: CustomRule;
243
+ declare const ghaThirdPartyActionWithSecrets: CustomRule;
244
+ declare const dockerfileADDInsteadOfCOPY: CustomRule;
245
+ declare const dockerfileUnverifiedShellPipe: CustomRule;
246
+ declare const dockerfileMissingHealthcheck: CustomRule;
247
+ declare const pyRequestsVerifyFalse: CustomRule;
248
+ declare const pyJinja2AutoescapeOff: CustomRule;
249
+ declare const pyTempfileMktemp: CustomRule;
250
+ declare const pyDjangoMarkSafe: CustomRule;
251
+ declare const pyParamikoAutoAdd: CustomRule;
252
+ declare const pyDjangoAllowedHostsWildcard: CustomRule;
253
+ declare const pyJWTDecodeWeakConfig: CustomRule;
254
+ declare const llmPromptInjection: CustomRule;
255
+ declare const llmSystemPromptInjection: CustomRule;
256
+ declare const llmOutputAsHTML: CustomRule;
257
+ declare const vectorStoreQueryNoUserFilter: CustomRule;
258
+ declare const vectorStoreUpsertNoMetadata: CustomRule;
259
+ declare const llmCallNoMaxTokens: CustomRule;
260
+ declare const graphqlNoDepthLimit: CustomRule;
261
+ declare const graphqlNoComplexityLimit: CustomRule;
262
+ declare const graphqlCSRFDisabled: CustomRule;
212
263
  declare const secretInURLParam: CustomRule;
213
264
  declare const secretLoggedToConsole: CustomRule;
214
265
  declare const secretInErrorResponse: CustomRule;
@@ -289,4 +340,115 @@ declare function scanEntropy(files: {
289
340
  content: string;
290
341
  }[]): Finding[];
291
342
 
292
- export { type AIFilterResult, type Confidence, type CustomRule, type DetectedFramework, type FilteredFinding, type Finding, type GradeResult, type RuleMatch, type SecurityGrade, type Severity, allCustomRules, allRules, androidDebuggable, blockingMainThread, calculateGrade, callbackHell, clickjacking, clientComponentSecret, clientSideAuth, commandInjection, complianceMap, consoleLogProduction, corsLocalhost, corsServerless, corsWildcard, dangerousInnerHTML, deprecatedTLS, detectFramework, disabledTLSVerification, djangoDebug, dockerCopySensitive, dockerLatestTag, dockerRunAsRoot, dockerTooManyPorts, ecbModeEncryption, electronNavigationUnrestricted, emptyCatchBlock, envNotGitignored, evalUsage, eventListenerLeak, exposedAdminRoutes, exposedAuthSecret, exposedDBCredentials, exposedDatabaseStudio, exposedDebugMode, exposedDockerPorts, exposedEnvFile, exposedGitDir, exposedServerActions, exposedSourceMaps, exposedStackTraces, filterFalsePositives, firebaseClientConfig, flaskSecretKey, freeRules, getSnippet, githubActionsInjection, graphqlIntrospection, hardcodedAnthropicKey, hardcodedDatadogKey, hardcodedEncryptionKey, hardcodedGCPServiceAccount, hardcodedGitHubPAT, hardcodedGitLabToken, hardcodedIPAllowlist, hardcodedJWTSecret, hardcodedMailgunKey, hardcodedOAuthSecret, hardcodedPineconeKey, hardcodedSecrets, hardcodedSendGridKey, hardcodedShopifyToken, hardcodedSlackToken, hardcodedSupabaseServiceRole, hardcodedTwilioKey, hardcodedVaultToken, hardcodedVercelToken, hostHeaderRedirect, httpRequestSmuggling, insecureCookies, insecureDeepLink, insecureDeserialization, insecureDirectObjectReference, insecureElectronWindow, insecureFileUpload, insecureGRPC, insecureHTTPMethods, insecurePasswordReset, insecureRandomness, insecureWebSocket, ipcPathTraversal, javaDeserialization, jwtAlgConfusion, k8sNoResourceLimits, k8sPrivileged, k8sSecretNotEncrypted, lambdaWithoutVPC, largeBundleImport, logInjection, magicNumbers, massAssignment, missingAIRateLimit, missingAuthMiddleware, missingAuthRateLimit, missingBruteForce, missingCSP, missingCSRF, missingCertPinning, missingCloudTrail, missingContentDisposition, missingDBEncryption, missingErrorBoundary, missingFileSizeLimits, missingHSTS, missingHTTPS, missingLockFile, missingOAuthState, missingPagination, missingRequestSizeLimit, missingRequestValidation, missingSRI, missingSecurityMeta, nPlusOneQuery, nextPublicSecret, noRateLimiting, nosqlInjection, openRedirectParams, overlyPermissiveIAM, pathTraversal, pickleDeserialization, piiInLogs, prototypePollution, raceCondition, rdsPubliclyAccessible, reflectedCORSOrigin, regexDos, runCustomRules, s3BucketNoEncryption, scanEntropy, secretInBundleConfig, secretInCLIArgument, secretInErrorResponse, secretInHTMLAttribute, secretInURLParam, secretLoggedToConsole, secretsInCI, securityGroupAllInbound, sensitiveAsyncStorage, sensitiveLocalStorage, sensitiveURLParams, sessionFixation, sqlInjection, ssrfVulnerability, ssti, stripeWebhookUnprotected, supabaseAnonAdmin, supabaseNoRLS, syncFileOps, terraformStateExposed, timingAttack, todoLeftInCode, unencryptedPII, unpinnedGitHubAction, unprotectedAPIRoutes, unprotectedDownload, unsafeObjectAssign, unsanitizedFilenames, unsanitizedHTMLExport, unvalidatedAPIParams, unvalidatedEventData, unvalidatedRedirect, vulnerableDependencies, weakHashing, weakPasswordRequirements, weakRSAKeySize, webhookSignatureVerification, xssVulnerability, xxeVulnerability };
343
+ /**
344
+ * Centralized Babel parser with per-file caching.
345
+ *
346
+ * Rules that opt in to AST analysis call parseFile(content, filename) to get
347
+ * a Program node back. Parsing is expensive (~5-50ms per KB of source); the
348
+ * LRU cache ensures a single scan pass touches each file at most once even
349
+ * when multiple rules walk the same AST.
350
+ *
351
+ * Failure mode: returns null on parse errors. Callers fall back to regex-only
352
+ * behavior so a syntax-error file in the user's repo can never break a scan.
353
+ */
354
+
355
+ interface ParsedFile {
356
+ ast: ParseResult<File>;
357
+ language: "js" | "ts" | "jsx" | "tsx";
358
+ }
359
+ /**
360
+ * Parse a JS/TS file. Returns null for unsupported extensions, parse errors,
361
+ * or empty content. Callers MUST handle null and fall back to regex-only.
362
+ */
363
+ declare function parseFile(content: string, filename: string): ParsedFile | null;
364
+
365
+ /**
366
+ * Lightweight taint tracking for AST-based rules.
367
+ *
368
+ * "Tainted" means "derived from untrusted input" — an Express/Next request
369
+ * body, query string, params, or headers; process.argv; environment
370
+ * variables known to be user-controlled; or file contents read at runtime.
371
+ *
372
+ * This is deliberately a local-only analysis: we walk the AST of one file,
373
+ * track which identifiers bind to a tainted source, and propagate through
374
+ * direct assignments and destructuring. Cross-function and cross-file flow
375
+ * is out of scope for Phase A — those require a module graph we don't build
376
+ * yet. A conservative local analysis is still enough to flip the benchmark
377
+ * recall on the data-flow rules.
378
+ *
379
+ * The analysis returns a TaintMap the rules can query:
380
+ * isTainted(node) → "is this AST expression tainted?"
381
+ * isTaintedIdent(name) → "is this identifier currently bound to tainted
382
+ * data in the file-level scope?"
383
+ *
384
+ * Shape of recognized sources:
385
+ * req.body, req.query, req.params, req.headers, req.cookies
386
+ * request.body, request.query, ... (Fastify)
387
+ * ctx.request.body, ctx.query (Koa)
388
+ * process.argv, process.env[Keys known to be user-controllable]
389
+ * event.queryStringParameters, event.body (AWS Lambda / API Gateway)
390
+ * searchParams.get(...), url.searchParams (Next.js / Web fetch API)
391
+ */
392
+
393
+ interface TaintMap {
394
+ /** true iff the given expression node evaluates to tainted data. */
395
+ isTainted(node: Node | null | undefined): boolean;
396
+ /** true iff the named identifier is bound to tainted data somewhere visible. */
397
+ isTaintedIdent(name: string): boolean;
398
+ /** Debug: all identifiers the analysis marked tainted, in discovery order. */
399
+ taintedNames(): string[];
400
+ }
401
+ /**
402
+ * Build a TaintMap for one parsed file. Single traversal, propagates taint
403
+ * through:
404
+ * - const/let bindings: const x = req.body.foo → x tainted
405
+ * - destructuring: const { foo } = req.body → foo tainted
406
+ * - assignment expressions: y = x; x is tainted → y tainted
407
+ * - function params named req/request/ctx (inside handlers, `req.body` is
408
+ * tainted even if we didn't see the outer binding)
409
+ */
410
+ declare function buildTaintMap(parsed: ParsedFile): TaintMap;
411
+
412
+ /**
413
+ * Visitor helpers for rule authors. Each helper takes a parsed file and a
414
+ * callback, and walks the AST in the most common pattern (find call
415
+ * expressions to a particular function, find member expressions of a
416
+ * particular shape, etc.).
417
+ *
418
+ * The rule code stays short and declarative; this file carries the
419
+ * @babel/traverse boilerplate and default-export interop.
420
+ */
421
+
422
+ /**
423
+ * Visit every BinaryExpression in the parsed file. Rule authors use this to
424
+ * catch `a === b` / `a !== b` comparisons where one side is a secret identifier.
425
+ */
426
+ declare function visitBinary(parsed: ParsedFile, visit: (node: BinaryExpression, line: number) => void): void;
427
+ /**
428
+ * Visit every CallExpression. `matchCallee` decides whether to surface the
429
+ * call; if it returns true, `visit` is invoked with the node and its
430
+ * 1-indexed source line.
431
+ */
432
+ declare function visitCalls(parsed: ParsedFile, matchCallee: (callee: Node) => boolean, visit: (call: CallExpression, line: number) => void): void;
433
+ /**
434
+ * "Does this callee resolve to a member/global named <name>?" — handles
435
+ * foo(x)
436
+ * obj.foo(x)
437
+ * a.b.foo(x)
438
+ * foo?.(x)
439
+ * Matches the terminal identifier only; doesn't bind to a specific receiver.
440
+ */
441
+ declare function isCalleeNamed(callee: Node, name: string): boolean;
442
+ /**
443
+ * Matches a call to `objName.methodName(...)` — useful for things like
444
+ * `_.merge`, `Object.assign`, `Handlebars.compile`, `libxml.parseXml`.
445
+ */
446
+ declare function isMethodCall(callee: Node, objName: string, methodName: string): boolean;
447
+ /** Looks up an ObjectExpression property by key name. */
448
+ declare function getObjectProperty(node: ObjectExpression, key: string): {
449
+ value: Node;
450
+ } | null;
451
+ /** Does this CallExpression spread an expression `matcher` returns true for? */
452
+ declare function callSpreads(call: CallExpression, matcher: (node: Node) => boolean): boolean;
453
+
454
+ export { type AIFilterResult, type Confidence, type CustomRule, type DetectedFramework, type FilteredFinding, type Finding, type GradeResult, type ParsedFile, type RuleMatch, type SecurityGrade, type Severity, type TaintMap, allCustomRules, allRules, androidDebuggable, blockingMainThread, buildTaintMap, calculateGrade, callSpreads, callbackHell, clickjacking, clientComponentSecret, clientSideAuth, commandInjection, complianceMap, consoleLogProduction, corsLocalhost, corsServerless, corsWildcard, dangerousInnerHTML, deprecatedTLS, detectFramework, disabledTLSVerification, djangoDebug, dockerCopySensitive, dockerLatestTag, dockerRunAsRoot, dockerTooManyPorts, dockerfileADDInsteadOfCOPY, dockerfileMissingHealthcheck, dockerfileUnverifiedShellPipe, ecbModeEncryption, electronNavigationUnrestricted, emptyCatchBlock, envNotGitignored, evalUsage, eventListenerLeak, exposedAdminRoutes, exposedAuthSecret, exposedDBCredentials, exposedDatabaseStudio, exposedDebugMode, exposedDockerPorts, exposedEnvFile, exposedGitDir, exposedServerActions, exposedSourceMaps, exposedStackTraces, filterFalsePositives, firebaseClientConfig, flaskSecretKey, freeRules, getObjectProperty, getSnippet, ghaExpressionInjection, ghaPermissionsWriteAll, ghaPullRequestTargetCheckout, ghaThirdPartyActionWithSecrets, githubActionsInjection, graphqlCSRFDisabled, graphqlIntrospection, graphqlNoComplexityLimit, graphqlNoDepthLimit, hardcodedAlgoliaAdminKey, hardcodedAnthropicKey, hardcodedCloudflareToken, hardcodedCohereKey, hardcodedDatadogKey, hardcodedDiscordToken, hardcodedEncryptionKey, hardcodedFastlyToken, hardcodedFireworksKey, hardcodedFlyToken, hardcodedGCPServiceAccount, hardcodedGitHubPAT, hardcodedGitLabToken, hardcodedGroqKey, hardcodedHighlightKey, hardcodedIPAllowlist, hardcodedIntercomToken, hardcodedJWTSecret, hardcodedLinearKey, hardcodedLogtailToken, hardcodedLoopsKey, hardcodedMailgunKey, hardcodedMistralKey, hardcodedNetlifyToken, hardcodedNotionKey, hardcodedOAuthSecret, hardcodedPineconeKey, hardcodedPlivoToken, hardcodedPostmarkKey, hardcodedQdrantKey, hardcodedRailwayToken, hardcodedReplicateKey, hardcodedResendKey, hardcodedSecrets, hardcodedSendGridKey, hardcodedSentryAuthToken, hardcodedShopifyToken, hardcodedSlackToken, hardcodedSupabaseServiceRole, hardcodedTogetherKey, hardcodedTwilioKey, hardcodedVaultToken, hardcodedVercelToken, hardcodedWeaviateKey, hostHeaderRedirect, httpRequestSmuggling, insecureCookies, insecureDeepLink, insecureDeserialization, insecureDirectObjectReference, insecureElectronWindow, insecureFileUpload, insecureGRPC, insecureHTTPMethods, insecurePasswordReset, insecureRandomness, insecureWebSocket, ipcPathTraversal, isCalleeNamed, isMethodCall, javaDeserialization, jwtAlgConfusion, k8sNoResourceLimits, k8sPrivileged, k8sSecretNotEncrypted, lambdaWithoutVPC, largeBundleImport, llmCallNoMaxTokens, llmOutputAsHTML, llmPromptInjection, llmSystemPromptInjection, logInjection, magicNumbers, massAssignment, missingAIRateLimit, missingAuthMiddleware, missingAuthRateLimit, missingBruteForce, missingCSP, missingCSRF, missingCertPinning, missingCloudTrail, missingContentDisposition, missingDBEncryption, missingErrorBoundary, missingFileSizeLimits, missingHSTS, missingHTTPS, missingLockFile, missingOAuthState, missingPagination, missingRequestSizeLimit, missingRequestValidation, missingSRI, missingSecurityMeta, nPlusOneQuery, nextPublicSecret, noRateLimiting, nosqlInjection, openRedirectParams, overlyPermissiveIAM, parseFile, pathTraversal, pickleDeserialization, piiInLogs, prototypePollution, pyDjangoAllowedHostsWildcard, pyDjangoMarkSafe, pyJWTDecodeWeakConfig, pyJinja2AutoescapeOff, pyParamikoAutoAdd, pyRequestsVerifyFalse, pyTempfileMktemp, raceCondition, rdsPubliclyAccessible, reflectedCORSOrigin, regexDos, runCustomRules, s3BucketNoEncryption, scanEntropy, secretInBundleConfig, secretInCLIArgument, secretInErrorResponse, secretInHTMLAttribute, secretInURLParam, secretLoggedToConsole, secretsInCI, securityGroupAllInbound, sensitiveAsyncStorage, sensitiveLocalStorage, sensitiveURLParams, sessionFixation, sqlInjection, ssrfVulnerability, ssti, stripeWebhookUnprotected, supabaseAnonAdmin, supabaseNoRLS, syncFileOps, terraformStateExposed, timingAttack, todoLeftInCode, unencryptedPII, unpinnedGitHubAction, unprotectedAPIRoutes, unprotectedDownload, unsafeObjectAssign, unsanitizedFilenames, unsanitizedHTMLExport, unvalidatedAPIParams, unvalidatedEventData, unvalidatedRedirect, vectorStoreQueryNoUserFilter, vectorStoreUpsertNoMetadata, visitBinary, visitCalls, vulnerableDependencies, weakHashing, weakPasswordRequirements, weakRSAKeySize, webhookSignatureVerification, xssVulnerability, xxeVulnerability };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import { ParseResult } from '@babel/parser';
2
+ import { File, Node, CallExpression, ObjectExpression, BinaryExpression } from '@babel/types';
3
+
1
4
  type Severity = "critical" | "high" | "medium" | "low" | "info";
2
5
  type Confidence = "high" | "medium" | "low";
3
6
  interface Finding {
@@ -209,6 +212,54 @@ declare const hardcodedVercelToken: CustomRule;
209
212
  declare const hardcodedSupabaseServiceRole: CustomRule;
210
213
  declare const hardcodedVaultToken: CustomRule;
211
214
  declare const hardcodedPineconeKey: CustomRule;
215
+ declare const hardcodedCohereKey: CustomRule;
216
+ declare const hardcodedReplicateKey: CustomRule;
217
+ declare const hardcodedMistralKey: CustomRule;
218
+ declare const hardcodedTogetherKey: CustomRule;
219
+ declare const hardcodedGroqKey: CustomRule;
220
+ declare const hardcodedFireworksKey: CustomRule;
221
+ declare const hardcodedPostmarkKey: CustomRule;
222
+ declare const hardcodedResendKey: CustomRule;
223
+ declare const hardcodedLoopsKey: CustomRule;
224
+ declare const hardcodedCloudflareToken: CustomRule;
225
+ declare const hardcodedFastlyToken: CustomRule;
226
+ declare const hardcodedNetlifyToken: CustomRule;
227
+ declare const hardcodedRailwayToken: CustomRule;
228
+ declare const hardcodedFlyToken: CustomRule;
229
+ declare const hardcodedAlgoliaAdminKey: CustomRule;
230
+ declare const hardcodedQdrantKey: CustomRule;
231
+ declare const hardcodedWeaviateKey: CustomRule;
232
+ declare const hardcodedLinearKey: CustomRule;
233
+ declare const hardcodedNotionKey: CustomRule;
234
+ declare const hardcodedDiscordToken: CustomRule;
235
+ declare const hardcodedIntercomToken: CustomRule;
236
+ declare const hardcodedSentryAuthToken: CustomRule;
237
+ declare const hardcodedLogtailToken: CustomRule;
238
+ declare const hardcodedHighlightKey: CustomRule;
239
+ declare const hardcodedPlivoToken: CustomRule;
240
+ declare const ghaPullRequestTargetCheckout: CustomRule;
241
+ declare const ghaPermissionsWriteAll: CustomRule;
242
+ declare const ghaExpressionInjection: CustomRule;
243
+ declare const ghaThirdPartyActionWithSecrets: CustomRule;
244
+ declare const dockerfileADDInsteadOfCOPY: CustomRule;
245
+ declare const dockerfileUnverifiedShellPipe: CustomRule;
246
+ declare const dockerfileMissingHealthcheck: CustomRule;
247
+ declare const pyRequestsVerifyFalse: CustomRule;
248
+ declare const pyJinja2AutoescapeOff: CustomRule;
249
+ declare const pyTempfileMktemp: CustomRule;
250
+ declare const pyDjangoMarkSafe: CustomRule;
251
+ declare const pyParamikoAutoAdd: CustomRule;
252
+ declare const pyDjangoAllowedHostsWildcard: CustomRule;
253
+ declare const pyJWTDecodeWeakConfig: CustomRule;
254
+ declare const llmPromptInjection: CustomRule;
255
+ declare const llmSystemPromptInjection: CustomRule;
256
+ declare const llmOutputAsHTML: CustomRule;
257
+ declare const vectorStoreQueryNoUserFilter: CustomRule;
258
+ declare const vectorStoreUpsertNoMetadata: CustomRule;
259
+ declare const llmCallNoMaxTokens: CustomRule;
260
+ declare const graphqlNoDepthLimit: CustomRule;
261
+ declare const graphqlNoComplexityLimit: CustomRule;
262
+ declare const graphqlCSRFDisabled: CustomRule;
212
263
  declare const secretInURLParam: CustomRule;
213
264
  declare const secretLoggedToConsole: CustomRule;
214
265
  declare const secretInErrorResponse: CustomRule;
@@ -289,4 +340,115 @@ declare function scanEntropy(files: {
289
340
  content: string;
290
341
  }[]): Finding[];
291
342
 
292
- export { type AIFilterResult, type Confidence, type CustomRule, type DetectedFramework, type FilteredFinding, type Finding, type GradeResult, type RuleMatch, type SecurityGrade, type Severity, allCustomRules, allRules, androidDebuggable, blockingMainThread, calculateGrade, callbackHell, clickjacking, clientComponentSecret, clientSideAuth, commandInjection, complianceMap, consoleLogProduction, corsLocalhost, corsServerless, corsWildcard, dangerousInnerHTML, deprecatedTLS, detectFramework, disabledTLSVerification, djangoDebug, dockerCopySensitive, dockerLatestTag, dockerRunAsRoot, dockerTooManyPorts, ecbModeEncryption, electronNavigationUnrestricted, emptyCatchBlock, envNotGitignored, evalUsage, eventListenerLeak, exposedAdminRoutes, exposedAuthSecret, exposedDBCredentials, exposedDatabaseStudio, exposedDebugMode, exposedDockerPorts, exposedEnvFile, exposedGitDir, exposedServerActions, exposedSourceMaps, exposedStackTraces, filterFalsePositives, firebaseClientConfig, flaskSecretKey, freeRules, getSnippet, githubActionsInjection, graphqlIntrospection, hardcodedAnthropicKey, hardcodedDatadogKey, hardcodedEncryptionKey, hardcodedGCPServiceAccount, hardcodedGitHubPAT, hardcodedGitLabToken, hardcodedIPAllowlist, hardcodedJWTSecret, hardcodedMailgunKey, hardcodedOAuthSecret, hardcodedPineconeKey, hardcodedSecrets, hardcodedSendGridKey, hardcodedShopifyToken, hardcodedSlackToken, hardcodedSupabaseServiceRole, hardcodedTwilioKey, hardcodedVaultToken, hardcodedVercelToken, hostHeaderRedirect, httpRequestSmuggling, insecureCookies, insecureDeepLink, insecureDeserialization, insecureDirectObjectReference, insecureElectronWindow, insecureFileUpload, insecureGRPC, insecureHTTPMethods, insecurePasswordReset, insecureRandomness, insecureWebSocket, ipcPathTraversal, javaDeserialization, jwtAlgConfusion, k8sNoResourceLimits, k8sPrivileged, k8sSecretNotEncrypted, lambdaWithoutVPC, largeBundleImport, logInjection, magicNumbers, massAssignment, missingAIRateLimit, missingAuthMiddleware, missingAuthRateLimit, missingBruteForce, missingCSP, missingCSRF, missingCertPinning, missingCloudTrail, missingContentDisposition, missingDBEncryption, missingErrorBoundary, missingFileSizeLimits, missingHSTS, missingHTTPS, missingLockFile, missingOAuthState, missingPagination, missingRequestSizeLimit, missingRequestValidation, missingSRI, missingSecurityMeta, nPlusOneQuery, nextPublicSecret, noRateLimiting, nosqlInjection, openRedirectParams, overlyPermissiveIAM, pathTraversal, pickleDeserialization, piiInLogs, prototypePollution, raceCondition, rdsPubliclyAccessible, reflectedCORSOrigin, regexDos, runCustomRules, s3BucketNoEncryption, scanEntropy, secretInBundleConfig, secretInCLIArgument, secretInErrorResponse, secretInHTMLAttribute, secretInURLParam, secretLoggedToConsole, secretsInCI, securityGroupAllInbound, sensitiveAsyncStorage, sensitiveLocalStorage, sensitiveURLParams, sessionFixation, sqlInjection, ssrfVulnerability, ssti, stripeWebhookUnprotected, supabaseAnonAdmin, supabaseNoRLS, syncFileOps, terraformStateExposed, timingAttack, todoLeftInCode, unencryptedPII, unpinnedGitHubAction, unprotectedAPIRoutes, unprotectedDownload, unsafeObjectAssign, unsanitizedFilenames, unsanitizedHTMLExport, unvalidatedAPIParams, unvalidatedEventData, unvalidatedRedirect, vulnerableDependencies, weakHashing, weakPasswordRequirements, weakRSAKeySize, webhookSignatureVerification, xssVulnerability, xxeVulnerability };
343
+ /**
344
+ * Centralized Babel parser with per-file caching.
345
+ *
346
+ * Rules that opt in to AST analysis call parseFile(content, filename) to get
347
+ * a Program node back. Parsing is expensive (~5-50ms per KB of source); the
348
+ * LRU cache ensures a single scan pass touches each file at most once even
349
+ * when multiple rules walk the same AST.
350
+ *
351
+ * Failure mode: returns null on parse errors. Callers fall back to regex-only
352
+ * behavior so a syntax-error file in the user's repo can never break a scan.
353
+ */
354
+
355
+ interface ParsedFile {
356
+ ast: ParseResult<File>;
357
+ language: "js" | "ts" | "jsx" | "tsx";
358
+ }
359
+ /**
360
+ * Parse a JS/TS file. Returns null for unsupported extensions, parse errors,
361
+ * or empty content. Callers MUST handle null and fall back to regex-only.
362
+ */
363
+ declare function parseFile(content: string, filename: string): ParsedFile | null;
364
+
365
+ /**
366
+ * Lightweight taint tracking for AST-based rules.
367
+ *
368
+ * "Tainted" means "derived from untrusted input" — an Express/Next request
369
+ * body, query string, params, or headers; process.argv; environment
370
+ * variables known to be user-controlled; or file contents read at runtime.
371
+ *
372
+ * This is deliberately a local-only analysis: we walk the AST of one file,
373
+ * track which identifiers bind to a tainted source, and propagate through
374
+ * direct assignments and destructuring. Cross-function and cross-file flow
375
+ * is out of scope for Phase A — those require a module graph we don't build
376
+ * yet. A conservative local analysis is still enough to flip the benchmark
377
+ * recall on the data-flow rules.
378
+ *
379
+ * The analysis returns a TaintMap the rules can query:
380
+ * isTainted(node) → "is this AST expression tainted?"
381
+ * isTaintedIdent(name) → "is this identifier currently bound to tainted
382
+ * data in the file-level scope?"
383
+ *
384
+ * Shape of recognized sources:
385
+ * req.body, req.query, req.params, req.headers, req.cookies
386
+ * request.body, request.query, ... (Fastify)
387
+ * ctx.request.body, ctx.query (Koa)
388
+ * process.argv, process.env[Keys known to be user-controllable]
389
+ * event.queryStringParameters, event.body (AWS Lambda / API Gateway)
390
+ * searchParams.get(...), url.searchParams (Next.js / Web fetch API)
391
+ */
392
+
393
+ interface TaintMap {
394
+ /** true iff the given expression node evaluates to tainted data. */
395
+ isTainted(node: Node | null | undefined): boolean;
396
+ /** true iff the named identifier is bound to tainted data somewhere visible. */
397
+ isTaintedIdent(name: string): boolean;
398
+ /** Debug: all identifiers the analysis marked tainted, in discovery order. */
399
+ taintedNames(): string[];
400
+ }
401
+ /**
402
+ * Build a TaintMap for one parsed file. Single traversal, propagates taint
403
+ * through:
404
+ * - const/let bindings: const x = req.body.foo → x tainted
405
+ * - destructuring: const { foo } = req.body → foo tainted
406
+ * - assignment expressions: y = x; x is tainted → y tainted
407
+ * - function params named req/request/ctx (inside handlers, `req.body` is
408
+ * tainted even if we didn't see the outer binding)
409
+ */
410
+ declare function buildTaintMap(parsed: ParsedFile): TaintMap;
411
+
412
+ /**
413
+ * Visitor helpers for rule authors. Each helper takes a parsed file and a
414
+ * callback, and walks the AST in the most common pattern (find call
415
+ * expressions to a particular function, find member expressions of a
416
+ * particular shape, etc.).
417
+ *
418
+ * The rule code stays short and declarative; this file carries the
419
+ * @babel/traverse boilerplate and default-export interop.
420
+ */
421
+
422
+ /**
423
+ * Visit every BinaryExpression in the parsed file. Rule authors use this to
424
+ * catch `a === b` / `a !== b` comparisons where one side is a secret identifier.
425
+ */
426
+ declare function visitBinary(parsed: ParsedFile, visit: (node: BinaryExpression, line: number) => void): void;
427
+ /**
428
+ * Visit every CallExpression. `matchCallee` decides whether to surface the
429
+ * call; if it returns true, `visit` is invoked with the node and its
430
+ * 1-indexed source line.
431
+ */
432
+ declare function visitCalls(parsed: ParsedFile, matchCallee: (callee: Node) => boolean, visit: (call: CallExpression, line: number) => void): void;
433
+ /**
434
+ * "Does this callee resolve to a member/global named <name>?" — handles
435
+ * foo(x)
436
+ * obj.foo(x)
437
+ * a.b.foo(x)
438
+ * foo?.(x)
439
+ * Matches the terminal identifier only; doesn't bind to a specific receiver.
440
+ */
441
+ declare function isCalleeNamed(callee: Node, name: string): boolean;
442
+ /**
443
+ * Matches a call to `objName.methodName(...)` — useful for things like
444
+ * `_.merge`, `Object.assign`, `Handlebars.compile`, `libxml.parseXml`.
445
+ */
446
+ declare function isMethodCall(callee: Node, objName: string, methodName: string): boolean;
447
+ /** Looks up an ObjectExpression property by key name. */
448
+ declare function getObjectProperty(node: ObjectExpression, key: string): {
449
+ value: Node;
450
+ } | null;
451
+ /** Does this CallExpression spread an expression `matcher` returns true for? */
452
+ declare function callSpreads(call: CallExpression, matcher: (node: Node) => boolean): boolean;
453
+
454
+ export { type AIFilterResult, type Confidence, type CustomRule, type DetectedFramework, type FilteredFinding, type Finding, type GradeResult, type ParsedFile, type RuleMatch, type SecurityGrade, type Severity, type TaintMap, allCustomRules, allRules, androidDebuggable, blockingMainThread, buildTaintMap, calculateGrade, callSpreads, callbackHell, clickjacking, clientComponentSecret, clientSideAuth, commandInjection, complianceMap, consoleLogProduction, corsLocalhost, corsServerless, corsWildcard, dangerousInnerHTML, deprecatedTLS, detectFramework, disabledTLSVerification, djangoDebug, dockerCopySensitive, dockerLatestTag, dockerRunAsRoot, dockerTooManyPorts, dockerfileADDInsteadOfCOPY, dockerfileMissingHealthcheck, dockerfileUnverifiedShellPipe, ecbModeEncryption, electronNavigationUnrestricted, emptyCatchBlock, envNotGitignored, evalUsage, eventListenerLeak, exposedAdminRoutes, exposedAuthSecret, exposedDBCredentials, exposedDatabaseStudio, exposedDebugMode, exposedDockerPorts, exposedEnvFile, exposedGitDir, exposedServerActions, exposedSourceMaps, exposedStackTraces, filterFalsePositives, firebaseClientConfig, flaskSecretKey, freeRules, getObjectProperty, getSnippet, ghaExpressionInjection, ghaPermissionsWriteAll, ghaPullRequestTargetCheckout, ghaThirdPartyActionWithSecrets, githubActionsInjection, graphqlCSRFDisabled, graphqlIntrospection, graphqlNoComplexityLimit, graphqlNoDepthLimit, hardcodedAlgoliaAdminKey, hardcodedAnthropicKey, hardcodedCloudflareToken, hardcodedCohereKey, hardcodedDatadogKey, hardcodedDiscordToken, hardcodedEncryptionKey, hardcodedFastlyToken, hardcodedFireworksKey, hardcodedFlyToken, hardcodedGCPServiceAccount, hardcodedGitHubPAT, hardcodedGitLabToken, hardcodedGroqKey, hardcodedHighlightKey, hardcodedIPAllowlist, hardcodedIntercomToken, hardcodedJWTSecret, hardcodedLinearKey, hardcodedLogtailToken, hardcodedLoopsKey, hardcodedMailgunKey, hardcodedMistralKey, hardcodedNetlifyToken, hardcodedNotionKey, hardcodedOAuthSecret, hardcodedPineconeKey, hardcodedPlivoToken, hardcodedPostmarkKey, hardcodedQdrantKey, hardcodedRailwayToken, hardcodedReplicateKey, hardcodedResendKey, hardcodedSecrets, hardcodedSendGridKey, hardcodedSentryAuthToken, hardcodedShopifyToken, hardcodedSlackToken, hardcodedSupabaseServiceRole, hardcodedTogetherKey, hardcodedTwilioKey, hardcodedVaultToken, hardcodedVercelToken, hardcodedWeaviateKey, hostHeaderRedirect, httpRequestSmuggling, insecureCookies, insecureDeepLink, insecureDeserialization, insecureDirectObjectReference, insecureElectronWindow, insecureFileUpload, insecureGRPC, insecureHTTPMethods, insecurePasswordReset, insecureRandomness, insecureWebSocket, ipcPathTraversal, isCalleeNamed, isMethodCall, javaDeserialization, jwtAlgConfusion, k8sNoResourceLimits, k8sPrivileged, k8sSecretNotEncrypted, lambdaWithoutVPC, largeBundleImport, llmCallNoMaxTokens, llmOutputAsHTML, llmPromptInjection, llmSystemPromptInjection, logInjection, magicNumbers, massAssignment, missingAIRateLimit, missingAuthMiddleware, missingAuthRateLimit, missingBruteForce, missingCSP, missingCSRF, missingCertPinning, missingCloudTrail, missingContentDisposition, missingDBEncryption, missingErrorBoundary, missingFileSizeLimits, missingHSTS, missingHTTPS, missingLockFile, missingOAuthState, missingPagination, missingRequestSizeLimit, missingRequestValidation, missingSRI, missingSecurityMeta, nPlusOneQuery, nextPublicSecret, noRateLimiting, nosqlInjection, openRedirectParams, overlyPermissiveIAM, parseFile, pathTraversal, pickleDeserialization, piiInLogs, prototypePollution, pyDjangoAllowedHostsWildcard, pyDjangoMarkSafe, pyJWTDecodeWeakConfig, pyJinja2AutoescapeOff, pyParamikoAutoAdd, pyRequestsVerifyFalse, pyTempfileMktemp, raceCondition, rdsPubliclyAccessible, reflectedCORSOrigin, regexDos, runCustomRules, s3BucketNoEncryption, scanEntropy, secretInBundleConfig, secretInCLIArgument, secretInErrorResponse, secretInHTMLAttribute, secretInURLParam, secretLoggedToConsole, secretsInCI, securityGroupAllInbound, sensitiveAsyncStorage, sensitiveLocalStorage, sensitiveURLParams, sessionFixation, sqlInjection, ssrfVulnerability, ssti, stripeWebhookUnprotected, supabaseAnonAdmin, supabaseNoRLS, syncFileOps, terraformStateExposed, timingAttack, todoLeftInCode, unencryptedPII, unpinnedGitHubAction, unprotectedAPIRoutes, unprotectedDownload, unsafeObjectAssign, unsanitizedFilenames, unsanitizedHTMLExport, unvalidatedAPIParams, unvalidatedEventData, unvalidatedRedirect, vectorStoreQueryNoUserFilter, vectorStoreUpsertNoMetadata, visitBinary, visitCalls, vulnerableDependencies, weakHashing, weakPasswordRequirements, weakRSAKeySize, webhookSignatureVerification, xssVulnerability, xxeVulnerability };