@oculum/scanner 1.0.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/formatters/cli-terminal.d.ts +27 -0
- package/dist/formatters/cli-terminal.d.ts.map +1 -0
- package/dist/formatters/cli-terminal.js +412 -0
- package/dist/formatters/cli-terminal.js.map +1 -0
- package/dist/formatters/github-comment.d.ts +41 -0
- package/dist/formatters/github-comment.d.ts.map +1 -0
- package/dist/formatters/github-comment.js +306 -0
- package/dist/formatters/github-comment.js.map +1 -0
- package/dist/formatters/grouping.d.ts +52 -0
- package/dist/formatters/grouping.d.ts.map +1 -0
- package/dist/formatters/grouping.js +152 -0
- package/dist/formatters/grouping.js.map +1 -0
- package/dist/formatters/index.d.ts +9 -0
- package/dist/formatters/index.d.ts.map +1 -0
- package/dist/formatters/index.js +35 -0
- package/dist/formatters/index.js.map +1 -0
- package/dist/formatters/vscode-diagnostic.d.ts +103 -0
- package/dist/formatters/vscode-diagnostic.d.ts.map +1 -0
- package/dist/formatters/vscode-diagnostic.js +151 -0
- package/dist/formatters/vscode-diagnostic.js.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +648 -0
- package/dist/index.js.map +1 -0
- package/dist/layer1/comments.d.ts +8 -0
- package/dist/layer1/comments.d.ts.map +1 -0
- package/dist/layer1/comments.js +203 -0
- package/dist/layer1/comments.js.map +1 -0
- package/dist/layer1/config-audit.d.ts +8 -0
- package/dist/layer1/config-audit.d.ts.map +1 -0
- package/dist/layer1/config-audit.js +252 -0
- package/dist/layer1/config-audit.js.map +1 -0
- package/dist/layer1/entropy.d.ts +8 -0
- package/dist/layer1/entropy.d.ts.map +1 -0
- package/dist/layer1/entropy.js +500 -0
- package/dist/layer1/entropy.js.map +1 -0
- package/dist/layer1/file-flags.d.ts +7 -0
- package/dist/layer1/file-flags.d.ts.map +1 -0
- package/dist/layer1/file-flags.js +112 -0
- package/dist/layer1/file-flags.js.map +1 -0
- package/dist/layer1/index.d.ts +36 -0
- package/dist/layer1/index.d.ts.map +1 -0
- package/dist/layer1/index.js +132 -0
- package/dist/layer1/index.js.map +1 -0
- package/dist/layer1/patterns.d.ts +8 -0
- package/dist/layer1/patterns.d.ts.map +1 -0
- package/dist/layer1/patterns.js +482 -0
- package/dist/layer1/patterns.js.map +1 -0
- package/dist/layer1/urls.d.ts +8 -0
- package/dist/layer1/urls.d.ts.map +1 -0
- package/dist/layer1/urls.js +296 -0
- package/dist/layer1/urls.js.map +1 -0
- package/dist/layer1/weak-crypto.d.ts +7 -0
- package/dist/layer1/weak-crypto.d.ts.map +1 -0
- package/dist/layer1/weak-crypto.js +291 -0
- package/dist/layer1/weak-crypto.js.map +1 -0
- package/dist/layer2/ai-agent-tools.d.ts +19 -0
- package/dist/layer2/ai-agent-tools.d.ts.map +1 -0
- package/dist/layer2/ai-agent-tools.js +528 -0
- package/dist/layer2/ai-agent-tools.js.map +1 -0
- package/dist/layer2/ai-endpoint-protection.d.ts +36 -0
- package/dist/layer2/ai-endpoint-protection.d.ts.map +1 -0
- package/dist/layer2/ai-endpoint-protection.js +332 -0
- package/dist/layer2/ai-endpoint-protection.js.map +1 -0
- package/dist/layer2/ai-execution-sinks.d.ts +18 -0
- package/dist/layer2/ai-execution-sinks.d.ts.map +1 -0
- package/dist/layer2/ai-execution-sinks.js +496 -0
- package/dist/layer2/ai-execution-sinks.js.map +1 -0
- package/dist/layer2/ai-fingerprinting.d.ts +7 -0
- package/dist/layer2/ai-fingerprinting.d.ts.map +1 -0
- package/dist/layer2/ai-fingerprinting.js +654 -0
- package/dist/layer2/ai-fingerprinting.js.map +1 -0
- package/dist/layer2/ai-prompt-hygiene.d.ts +19 -0
- package/dist/layer2/ai-prompt-hygiene.d.ts.map +1 -0
- package/dist/layer2/ai-prompt-hygiene.js +356 -0
- package/dist/layer2/ai-prompt-hygiene.js.map +1 -0
- package/dist/layer2/ai-rag-safety.d.ts +21 -0
- package/dist/layer2/ai-rag-safety.d.ts.map +1 -0
- package/dist/layer2/ai-rag-safety.js +459 -0
- package/dist/layer2/ai-rag-safety.js.map +1 -0
- package/dist/layer2/ai-schema-validation.d.ts +25 -0
- package/dist/layer2/ai-schema-validation.d.ts.map +1 -0
- package/dist/layer2/ai-schema-validation.js +375 -0
- package/dist/layer2/ai-schema-validation.js.map +1 -0
- package/dist/layer2/auth-antipatterns.d.ts +20 -0
- package/dist/layer2/auth-antipatterns.d.ts.map +1 -0
- package/dist/layer2/auth-antipatterns.js +333 -0
- package/dist/layer2/auth-antipatterns.js.map +1 -0
- package/dist/layer2/byok-patterns.d.ts +12 -0
- package/dist/layer2/byok-patterns.d.ts.map +1 -0
- package/dist/layer2/byok-patterns.js +299 -0
- package/dist/layer2/byok-patterns.js.map +1 -0
- package/dist/layer2/dangerous-functions.d.ts +7 -0
- package/dist/layer2/dangerous-functions.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions.js +1375 -0
- package/dist/layer2/dangerous-functions.js.map +1 -0
- package/dist/layer2/data-exposure.d.ts +16 -0
- package/dist/layer2/data-exposure.d.ts.map +1 -0
- package/dist/layer2/data-exposure.js +279 -0
- package/dist/layer2/data-exposure.js.map +1 -0
- package/dist/layer2/framework-checks.d.ts +7 -0
- package/dist/layer2/framework-checks.d.ts.map +1 -0
- package/dist/layer2/framework-checks.js +388 -0
- package/dist/layer2/framework-checks.js.map +1 -0
- package/dist/layer2/index.d.ts +58 -0
- package/dist/layer2/index.d.ts.map +1 -0
- package/dist/layer2/index.js +380 -0
- package/dist/layer2/index.js.map +1 -0
- package/dist/layer2/logic-gates.d.ts +7 -0
- package/dist/layer2/logic-gates.d.ts.map +1 -0
- package/dist/layer2/logic-gates.js +182 -0
- package/dist/layer2/logic-gates.js.map +1 -0
- package/dist/layer2/risky-imports.d.ts +7 -0
- package/dist/layer2/risky-imports.d.ts.map +1 -0
- package/dist/layer2/risky-imports.js +161 -0
- package/dist/layer2/risky-imports.js.map +1 -0
- package/dist/layer2/variables.d.ts +8 -0
- package/dist/layer2/variables.d.ts.map +1 -0
- package/dist/layer2/variables.js +152 -0
- package/dist/layer2/variables.js.map +1 -0
- package/dist/layer3/anthropic.d.ts +83 -0
- package/dist/layer3/anthropic.d.ts.map +1 -0
- package/dist/layer3/anthropic.js +1745 -0
- package/dist/layer3/anthropic.js.map +1 -0
- package/dist/layer3/index.d.ts +24 -0
- package/dist/layer3/index.d.ts.map +1 -0
- package/dist/layer3/index.js +119 -0
- package/dist/layer3/index.js.map +1 -0
- package/dist/layer3/openai.d.ts +25 -0
- package/dist/layer3/openai.d.ts.map +1 -0
- package/dist/layer3/openai.js +238 -0
- package/dist/layer3/openai.js.map +1 -0
- package/dist/layer3/package-check.d.ts +63 -0
- package/dist/layer3/package-check.d.ts.map +1 -0
- package/dist/layer3/package-check.js +508 -0
- package/dist/layer3/package-check.js.map +1 -0
- package/dist/modes/incremental.d.ts +66 -0
- package/dist/modes/incremental.d.ts.map +1 -0
- package/dist/modes/incremental.js +200 -0
- package/dist/modes/incremental.js.map +1 -0
- package/dist/tiers.d.ts +125 -0
- package/dist/tiers.d.ts.map +1 -0
- package/dist/tiers.js +234 -0
- package/dist/tiers.js.map +1 -0
- package/dist/types.d.ts +175 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +50 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/auth-helper-detector.d.ts +56 -0
- package/dist/utils/auth-helper-detector.d.ts.map +1 -0
- package/dist/utils/auth-helper-detector.js +360 -0
- package/dist/utils/auth-helper-detector.js.map +1 -0
- package/dist/utils/context-helpers.d.ts +96 -0
- package/dist/utils/context-helpers.d.ts.map +1 -0
- package/dist/utils/context-helpers.js +493 -0
- package/dist/utils/context-helpers.js.map +1 -0
- package/dist/utils/diff-detector.d.ts +53 -0
- package/dist/utils/diff-detector.d.ts.map +1 -0
- package/dist/utils/diff-detector.js +104 -0
- package/dist/utils/diff-detector.js.map +1 -0
- package/dist/utils/diff-parser.d.ts +80 -0
- package/dist/utils/diff-parser.d.ts.map +1 -0
- package/dist/utils/diff-parser.js +202 -0
- package/dist/utils/diff-parser.js.map +1 -0
- package/dist/utils/imported-auth-detector.d.ts +37 -0
- package/dist/utils/imported-auth-detector.d.ts.map +1 -0
- package/dist/utils/imported-auth-detector.js +251 -0
- package/dist/utils/imported-auth-detector.js.map +1 -0
- package/dist/utils/middleware-detector.d.ts +55 -0
- package/dist/utils/middleware-detector.d.ts.map +1 -0
- package/dist/utils/middleware-detector.js +260 -0
- package/dist/utils/middleware-detector.js.map +1 -0
- package/dist/utils/oauth-flow-detector.d.ts +41 -0
- package/dist/utils/oauth-flow-detector.d.ts.map +1 -0
- package/dist/utils/oauth-flow-detector.js +202 -0
- package/dist/utils/oauth-flow-detector.js.map +1 -0
- package/dist/utils/path-exclusions.d.ts +55 -0
- package/dist/utils/path-exclusions.d.ts.map +1 -0
- package/dist/utils/path-exclusions.js +222 -0
- package/dist/utils/path-exclusions.js.map +1 -0
- package/dist/utils/project-context-builder.d.ts +119 -0
- package/dist/utils/project-context-builder.d.ts.map +1 -0
- package/dist/utils/project-context-builder.js +534 -0
- package/dist/utils/project-context-builder.js.map +1 -0
- package/dist/utils/registry-clients.d.ts +93 -0
- package/dist/utils/registry-clients.d.ts.map +1 -0
- package/dist/utils/registry-clients.js +273 -0
- package/dist/utils/registry-clients.js.map +1 -0
- package/dist/utils/trpc-analyzer.d.ts +78 -0
- package/dist/utils/trpc-analyzer.d.ts.map +1 -0
- package/dist/utils/trpc-analyzer.js +297 -0
- package/dist/utils/trpc-analyzer.js.map +1 -0
- package/package.json +45 -0
- package/src/__tests__/benchmark/fixtures/false-positives.ts +227 -0
- package/src/__tests__/benchmark/fixtures/index.ts +68 -0
- package/src/__tests__/benchmark/fixtures/layer1/config-audit.ts +364 -0
- package/src/__tests__/benchmark/fixtures/layer1/hardcoded-secrets.ts +173 -0
- package/src/__tests__/benchmark/fixtures/layer1/high-entropy.ts +234 -0
- package/src/__tests__/benchmark/fixtures/layer1/index.ts +31 -0
- package/src/__tests__/benchmark/fixtures/layer1/sensitive-urls.ts +90 -0
- package/src/__tests__/benchmark/fixtures/layer1/weak-crypto.ts +197 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-agent-tools.ts +170 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-endpoint-protection.ts +418 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-execution-sinks.ts +189 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-fingerprinting.ts +316 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-prompt-hygiene.ts +178 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-rag-safety.ts +184 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-schema-validation.ts +434 -0
- package/src/__tests__/benchmark/fixtures/layer2/auth-antipatterns.ts +159 -0
- package/src/__tests__/benchmark/fixtures/layer2/byok-patterns.ts +112 -0
- package/src/__tests__/benchmark/fixtures/layer2/dangerous-functions.ts +246 -0
- package/src/__tests__/benchmark/fixtures/layer2/data-exposure.ts +168 -0
- package/src/__tests__/benchmark/fixtures/layer2/framework-checks.ts +346 -0
- package/src/__tests__/benchmark/fixtures/layer2/index.ts +67 -0
- package/src/__tests__/benchmark/fixtures/layer2/injection-vulnerabilities.ts +239 -0
- package/src/__tests__/benchmark/fixtures/layer2/logic-gates.ts +246 -0
- package/src/__tests__/benchmark/fixtures/layer2/risky-imports.ts +231 -0
- package/src/__tests__/benchmark/fixtures/layer2/variables.ts +167 -0
- package/src/__tests__/benchmark/index.ts +29 -0
- package/src/__tests__/benchmark/run-benchmark.ts +144 -0
- package/src/__tests__/benchmark/run-depth-validation.ts +206 -0
- package/src/__tests__/benchmark/run-real-world-test.ts +243 -0
- package/src/__tests__/benchmark/security-benchmark-script.ts +1737 -0
- package/src/__tests__/benchmark/tier-integration-script.ts +177 -0
- package/src/__tests__/benchmark/types.ts +144 -0
- package/src/__tests__/benchmark/utils/test-runner.ts +475 -0
- package/src/__tests__/regression/known-false-positives.test.ts +467 -0
- package/src/__tests__/snapshots/__snapshots__/scan-depth.test.ts.snap +178 -0
- package/src/__tests__/snapshots/scan-depth.test.ts +258 -0
- package/src/__tests__/validation/analyze-results.ts +542 -0
- package/src/__tests__/validation/extract-for-triage.ts +146 -0
- package/src/__tests__/validation/fp-deep-analysis.ts +327 -0
- package/src/__tests__/validation/run-validation.ts +364 -0
- package/src/__tests__/validation/triage-template.md +132 -0
- package/src/formatters/cli-terminal.ts +446 -0
- package/src/formatters/github-comment.ts +382 -0
- package/src/formatters/grouping.ts +190 -0
- package/src/formatters/index.ts +47 -0
- package/src/formatters/vscode-diagnostic.ts +243 -0
- package/src/index.ts +823 -0
- package/src/layer1/comments.ts +218 -0
- package/src/layer1/config-audit.ts +289 -0
- package/src/layer1/entropy.ts +583 -0
- package/src/layer1/file-flags.ts +127 -0
- package/src/layer1/index.ts +181 -0
- package/src/layer1/patterns.ts +516 -0
- package/src/layer1/urls.ts +334 -0
- package/src/layer1/weak-crypto.ts +328 -0
- package/src/layer2/ai-agent-tools.ts +601 -0
- package/src/layer2/ai-endpoint-protection.ts +387 -0
- package/src/layer2/ai-execution-sinks.ts +580 -0
- package/src/layer2/ai-fingerprinting.ts +758 -0
- package/src/layer2/ai-prompt-hygiene.ts +411 -0
- package/src/layer2/ai-rag-safety.ts +511 -0
- package/src/layer2/ai-schema-validation.ts +421 -0
- package/src/layer2/auth-antipatterns.ts +394 -0
- package/src/layer2/byok-patterns.ts +336 -0
- package/src/layer2/dangerous-functions.ts +1563 -0
- package/src/layer2/data-exposure.ts +315 -0
- package/src/layer2/framework-checks.ts +433 -0
- package/src/layer2/index.ts +473 -0
- package/src/layer2/logic-gates.ts +206 -0
- package/src/layer2/risky-imports.ts +186 -0
- package/src/layer2/variables.ts +166 -0
- package/src/layer3/anthropic.ts +2030 -0
- package/src/layer3/index.ts +130 -0
- package/src/layer3/package-check.ts +604 -0
- package/src/modes/incremental.ts +293 -0
- package/src/tiers.ts +318 -0
- package/src/types.ts +284 -0
- package/src/utils/auth-helper-detector.ts +443 -0
- package/src/utils/context-helpers.ts +535 -0
- package/src/utils/diff-detector.ts +135 -0
- package/src/utils/diff-parser.ts +272 -0
- package/src/utils/imported-auth-detector.ts +320 -0
- package/src/utils/middleware-detector.ts +333 -0
- package/src/utils/oauth-flow-detector.ts +246 -0
- package/src/utils/path-exclusions.ts +266 -0
- package/src/utils/project-context-builder.ts +707 -0
- package/src/utils/registry-clients.ts +351 -0
- package/src/utils/trpc-analyzer.ts +382 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 1: File Extension Red Flags
|
|
3
|
+
* Detects dangerous files that should not be in a repository
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Vulnerability } from '../types'
|
|
7
|
+
|
|
8
|
+
// Dangerous file extensions and names that should not be committed
|
|
9
|
+
const DANGEROUS_FILE_PATTERNS = [
|
|
10
|
+
// Private keys
|
|
11
|
+
{ pattern: /\.pem$/i, name: 'PEM Private Key', severity: 'critical' as const },
|
|
12
|
+
{ pattern: /\.key$/i, name: 'Private Key File', severity: 'critical' as const },
|
|
13
|
+
{ pattern: /\.p12$/i, name: 'PKCS#12 Certificate', severity: 'critical' as const },
|
|
14
|
+
{ pattern: /\.pfx$/i, name: 'PFX Certificate', severity: 'critical' as const },
|
|
15
|
+
{ pattern: /\.p8$/i, name: 'PKCS#8 Private Key', severity: 'critical' as const },
|
|
16
|
+
|
|
17
|
+
// SSH keys
|
|
18
|
+
{ pattern: /id_rsa$/i, name: 'RSA SSH Private Key', severity: 'critical' as const },
|
|
19
|
+
{ pattern: /id_dsa$/i, name: 'DSA SSH Private Key', severity: 'critical' as const },
|
|
20
|
+
{ pattern: /id_ecdsa$/i, name: 'ECDSA SSH Private Key', severity: 'critical' as const },
|
|
21
|
+
{ pattern: /id_ed25519$/i, name: 'Ed25519 SSH Private Key', severity: 'critical' as const },
|
|
22
|
+
|
|
23
|
+
// Environment files (should be gitignored)
|
|
24
|
+
{ pattern: /^\.env$/i, name: 'Environment File', severity: 'critical' as const },
|
|
25
|
+
{ pattern: /^\.env\.local$/i, name: 'Local Environment File', severity: 'critical' as const },
|
|
26
|
+
{ pattern: /^\.env\.production$/i, name: 'Production Environment File', severity: 'critical' as const },
|
|
27
|
+
{ pattern: /^\.env\.development$/i, name: 'Development Environment File', severity: 'high' as const },
|
|
28
|
+
{ pattern: /^\.env\.staging$/i, name: 'Staging Environment File', severity: 'high' as const },
|
|
29
|
+
|
|
30
|
+
// Credential files
|
|
31
|
+
{ pattern: /\.pgpass$/i, name: 'PostgreSQL Password File', severity: 'critical' as const },
|
|
32
|
+
{ pattern: /\.npmrc$/i, name: 'NPM Configuration (may contain tokens)', severity: 'high' as const },
|
|
33
|
+
{ pattern: /\.pypirc$/i, name: 'PyPI Configuration (may contain tokens)', severity: 'high' as const },
|
|
34
|
+
{ pattern: /\.netrc$/i, name: 'Netrc File (contains credentials)', severity: 'critical' as const },
|
|
35
|
+
{ pattern: /\.htpasswd$/i, name: 'Apache Password File', severity: 'critical' as const },
|
|
36
|
+
|
|
37
|
+
// Database files
|
|
38
|
+
{ pattern: /\.sqlite$/i, name: 'SQLite Database', severity: 'medium' as const },
|
|
39
|
+
{ pattern: /\.sqlite3$/i, name: 'SQLite Database', severity: 'medium' as const },
|
|
40
|
+
{ pattern: /\.db$/i, name: 'Database File', severity: 'medium' as const },
|
|
41
|
+
|
|
42
|
+
// Backup files that may contain secrets
|
|
43
|
+
{ pattern: /\.bak$/i, name: 'Backup File', severity: 'low' as const },
|
|
44
|
+
{ pattern: /\.backup$/i, name: 'Backup File', severity: 'low' as const },
|
|
45
|
+
{ pattern: /\.old$/i, name: 'Old File Backup', severity: 'low' as const },
|
|
46
|
+
|
|
47
|
+
// Keystore files
|
|
48
|
+
{ pattern: /\.jks$/i, name: 'Java Keystore', severity: 'high' as const },
|
|
49
|
+
{ pattern: /\.keystore$/i, name: 'Keystore File', severity: 'high' as const },
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
// Files that are okay in certain contexts but should be reviewed
|
|
53
|
+
const CONTEXT_SENSITIVE_PATTERNS = [
|
|
54
|
+
{ pattern: /\.env\.example$/i, name: 'Environment Example File', checkContent: true },
|
|
55
|
+
{ pattern: /\.env\.sample$/i, name: 'Environment Sample File', checkContent: true },
|
|
56
|
+
{ pattern: /\.env\.template$/i, name: 'Environment Template File', checkContent: true },
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
export function detectDangerousFiles(
|
|
60
|
+
content: string,
|
|
61
|
+
filePath: string
|
|
62
|
+
): Vulnerability[] {
|
|
63
|
+
const vulnerabilities: Vulnerability[] = []
|
|
64
|
+
const fileName = filePath.split('/').pop() || ''
|
|
65
|
+
|
|
66
|
+
// Check for dangerous file patterns
|
|
67
|
+
for (const { pattern, name, severity } of DANGEROUS_FILE_PATTERNS) {
|
|
68
|
+
if (pattern.test(fileName) || pattern.test(filePath)) {
|
|
69
|
+
vulnerabilities.push({
|
|
70
|
+
id: `file-flag-${filePath}`,
|
|
71
|
+
filePath,
|
|
72
|
+
lineNumber: 1,
|
|
73
|
+
lineContent: `File: ${fileName}`,
|
|
74
|
+
severity,
|
|
75
|
+
category: 'dangerous_file',
|
|
76
|
+
title: `Dangerous file detected: ${name}`,
|
|
77
|
+
description: `This file type (${name}) should not be committed to version control as it may contain sensitive information.`,
|
|
78
|
+
suggestedFix: 'Add this file to .gitignore and remove it from the repository. If it contains secrets, rotate them immediately.',
|
|
79
|
+
confidence: 'high',
|
|
80
|
+
layer: 1,
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Check context-sensitive files for actual secrets
|
|
86
|
+
for (const { pattern, name, checkContent } of CONTEXT_SENSITIVE_PATTERNS) {
|
|
87
|
+
if ((pattern.test(fileName) || pattern.test(filePath)) && checkContent) {
|
|
88
|
+
// Check if the example/sample file contains what looks like real values
|
|
89
|
+
const suspiciousPatterns = [
|
|
90
|
+
/[a-zA-Z0-9_]+=sk-[a-zA-Z0-9]{20,}/, // API keys
|
|
91
|
+
/[a-zA-Z0-9_]+=ghp_[a-zA-Z0-9]{36,}/, // GitHub tokens
|
|
92
|
+
/[a-zA-Z0-9_]+=eyJ[a-zA-Z0-9_-]+\./, // JWT tokens
|
|
93
|
+
/password\s*=\s*[^\s$]{8,}/i, // Passwords (not env vars)
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
const lines = content.split('\n')
|
|
97
|
+
for (let i = 0; i < lines.length; i++) {
|
|
98
|
+
const line = lines[i]
|
|
99
|
+
// Skip lines that reference environment variables
|
|
100
|
+
if (line.includes('${') || line.includes('$env:') || line.includes('process.env')) {
|
|
101
|
+
continue
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
for (const suspicious of suspiciousPatterns) {
|
|
105
|
+
if (suspicious.test(line)) {
|
|
106
|
+
vulnerabilities.push({
|
|
107
|
+
id: `file-flag-content-${filePath}-${i + 1}`,
|
|
108
|
+
filePath,
|
|
109
|
+
lineNumber: i + 1,
|
|
110
|
+
lineContent: line.trim(),
|
|
111
|
+
severity: 'high',
|
|
112
|
+
category: 'dangerous_file',
|
|
113
|
+
title: `${name} may contain real secrets`,
|
|
114
|
+
description: 'This example/sample file appears to contain real secret values instead of placeholders.',
|
|
115
|
+
suggestedFix: 'Replace real values with placeholders like YOUR_API_KEY_HERE or use environment variable references.',
|
|
116
|
+
confidence: 'medium',
|
|
117
|
+
layer: 1,
|
|
118
|
+
})
|
|
119
|
+
break
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return vulnerabilities
|
|
127
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 1: Surface Scan
|
|
3
|
+
* Fast, deterministic scanning using entropy, patterns, config auditing,
|
|
4
|
+
* file flags, comment analysis, URL detection, and weak crypto detection
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Vulnerability, ScanFile } from '../types'
|
|
8
|
+
import { detectHighEntropyStrings } from './entropy'
|
|
9
|
+
import { detectKnownPatterns } from './patterns'
|
|
10
|
+
import { auditConfiguration } from './config-audit'
|
|
11
|
+
import { detectDangerousFiles } from './file-flags'
|
|
12
|
+
import { detectAICommentPatterns } from './comments'
|
|
13
|
+
import { detectSensitiveURLs } from './urls'
|
|
14
|
+
import { detectWeakCrypto } from './weak-crypto'
|
|
15
|
+
import {
|
|
16
|
+
type TierStats,
|
|
17
|
+
computeTierStats,
|
|
18
|
+
formatTierStats,
|
|
19
|
+
getLayer1DetectorTier,
|
|
20
|
+
type Layer1DetectorName,
|
|
21
|
+
} from '../tiers'
|
|
22
|
+
import {
|
|
23
|
+
filterFindingsByPath,
|
|
24
|
+
type ExclusionConfig,
|
|
25
|
+
} from '../utils/path-exclusions'
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Layer 1 detector stats for raw finding counts before deduplication
|
|
29
|
+
*/
|
|
30
|
+
export interface Layer1Stats {
|
|
31
|
+
/** Raw finding counts per detector (before dedupe) */
|
|
32
|
+
raw: Record<string, number>
|
|
33
|
+
/** Deduped finding counts per category */
|
|
34
|
+
deduped: Record<string, number>
|
|
35
|
+
/** Tier breakdown of deduped findings */
|
|
36
|
+
tiers: TierStats
|
|
37
|
+
/** Number of findings suppressed by path exclusions */
|
|
38
|
+
suppressedByPath: number
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface Layer1Result {
|
|
42
|
+
vulnerabilities: Vulnerability[]
|
|
43
|
+
filesScanned: number
|
|
44
|
+
duration: number
|
|
45
|
+
/** Heuristic breakdown stats for noise analysis */
|
|
46
|
+
stats: Layer1Stats
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function runLayer1Scan(files: ScanFile[]): Promise<Layer1Result> {
|
|
50
|
+
const startTime = Date.now()
|
|
51
|
+
const vulnerabilities: Vulnerability[] = []
|
|
52
|
+
|
|
53
|
+
// Track raw counts per detector (before dedupe)
|
|
54
|
+
const rawStats: Record<Layer1DetectorName, number> = {
|
|
55
|
+
known_secrets: 0,
|
|
56
|
+
weak_crypto: 0,
|
|
57
|
+
sensitive_urls: 0,
|
|
58
|
+
entropy: 0,
|
|
59
|
+
config_audit: 0,
|
|
60
|
+
file_flags: 0,
|
|
61
|
+
ai_comments: 0,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
for (const file of files) {
|
|
65
|
+
// Run all Layer 1 detectors and track raw counts
|
|
66
|
+
const entropyFindings = detectHighEntropyStrings(file.content, file.path)
|
|
67
|
+
const patternFindings = detectKnownPatterns(file.content, file.path)
|
|
68
|
+
const configFindings = auditConfiguration(file.content, file.path)
|
|
69
|
+
const fileFlags = detectDangerousFiles(file.content, file.path)
|
|
70
|
+
const commentFindings = detectAICommentPatterns(file.content, file.path)
|
|
71
|
+
const urlFindings = detectSensitiveURLs(file.content, file.path)
|
|
72
|
+
const cryptoFindings = detectWeakCrypto(file.content, file.path)
|
|
73
|
+
|
|
74
|
+
rawStats.entropy += entropyFindings.length
|
|
75
|
+
rawStats.known_secrets += patternFindings.length
|
|
76
|
+
rawStats.config_audit += configFindings.length
|
|
77
|
+
rawStats.file_flags += fileFlags.length
|
|
78
|
+
rawStats.ai_comments += commentFindings.length
|
|
79
|
+
rawStats.sensitive_urls += urlFindings.length
|
|
80
|
+
rawStats.weak_crypto += cryptoFindings.length
|
|
81
|
+
|
|
82
|
+
vulnerabilities.push(
|
|
83
|
+
...entropyFindings,
|
|
84
|
+
...patternFindings,
|
|
85
|
+
...configFindings,
|
|
86
|
+
...fileFlags,
|
|
87
|
+
...commentFindings,
|
|
88
|
+
...urlFindings,
|
|
89
|
+
...cryptoFindings
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Deduplicate findings (same line might be caught by multiple detectors)
|
|
94
|
+
const dedupedVulnerabilities = deduplicateFindings(vulnerabilities)
|
|
95
|
+
|
|
96
|
+
// Apply path exclusions to filter out findings in test/seed/example files
|
|
97
|
+
const { kept: uniqueVulnerabilities, suppressed } = filterFindingsByPath(dedupedVulnerabilities)
|
|
98
|
+
|
|
99
|
+
// Log suppressed findings
|
|
100
|
+
if (suppressed.length > 0) {
|
|
101
|
+
const byReason: Record<string, number> = {}
|
|
102
|
+
for (const s of suppressed) {
|
|
103
|
+
const reason = s.reason || 'unknown'
|
|
104
|
+
byReason[reason] = (byReason[reason] || 0) + 1
|
|
105
|
+
}
|
|
106
|
+
console.log(`[Layer 1] Suppressed ${suppressed.length} findings in test/seed/example files:`)
|
|
107
|
+
for (const [reason, count] of Object.entries(byReason)) {
|
|
108
|
+
console.log(` - ${reason}: ${count}`)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Compute deduped counts per category
|
|
113
|
+
const dedupedStats: Record<string, number> = {}
|
|
114
|
+
for (const vuln of uniqueVulnerabilities) {
|
|
115
|
+
const cat = vuln.category
|
|
116
|
+
dedupedStats[cat] = (dedupedStats[cat] || 0) + 1
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Compute tier breakdown (all Layer 1 findings have layer: 1)
|
|
120
|
+
const tierStats = computeTierStats(
|
|
121
|
+
uniqueVulnerabilities.map(v => ({ category: v.category, layer: 1 as const }))
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
// Log heuristic breakdown with tier info
|
|
125
|
+
console.log('[Layer 1] Heuristic breakdown (raw findings before dedupe):')
|
|
126
|
+
for (const [name, count] of Object.entries(rawStats)) {
|
|
127
|
+
if (count > 0) {
|
|
128
|
+
const tier = getLayer1DetectorTier(name as Layer1DetectorName)
|
|
129
|
+
console.log(` - ${name}: ${count} (${tier})`)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
console.log(`[Layer 1] Tier breakdown (after dedupe): ${formatTierStats(tierStats)}`)
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
vulnerabilities: uniqueVulnerabilities,
|
|
136
|
+
filesScanned: files.length,
|
|
137
|
+
duration: Date.now() - startTime,
|
|
138
|
+
stats: {
|
|
139
|
+
raw: rawStats,
|
|
140
|
+
deduped: dedupedStats,
|
|
141
|
+
tiers: tierStats,
|
|
142
|
+
suppressedByPath: suppressed.length,
|
|
143
|
+
},
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Remove duplicate findings on the same line
|
|
148
|
+
function deduplicateFindings(vulnerabilities: Vulnerability[]): Vulnerability[] {
|
|
149
|
+
const seen = new Map<string, Vulnerability>()
|
|
150
|
+
|
|
151
|
+
for (const vuln of vulnerabilities) {
|
|
152
|
+
const key = `${vuln.filePath}:${vuln.lineNumber}:${vuln.category}`
|
|
153
|
+
const existing = seen.get(key)
|
|
154
|
+
|
|
155
|
+
// Keep the higher severity finding
|
|
156
|
+
if (!existing || severityRank(vuln.severity) > severityRank(existing.severity)) {
|
|
157
|
+
seen.set(key, vuln)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return Array.from(seen.values())
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function severityRank(severity: string): number {
|
|
165
|
+
const ranks: Record<string, number> = {
|
|
166
|
+
critical: 5,
|
|
167
|
+
high: 4,
|
|
168
|
+
medium: 3,
|
|
169
|
+
low: 2,
|
|
170
|
+
info: 1,
|
|
171
|
+
}
|
|
172
|
+
return ranks[severity] || 0
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export { detectHighEntropyStrings } from './entropy'
|
|
176
|
+
export { detectKnownPatterns } from './patterns'
|
|
177
|
+
export { auditConfiguration } from './config-audit'
|
|
178
|
+
export { detectDangerousFiles } from './file-flags'
|
|
179
|
+
export { detectAICommentPatterns } from './comments'
|
|
180
|
+
export { detectSensitiveURLs } from './urls'
|
|
181
|
+
export { detectWeakCrypto } from './weak-crypto'
|