@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,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scan Depth Snapshot Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests the scanner output at different depth levels to ensure consistent results.
|
|
5
|
+
* Snapshots help detect unintended changes to scanner behavior.
|
|
6
|
+
*
|
|
7
|
+
* Run: npx jest src/__tests__/snapshots/scan-depth.test.ts
|
|
8
|
+
* Update snapshots: npx jest --updateSnapshot
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { runLayer1Scan } from '../../layer1'
|
|
12
|
+
import { runLayer2Scan } from '../../layer2'
|
|
13
|
+
import type { ScanFile, Vulnerability } from '../../types'
|
|
14
|
+
|
|
15
|
+
// Helper to normalize vulnerability output for snapshot comparison
|
|
16
|
+
// Removes volatile fields like timestamps and IDs
|
|
17
|
+
function normalizeVulnerabilities(vulns: Vulnerability[]): object[] {
|
|
18
|
+
return vulns
|
|
19
|
+
.map(v => ({
|
|
20
|
+
category: v.category,
|
|
21
|
+
severity: v.severity,
|
|
22
|
+
confidence: v.confidence,
|
|
23
|
+
layer: v.layer,
|
|
24
|
+
title: v.title,
|
|
25
|
+
lineNumber: v.lineNumber,
|
|
26
|
+
// Normalize line content to avoid whitespace issues
|
|
27
|
+
lineContent: v.lineContent?.trim(),
|
|
28
|
+
}))
|
|
29
|
+
.sort((a, b) => {
|
|
30
|
+
// Sort by line number, then category for consistent ordering
|
|
31
|
+
if (a.lineNumber !== b.lineNumber) return (a.lineNumber || 0) - (b.lineNumber || 0)
|
|
32
|
+
return a.category.localeCompare(b.category)
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Helper to run a cheap scan (Layer 1 only, no AI)
|
|
37
|
+
async function runCheapScan(file: ScanFile): Promise<object[]> {
|
|
38
|
+
const layer1Result = await runLayer1Scan([file])
|
|
39
|
+
return normalizeVulnerabilities(layer1Result.vulnerabilities)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Helper to run a full scan (Layer 1 + Layer 2, no AI validation)
|
|
43
|
+
async function runFullScan(file: ScanFile): Promise<object[]> {
|
|
44
|
+
const [layer1Result, layer2Result] = await Promise.all([
|
|
45
|
+
runLayer1Scan([file]),
|
|
46
|
+
runLayer2Scan([file]),
|
|
47
|
+
])
|
|
48
|
+
return normalizeVulnerabilities([...layer1Result.vulnerabilities, ...layer2Result.vulnerabilities])
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
describe('Scan Depth Snapshots', () => {
|
|
52
|
+
describe('Clean File - No Findings Expected', () => {
|
|
53
|
+
const cleanFile: ScanFile = {
|
|
54
|
+
path: 'src/utils/helpers.ts',
|
|
55
|
+
content: `
|
|
56
|
+
/**
|
|
57
|
+
* Safe utility functions
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
export function formatDate(date: Date): string {
|
|
61
|
+
return date.toISOString()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function capitalize(str: string): string {
|
|
65
|
+
return str.charAt(0).toUpperCase() + str.slice(1)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function clamp(value: number, min: number, max: number): number {
|
|
69
|
+
return Math.min(Math.max(value, min), max)
|
|
70
|
+
}
|
|
71
|
+
`,
|
|
72
|
+
language: 'typescript',
|
|
73
|
+
size: 300,
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
it('cheap scan should produce no findings', async () => {
|
|
77
|
+
const results = await runCheapScan(cleanFile)
|
|
78
|
+
expect(results).toMatchSnapshot()
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('full scan should produce no findings', async () => {
|
|
82
|
+
const results = await runFullScan(cleanFile)
|
|
83
|
+
expect(results).toMatchSnapshot()
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
describe('Hardcoded Secrets - Critical Findings', () => {
|
|
88
|
+
const secretsFile: ScanFile = {
|
|
89
|
+
path: 'src/config/api-keys.ts',
|
|
90
|
+
content: `
|
|
91
|
+
// API Keys - CRITICAL
|
|
92
|
+
const OPENAI_API_KEY = "sk-proj-abc123def456ghi789jkl012mno345pqr678stu901vwx"
|
|
93
|
+
const AWS_ACCESS_KEY_ID = "AKIAIOSFODNN7EXAMPLE"
|
|
94
|
+
const AWS_SECRET_ACCESS_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
|
|
95
|
+
`,
|
|
96
|
+
language: 'typescript',
|
|
97
|
+
size: 250,
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
it('cheap scan should detect hardcoded secrets', async () => {
|
|
101
|
+
const results = await runCheapScan(secretsFile)
|
|
102
|
+
expect(results).toMatchSnapshot()
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
it('full scan should detect hardcoded secrets', async () => {
|
|
106
|
+
const results = await runFullScan(secretsFile)
|
|
107
|
+
expect(results).toMatchSnapshot()
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
describe('Mixed Severity - Multiple Issue Types', () => {
|
|
112
|
+
const mixedFile: ScanFile = {
|
|
113
|
+
path: 'src/api/handler.ts',
|
|
114
|
+
content: `
|
|
115
|
+
import express from 'express'
|
|
116
|
+
|
|
117
|
+
const app = express()
|
|
118
|
+
|
|
119
|
+
// Hardcoded secret - CRITICAL
|
|
120
|
+
const API_KEY = "sk-live-1234567890abcdef"
|
|
121
|
+
|
|
122
|
+
// CORS wildcard - MEDIUM
|
|
123
|
+
app.use(cors({ origin: '*' }))
|
|
124
|
+
|
|
125
|
+
// Weak crypto - HIGH
|
|
126
|
+
const hash = crypto.createHash('md5')
|
|
127
|
+
|
|
128
|
+
// innerHTML with user input - HIGH
|
|
129
|
+
element.innerHTML = userInput
|
|
130
|
+
|
|
131
|
+
// Debug logging - LOW
|
|
132
|
+
console.log('Debug:', sensitiveData)
|
|
133
|
+
`,
|
|
134
|
+
language: 'typescript',
|
|
135
|
+
size: 400,
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
it('cheap scan should detect Layer 1 issues', async () => {
|
|
139
|
+
const results = await runCheapScan(mixedFile)
|
|
140
|
+
expect(results).toMatchSnapshot()
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('full scan should detect all issues', async () => {
|
|
144
|
+
const results = await runFullScan(mixedFile)
|
|
145
|
+
expect(results).toMatchSnapshot()
|
|
146
|
+
})
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
describe('AI-Era Patterns - Modern Security Issues', () => {
|
|
150
|
+
const aiEraFile: ScanFile = {
|
|
151
|
+
path: 'src/ai/chat-handler.ts',
|
|
152
|
+
content: `
|
|
153
|
+
import OpenAI from 'openai'
|
|
154
|
+
|
|
155
|
+
// User API key in request - transient BYOK
|
|
156
|
+
export async function handleChat(req: Request) {
|
|
157
|
+
const openai = new OpenAI({ apiKey: req.body.userApiKey })
|
|
158
|
+
|
|
159
|
+
// User input directly in prompt - prompt injection risk
|
|
160
|
+
const response = await openai.chat.completions.create({
|
|
161
|
+
model: 'gpt-4',
|
|
162
|
+
messages: [{ role: 'user', content: req.body.message }],
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
return response.choices[0].message
|
|
166
|
+
}
|
|
167
|
+
`,
|
|
168
|
+
language: 'typescript',
|
|
169
|
+
size: 400,
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
it('cheap scan should detect Layer 1 patterns', async () => {
|
|
173
|
+
const results = await runCheapScan(aiEraFile)
|
|
174
|
+
expect(results).toMatchSnapshot()
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it('full scan should detect AI-era security patterns', async () => {
|
|
178
|
+
const results = await runFullScan(aiEraFile)
|
|
179
|
+
expect(results).toMatchSnapshot()
|
|
180
|
+
})
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
describe('Auth Patterns - Missing Authentication', () => {
|
|
184
|
+
const authFile: ScanFile = {
|
|
185
|
+
path: 'src/app/api/users/route.ts',
|
|
186
|
+
content: `
|
|
187
|
+
import { NextResponse } from 'next/server'
|
|
188
|
+
import { db } from '@/lib/db'
|
|
189
|
+
|
|
190
|
+
// API route without auth check
|
|
191
|
+
export async function GET(request: Request) {
|
|
192
|
+
const users = await db.user.findMany()
|
|
193
|
+
return NextResponse.json(users)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export async function DELETE(request: Request) {
|
|
197
|
+
const { id } = await request.json()
|
|
198
|
+
await db.user.delete({ where: { id } })
|
|
199
|
+
return NextResponse.json({ success: true })
|
|
200
|
+
}
|
|
201
|
+
`,
|
|
202
|
+
language: 'typescript',
|
|
203
|
+
size: 350,
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
it('cheap scan should detect basic patterns', async () => {
|
|
207
|
+
const results = await runCheapScan(authFile)
|
|
208
|
+
expect(results).toMatchSnapshot()
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it('full scan should detect missing auth patterns', async () => {
|
|
212
|
+
const results = await runFullScan(authFile)
|
|
213
|
+
expect(results).toMatchSnapshot()
|
|
214
|
+
})
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
describe('Safe File - No False Positives', () => {
|
|
218
|
+
const safeFile: ScanFile = {
|
|
219
|
+
path: 'src/components/Dashboard.tsx',
|
|
220
|
+
content: `
|
|
221
|
+
import { useState, useEffect } from 'react'
|
|
222
|
+
|
|
223
|
+
// CSS classes - should NOT be flagged as high entropy
|
|
224
|
+
const styles = 'flex items-center justify-between p-4 bg-gray-100'
|
|
225
|
+
|
|
226
|
+
// Environment variable reference - should NOT be flagged
|
|
227
|
+
const apiUrl = process.env.API_URL
|
|
228
|
+
|
|
229
|
+
// UUID - should NOT be flagged as secret
|
|
230
|
+
const sessionId = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
|
|
231
|
+
|
|
232
|
+
export function Dashboard() {
|
|
233
|
+
const [data, setData] = useState(null)
|
|
234
|
+
|
|
235
|
+
useEffect(() => {
|
|
236
|
+
fetch(apiUrl + '/data')
|
|
237
|
+
.then(res => res.json())
|
|
238
|
+
.then(setData)
|
|
239
|
+
}, [])
|
|
240
|
+
|
|
241
|
+
return <div className={styles}>{data}</div>
|
|
242
|
+
}
|
|
243
|
+
`,
|
|
244
|
+
language: 'typescript',
|
|
245
|
+
size: 500,
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
it('cheap scan should produce minimal findings', async () => {
|
|
249
|
+
const results = await runCheapScan(safeFile)
|
|
250
|
+
expect(results).toMatchSnapshot()
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
it('full scan should produce minimal findings', async () => {
|
|
254
|
+
const results = await runFullScan(safeFile)
|
|
255
|
+
expect(results).toMatchSnapshot()
|
|
256
|
+
})
|
|
257
|
+
})
|
|
258
|
+
})
|