@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,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 1: Comment Scanning for AI Patterns
|
|
3
|
+
* Detects suspicious patterns in code comments that may indicate
|
|
4
|
+
* prompt injection attempts or AI-generated security bypasses
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Vulnerability } from '../types'
|
|
8
|
+
|
|
9
|
+
// Patterns that indicate potential prompt injection or AI manipulation
|
|
10
|
+
const AI_COMMENT_PATTERNS = [
|
|
11
|
+
// Prompt injection attempts
|
|
12
|
+
{
|
|
13
|
+
pattern: /ignore\s+(previous|all|above)\s+instructions?/i,
|
|
14
|
+
name: 'Prompt Injection Attempt',
|
|
15
|
+
severity: 'high' as const,
|
|
16
|
+
description: 'Comment contains prompt injection language that could manipulate AI assistants',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
pattern: /disregard\s+(security|safety|previous|all)/i,
|
|
20
|
+
name: 'Security Disregard Instruction',
|
|
21
|
+
severity: 'high' as const,
|
|
22
|
+
description: 'Comment instructs to disregard security measures',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
pattern: /you\s+are\s+now\s+in\s+(developer|debug|admin)\s+mode/i,
|
|
26
|
+
name: 'Mode Override Attempt',
|
|
27
|
+
severity: 'high' as const,
|
|
28
|
+
description: 'Comment attempts to override AI mode or permissions',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
pattern: /override\s+(security|safety)\s+protocols?/i,
|
|
32
|
+
name: 'Security Override Instruction',
|
|
33
|
+
severity: 'high' as const,
|
|
34
|
+
description: 'Comment instructs to override security protocols',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
pattern: /system:\s*ignore/i,
|
|
38
|
+
name: 'System Prompt Injection',
|
|
39
|
+
severity: 'critical' as const,
|
|
40
|
+
description: 'Comment contains system-level prompt injection',
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
// Developer instructions to skip security
|
|
44
|
+
{
|
|
45
|
+
pattern: /skip\s+(security|validation|sanitization|auth)/i,
|
|
46
|
+
name: 'Security Skip Instruction',
|
|
47
|
+
severity: 'medium' as const,
|
|
48
|
+
description: 'Comment instructs to skip security measures',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
pattern: /don['']?t\s+(validate|sanitize|check|verify)/i,
|
|
52
|
+
name: 'Validation Skip Instruction',
|
|
53
|
+
severity: 'medium' as const,
|
|
54
|
+
description: 'Comment instructs to skip validation',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
pattern: /disable\s+(auth|authentication|authorization|csrf|xss)/i,
|
|
58
|
+
name: 'Security Disable Instruction',
|
|
59
|
+
severity: 'high' as const,
|
|
60
|
+
description: 'Comment instructs to disable security features',
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
// Security-related TODOs - downgraded as these are often addressed or intentional
|
|
64
|
+
{
|
|
65
|
+
pattern: /TODO[:\s].*fix.*security/i,
|
|
66
|
+
name: 'Security TODO',
|
|
67
|
+
severity: 'low' as const, // Downgraded from medium
|
|
68
|
+
description: 'Unresolved security-related TODO comment',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
pattern: /FIXME[:\s].*vulnerab/i,
|
|
72
|
+
name: 'Vulnerability FIXME',
|
|
73
|
+
severity: 'medium' as const, // Downgraded from high
|
|
74
|
+
description: 'Unresolved vulnerability-related FIXME comment',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
pattern: /HACK[:\s].*bypass/i,
|
|
78
|
+
name: 'Security Bypass HACK',
|
|
79
|
+
severity: 'medium' as const, // Downgraded from high
|
|
80
|
+
description: 'Hack comment indicating security bypass',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
pattern: /TODO[:\s].*add\s+(auth|authentication|authorization)/i,
|
|
84
|
+
name: 'Missing Auth TODO',
|
|
85
|
+
severity: 'low' as const, // Downgraded from high - often outdated or in test code
|
|
86
|
+
description: 'TODO indicates authentication may need implementation',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
pattern: /TODO[:\s].*implement\s+(validation|sanitization)/i,
|
|
90
|
+
name: 'Missing Validation TODO',
|
|
91
|
+
severity: 'low' as const, // Downgraded from medium
|
|
92
|
+
description: 'TODO indicates validation may need implementation',
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
// AI-generated placeholder patterns - downgraded to info (usually harmless)
|
|
96
|
+
{
|
|
97
|
+
pattern: /TODO[:\s].*add\s+proper\s+error\s+handling/i,
|
|
98
|
+
name: 'AI Placeholder: Error Handling',
|
|
99
|
+
severity: 'info' as const, // Downgraded from low
|
|
100
|
+
description: 'AI-typical placeholder comment for error handling',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
pattern: /TODO[:\s].*implement\s+proper/i,
|
|
104
|
+
name: 'AI Placeholder: Implementation',
|
|
105
|
+
severity: 'info' as const, // Downgraded from low
|
|
106
|
+
description: 'AI-typical placeholder comment for implementation',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
pattern: /add\s+your\s+(code|logic|implementation)\s+here/i,
|
|
110
|
+
name: 'AI Placeholder: Code Here',
|
|
111
|
+
severity: 'info' as const, // Downgraded from low
|
|
112
|
+
description: 'AI-typical placeholder comment',
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
// Temporary security bypasses
|
|
116
|
+
{
|
|
117
|
+
pattern: /temporary\s+(bypass|workaround|fix).*security/i,
|
|
118
|
+
name: 'Temporary Security Bypass',
|
|
119
|
+
severity: 'medium' as const, // Downgraded from high
|
|
120
|
+
description: 'Comment indicates temporary security bypass that may have become permanent',
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
pattern: /remove\s+(before|in)\s+production/i,
|
|
124
|
+
name: 'Pre-Production Code',
|
|
125
|
+
severity: 'low' as const, // Downgraded from medium
|
|
126
|
+
description: 'Comment indicates code should be removed before production',
|
|
127
|
+
},
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
// Extract comments from code
|
|
131
|
+
function extractComments(content: string): Array<{ text: string; line: number; lineContent: string }> {
|
|
132
|
+
const comments: Array<{ text: string; line: number; lineContent: string }> = []
|
|
133
|
+
const lines = content.split('\n')
|
|
134
|
+
|
|
135
|
+
let inBlockComment = false
|
|
136
|
+
let blockCommentStart = 0
|
|
137
|
+
let blockCommentText = ''
|
|
138
|
+
|
|
139
|
+
for (let i = 0; i < lines.length; i++) {
|
|
140
|
+
const line = lines[i]
|
|
141
|
+
const trimmed = line.trim()
|
|
142
|
+
|
|
143
|
+
// Handle block comments
|
|
144
|
+
if (inBlockComment) {
|
|
145
|
+
if (trimmed.includes('*/')) {
|
|
146
|
+
inBlockComment = false
|
|
147
|
+
blockCommentText += ' ' + trimmed.replace(/\*\/.*$/, '')
|
|
148
|
+
comments.push({
|
|
149
|
+
text: blockCommentText,
|
|
150
|
+
line: blockCommentStart + 1,
|
|
151
|
+
lineContent: lines[blockCommentStart].trim(),
|
|
152
|
+
})
|
|
153
|
+
blockCommentText = ''
|
|
154
|
+
} else {
|
|
155
|
+
blockCommentText += ' ' + trimmed.replace(/^\*\s*/, '')
|
|
156
|
+
}
|
|
157
|
+
continue
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Start of block comment
|
|
161
|
+
if (trimmed.includes('/*')) {
|
|
162
|
+
if (trimmed.includes('*/')) {
|
|
163
|
+
// Single-line block comment
|
|
164
|
+
const text = trimmed.replace(/\/\*|\*\//g, '')
|
|
165
|
+
comments.push({ text, line: i + 1, lineContent: trimmed })
|
|
166
|
+
} else {
|
|
167
|
+
inBlockComment = true
|
|
168
|
+
blockCommentStart = i
|
|
169
|
+
blockCommentText = trimmed.replace(/\/\*/, '')
|
|
170
|
+
}
|
|
171
|
+
continue
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Single-line comments
|
|
175
|
+
const singleLineMatch = trimmed.match(/\/\/(.*)$|#(.*)$/)
|
|
176
|
+
if (singleLineMatch) {
|
|
177
|
+
const text = singleLineMatch[1] || singleLineMatch[2] || ''
|
|
178
|
+
comments.push({ text, line: i + 1, lineContent: trimmed })
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return comments
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function detectAICommentPatterns(
|
|
186
|
+
content: string,
|
|
187
|
+
filePath: string
|
|
188
|
+
): Vulnerability[] {
|
|
189
|
+
const vulnerabilities: Vulnerability[] = []
|
|
190
|
+
const comments = extractComments(content)
|
|
191
|
+
|
|
192
|
+
for (const comment of comments) {
|
|
193
|
+
for (const { pattern, name, severity, description } of AI_COMMENT_PATTERNS) {
|
|
194
|
+
if (pattern.test(comment.text)) {
|
|
195
|
+
// Most comment-based findings require AI validation to confirm relevance
|
|
196
|
+
const requiresAIValidation = severity !== 'critical'
|
|
197
|
+
|
|
198
|
+
vulnerabilities.push({
|
|
199
|
+
id: `ai-comment-${filePath}-${comment.line}`,
|
|
200
|
+
filePath,
|
|
201
|
+
lineNumber: comment.line,
|
|
202
|
+
lineContent: comment.lineContent,
|
|
203
|
+
severity,
|
|
204
|
+
category: 'ai_pattern',
|
|
205
|
+
title: name,
|
|
206
|
+
description,
|
|
207
|
+
suggestedFix: 'Review and address this comment. If it indicates a security issue, fix it. If it\'s a prompt injection attempt, remove it.',
|
|
208
|
+
confidence: severity === 'critical' || severity === 'high' ? 'high' : 'low', // Lower default confidence
|
|
209
|
+
layer: 1,
|
|
210
|
+
requiresAIValidation,
|
|
211
|
+
})
|
|
212
|
+
break // Only report one pattern per comment
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return vulnerabilities
|
|
218
|
+
}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 1: Configuration Auditing
|
|
3
|
+
* Scans configuration files for security misconfigurations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ConfigRule, ConfigViolation, Vulnerability } from '../types'
|
|
7
|
+
|
|
8
|
+
// Configuration audit rules
|
|
9
|
+
export const CONFIG_RULES: ConfigRule[] = [
|
|
10
|
+
// Dockerfile rules
|
|
11
|
+
{
|
|
12
|
+
name: 'Docker running as root',
|
|
13
|
+
filePatterns: ['Dockerfile', '*.dockerfile'],
|
|
14
|
+
check: (content: string): ConfigViolation[] => {
|
|
15
|
+
const violations: ConfigViolation[] = []
|
|
16
|
+
const lines = content.split('\n')
|
|
17
|
+
|
|
18
|
+
// Check if USER instruction exists
|
|
19
|
+
const hasUserInstruction = lines.some(line =>
|
|
20
|
+
line.trim().toUpperCase().startsWith('USER ')
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
// Check for explicit root user
|
|
24
|
+
lines.forEach((line, index) => {
|
|
25
|
+
if (line.trim().toUpperCase() === 'USER ROOT') {
|
|
26
|
+
violations.push({
|
|
27
|
+
line: index + 1,
|
|
28
|
+
lineContent: line.trim(),
|
|
29
|
+
message: 'Container explicitly runs as root user',
|
|
30
|
+
severity: 'high',
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
// If no USER instruction at all, flag it
|
|
36
|
+
if (!hasUserInstruction && lines.length > 5) {
|
|
37
|
+
violations.push({
|
|
38
|
+
line: 1,
|
|
39
|
+
lineContent: 'Dockerfile',
|
|
40
|
+
message: 'No USER instruction found - container will run as root by default',
|
|
41
|
+
severity: 'medium',
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return violations
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'Hardcoded secrets in Docker build args',
|
|
50
|
+
filePatterns: ['Dockerfile', '*.dockerfile', 'docker-compose.yml', 'docker-compose.yaml'],
|
|
51
|
+
check: (content: string): ConfigViolation[] => {
|
|
52
|
+
const violations: ConfigViolation[] = []
|
|
53
|
+
const lines = content.split('\n')
|
|
54
|
+
|
|
55
|
+
const sensitivePatterns = [
|
|
56
|
+
/ARG\s+\w*(PASSWORD|SECRET|KEY|TOKEN|CREDENTIAL)\w*\s*=\s*[^\s$]/i,
|
|
57
|
+
/ENV\s+\w*(PASSWORD|SECRET|KEY|TOKEN|CREDENTIAL)\w*\s*=\s*[^\s$]/i,
|
|
58
|
+
/environment:[\s\S]*?(PASSWORD|SECRET|KEY|TOKEN)\s*[:=]\s*[^\s${\n]/i,
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
lines.forEach((line, index) => {
|
|
62
|
+
for (const pattern of sensitivePatterns) {
|
|
63
|
+
if (pattern.test(line)) {
|
|
64
|
+
violations.push({
|
|
65
|
+
line: index + 1,
|
|
66
|
+
lineContent: line.trim(),
|
|
67
|
+
message: 'Hardcoded sensitive value in build argument or environment variable',
|
|
68
|
+
severity: 'critical',
|
|
69
|
+
})
|
|
70
|
+
break
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
return violations
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
// CORS configuration
|
|
79
|
+
{
|
|
80
|
+
name: 'Permissive CORS configuration',
|
|
81
|
+
filePatterns: ['*.ts', '*.js', '*.tsx', '*.jsx', 'next.config.*', 'vercel.json', '*.yaml', '*.yml'],
|
|
82
|
+
check: (content: string): ConfigViolation[] => {
|
|
83
|
+
const violations: ConfigViolation[] = []
|
|
84
|
+
const lines = content.split('\n')
|
|
85
|
+
|
|
86
|
+
const corsPatterns = [
|
|
87
|
+
/['"]Access-Control-Allow-Origin['"]\s*[,:]\s*['"]\*['"]/i,
|
|
88
|
+
/cors\s*\(\s*\{\s*origin\s*:\s*['"]\*['"]/i,
|
|
89
|
+
/origin\s*:\s*['"]\*['"]/i,
|
|
90
|
+
/allowedOrigins?\s*[=:]\s*\[\s*['"]\*['"]/i,
|
|
91
|
+
/Access-Control-Allow-Origin:\s*\*/i,
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
lines.forEach((line, index) => {
|
|
95
|
+
for (const pattern of corsPatterns) {
|
|
96
|
+
if (pattern.test(line)) {
|
|
97
|
+
violations.push({
|
|
98
|
+
line: index + 1,
|
|
99
|
+
lineContent: line.trim(),
|
|
100
|
+
message: 'Permissive CORS policy allows requests from any origin (*)',
|
|
101
|
+
severity: 'medium',
|
|
102
|
+
})
|
|
103
|
+
break
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
return violations
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
// GitHub Actions secrets exposure
|
|
112
|
+
{
|
|
113
|
+
name: 'GitHub Actions security issues',
|
|
114
|
+
filePatterns: ['.github/workflows/*.yml', '.github/workflows/*.yaml'],
|
|
115
|
+
check: (content: string): ConfigViolation[] => {
|
|
116
|
+
const violations: ConfigViolation[] = []
|
|
117
|
+
const lines = content.split('\n')
|
|
118
|
+
|
|
119
|
+
// Check for pull_request_target with checkout
|
|
120
|
+
const hasPRTarget = content.includes('pull_request_target')
|
|
121
|
+
const hasCheckout = content.includes('actions/checkout')
|
|
122
|
+
|
|
123
|
+
if (hasPRTarget && hasCheckout) {
|
|
124
|
+
const checkoutLine = lines.findIndex(l => l.includes('actions/checkout'))
|
|
125
|
+
violations.push({
|
|
126
|
+
line: checkoutLine + 1,
|
|
127
|
+
lineContent: lines[checkoutLine]?.trim() || '',
|
|
128
|
+
message: 'Using actions/checkout with pull_request_target can expose secrets to untrusted code',
|
|
129
|
+
severity: 'high',
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Check for hardcoded secrets
|
|
134
|
+
lines.forEach((line, index) => {
|
|
135
|
+
if (/env:\s*\w+\s*=\s*['"][^$]/.test(line) &&
|
|
136
|
+
/(SECRET|TOKEN|KEY|PASSWORD)/i.test(line)) {
|
|
137
|
+
violations.push({
|
|
138
|
+
line: index + 1,
|
|
139
|
+
lineContent: line.trim(),
|
|
140
|
+
message: 'Potential hardcoded secret in GitHub Actions workflow',
|
|
141
|
+
severity: 'critical',
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
return violations
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
// Next.js security config
|
|
150
|
+
{
|
|
151
|
+
name: 'Next.js security configuration',
|
|
152
|
+
filePatterns: ['next.config.js', 'next.config.ts', 'next.config.mjs'],
|
|
153
|
+
check: (content: string): ConfigViolation[] => {
|
|
154
|
+
const violations: ConfigViolation[] = []
|
|
155
|
+
const lines = content.split('\n')
|
|
156
|
+
|
|
157
|
+
// Only flag if poweredByHeader is explicitly set to true (not if missing)
|
|
158
|
+
if (content.includes('poweredByHeader: true') || content.includes('poweredByHeader:true')) {
|
|
159
|
+
const lineIndex = lines.findIndex(l => l.includes('poweredByHeader'))
|
|
160
|
+
violations.push({
|
|
161
|
+
line: lineIndex >= 0 ? lineIndex + 1 : 1,
|
|
162
|
+
lineContent: lines[lineIndex]?.trim() || 'poweredByHeader: true',
|
|
163
|
+
message: 'poweredByHeader is enabled - consider setting to false to hide X-Powered-By header',
|
|
164
|
+
severity: 'low',
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Check for exposed source maps in production
|
|
169
|
+
lines.forEach((line, index) => {
|
|
170
|
+
if (/productionBrowserSourceMaps\s*:\s*true/.test(line)) {
|
|
171
|
+
violations.push({
|
|
172
|
+
line: index + 1,
|
|
173
|
+
lineContent: line.trim(),
|
|
174
|
+
message: 'Production source maps are enabled - this exposes your source code',
|
|
175
|
+
severity: 'medium',
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
return violations
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
// Package.json security
|
|
184
|
+
{
|
|
185
|
+
name: 'Package.json security issues',
|
|
186
|
+
filePatterns: ['package.json'],
|
|
187
|
+
check: (content: string): ConfigViolation[] => {
|
|
188
|
+
const violations: ConfigViolation[] = []
|
|
189
|
+
|
|
190
|
+
try {
|
|
191
|
+
const pkg = JSON.parse(content)
|
|
192
|
+
|
|
193
|
+
// Check for postinstall scripts that could be malicious
|
|
194
|
+
if (pkg.scripts?.postinstall || pkg.scripts?.preinstall) {
|
|
195
|
+
const lines = content.split('\n')
|
|
196
|
+
const scriptLine = lines.findIndex(l =>
|
|
197
|
+
l.includes('"postinstall"') || l.includes('"preinstall"')
|
|
198
|
+
)
|
|
199
|
+
violations.push({
|
|
200
|
+
line: scriptLine + 1,
|
|
201
|
+
lineContent: lines[scriptLine]?.trim() || '',
|
|
202
|
+
message: 'Pre/post install scripts can execute arbitrary code - review carefully',
|
|
203
|
+
severity: 'low',
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Check for wildcard dependencies
|
|
208
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies }
|
|
209
|
+
const lines = content.split('\n')
|
|
210
|
+
|
|
211
|
+
for (const [name, version] of Object.entries(allDeps)) {
|
|
212
|
+
if (version === '*' || version === 'latest') {
|
|
213
|
+
const depLine = lines.findIndex(l => l.includes(`"${name}"`))
|
|
214
|
+
violations.push({
|
|
215
|
+
line: depLine + 1,
|
|
216
|
+
lineContent: lines[depLine]?.trim() || '',
|
|
217
|
+
message: `Dependency "${name}" uses wildcard/latest version - pin to specific version`,
|
|
218
|
+
severity: 'medium',
|
|
219
|
+
})
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
} catch {
|
|
223
|
+
// Invalid JSON, skip
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return violations
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
]
|
|
230
|
+
|
|
231
|
+
// Check if file matches any of the patterns
|
|
232
|
+
function matchesFilePattern(filePath: string, patterns: string[]): boolean {
|
|
233
|
+
const fileName = filePath.split('/').pop() || ''
|
|
234
|
+
|
|
235
|
+
return patterns.some(pattern => {
|
|
236
|
+
if (pattern.includes('*')) {
|
|
237
|
+
const regex = new RegExp(
|
|
238
|
+
'^' + pattern.replace(/\*/g, '.*').replace(/\./g, '\\.') + '$',
|
|
239
|
+
'i'
|
|
240
|
+
)
|
|
241
|
+
return regex.test(fileName) || regex.test(filePath)
|
|
242
|
+
}
|
|
243
|
+
return fileName === pattern || filePath.endsWith(pattern)
|
|
244
|
+
})
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export function auditConfiguration(
|
|
248
|
+
content: string,
|
|
249
|
+
filePath: string
|
|
250
|
+
): Vulnerability[] {
|
|
251
|
+
const vulnerabilities: Vulnerability[] = []
|
|
252
|
+
|
|
253
|
+
for (const rule of CONFIG_RULES) {
|
|
254
|
+
if (matchesFilePattern(filePath, rule.filePatterns)) {
|
|
255
|
+
const violations = rule.check(content, filePath)
|
|
256
|
+
|
|
257
|
+
for (const violation of violations) {
|
|
258
|
+
vulnerabilities.push({
|
|
259
|
+
id: `config-${filePath}-${violation.line}-${rule.name}`,
|
|
260
|
+
filePath,
|
|
261
|
+
lineNumber: violation.line,
|
|
262
|
+
lineContent: violation.lineContent,
|
|
263
|
+
severity: violation.severity,
|
|
264
|
+
category: 'insecure_config',
|
|
265
|
+
title: rule.name,
|
|
266
|
+
description: violation.message,
|
|
267
|
+
suggestedFix: getConfigFix(rule.name, violation),
|
|
268
|
+
confidence: 'high',
|
|
269
|
+
layer: 1,
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return vulnerabilities
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function getConfigFix(ruleName: string, violation: ConfigViolation): string {
|
|
279
|
+
const fixes: Record<string, string> = {
|
|
280
|
+
'Docker running as root': 'Add a USER instruction to run as a non-root user: USER node',
|
|
281
|
+
'Hardcoded secrets in Docker build args': 'Use Docker secrets or pass values at runtime via environment variables',
|
|
282
|
+
'Permissive CORS configuration': 'Specify allowed origins explicitly instead of using wildcard (*)',
|
|
283
|
+
'GitHub Actions security issues': 'Use secrets context (${{ secrets.NAME }}) for sensitive values',
|
|
284
|
+
'Next.js security configuration': 'Review Next.js security best practices and configure headers appropriately',
|
|
285
|
+
'Package.json security issues': 'Pin dependencies to specific versions and review install scripts',
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return fixes[ruleName] || 'Review and fix the security configuration'
|
|
289
|
+
}
|