@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,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 2: Risky Import/Package Analysis
|
|
3
|
+
* Detects imports of packages known to have security concerns or deprecated
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Vulnerability, VulnerabilitySeverity } from '../types'
|
|
7
|
+
|
|
8
|
+
interface RiskyPackage {
|
|
9
|
+
name: string
|
|
10
|
+
pattern: RegExp
|
|
11
|
+
severity: VulnerabilitySeverity
|
|
12
|
+
description: string
|
|
13
|
+
suggestedFix: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const RISKY_PACKAGES: RiskyPackage[] = [
|
|
17
|
+
// Known vulnerable or deprecated packages
|
|
18
|
+
{
|
|
19
|
+
name: 'request (deprecated)',
|
|
20
|
+
pattern: /require\s*\(\s*['"]request['"]\s*\)|from\s+['"]request['"]/gi,
|
|
21
|
+
severity: 'medium',
|
|
22
|
+
description: 'The "request" package is deprecated and no longer maintained',
|
|
23
|
+
suggestedFix: 'Migrate to fetch, axios, or node-fetch',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'node-uuid (deprecated)',
|
|
27
|
+
pattern: /require\s*\(\s*['"]node-uuid['"]\s*\)|from\s+['"]node-uuid['"]/gi,
|
|
28
|
+
severity: 'low',
|
|
29
|
+
description: 'node-uuid is deprecated in favor of uuid package',
|
|
30
|
+
suggestedFix: 'Use the "uuid" package instead',
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
// Packages with known security issues
|
|
34
|
+
{
|
|
35
|
+
name: 'lodash (full import)',
|
|
36
|
+
pattern: /require\s*\(\s*['"]lodash['"]\s*\)|import\s+\*?\s*(?:as\s+)?\w+\s+from\s+['"]lodash['"]/gi,
|
|
37
|
+
severity: 'low',
|
|
38
|
+
description: 'Full lodash import increases bundle size and attack surface',
|
|
39
|
+
suggestedFix: 'Import specific functions: import get from "lodash/get"',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'moment.js (deprecated)',
|
|
43
|
+
pattern: /require\s*\(\s*['"]moment['"]\s*\)|from\s+['"]moment['"]/gi,
|
|
44
|
+
severity: 'low',
|
|
45
|
+
description: 'Moment.js is in maintenance mode, consider alternatives',
|
|
46
|
+
suggestedFix: 'Use date-fns, dayjs, or native Intl APIs',
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
// Security-focused sandbox packages - info only (these are used for security, not risky)
|
|
50
|
+
{
|
|
51
|
+
name: 'vm2 (sandbox)',
|
|
52
|
+
pattern: /require\s*\(\s*['"]vm2['"]\s*\)|from\s+['"]vm2['"]/gi,
|
|
53
|
+
severity: 'info',
|
|
54
|
+
description: 'vm2 is a sandboxing library. While it has had sandbox escape vulnerabilities historically, using it is generally safer than running untrusted code directly. Keep vm2 updated.',
|
|
55
|
+
suggestedFix: 'Keep vm2 updated to the latest version. For maximum isolation, consider isolated-vm or running in a separate process.',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'serialize-javascript (RCE risk)',
|
|
59
|
+
pattern: /require\s*\(\s*['"]serialize-javascript['"]\s*\)|from\s+['"]serialize-javascript['"]/gi,
|
|
60
|
+
severity: 'medium',
|
|
61
|
+
description: 'serialize-javascript can be dangerous if output is not properly handled',
|
|
62
|
+
suggestedFix: 'Ensure serialized output is not directly executed or use JSON.stringify',
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
// Crypto-related risky imports
|
|
66
|
+
{
|
|
67
|
+
name: 'crypto-js (outdated patterns)',
|
|
68
|
+
pattern: /require\s*\(\s*['"]crypto-js['"]\s*\)|from\s+['"]crypto-js['"]/gi,
|
|
69
|
+
severity: 'low',
|
|
70
|
+
description: 'crypto-js may use outdated crypto patterns',
|
|
71
|
+
suggestedFix: 'Prefer Node.js built-in crypto module or Web Crypto API',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'bcrypt-nodejs (deprecated)',
|
|
75
|
+
pattern: /require\s*\(\s*['"]bcrypt-nodejs['"]\s*\)|from\s+['"]bcrypt-nodejs['"]/gi,
|
|
76
|
+
severity: 'medium',
|
|
77
|
+
description: 'bcrypt-nodejs is deprecated and unmaintained',
|
|
78
|
+
suggestedFix: 'Use bcrypt or bcryptjs instead',
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
// SQL/Database risky patterns
|
|
82
|
+
{
|
|
83
|
+
name: 'mysql (prefer mysql2)',
|
|
84
|
+
pattern: /require\s*\(\s*['"]mysql['"]\s*\)|from\s+['"]mysql['"]/gi,
|
|
85
|
+
severity: 'low',
|
|
86
|
+
description: 'mysql package is less maintained than mysql2',
|
|
87
|
+
suggestedFix: 'Consider using mysql2 for better security and performance',
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
// Python risky imports
|
|
91
|
+
{
|
|
92
|
+
name: 'pickle (unsafe deserialization)',
|
|
93
|
+
pattern: /^import\s+pickle|^from\s+pickle\s+import/gim,
|
|
94
|
+
severity: 'high',
|
|
95
|
+
description: 'pickle can execute arbitrary code during deserialization',
|
|
96
|
+
suggestedFix: 'Use JSON or other safe serialization formats for untrusted data',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'yaml unsafe load',
|
|
100
|
+
pattern: /yaml\.load\s*\([^)]*\)(?!.*Loader)/gi,
|
|
101
|
+
severity: 'high',
|
|
102
|
+
description: 'yaml.load without Loader parameter can execute arbitrary code',
|
|
103
|
+
suggestedFix: 'Use yaml.safe_load() or specify Loader=yaml.SafeLoader',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'subprocess shell=True',
|
|
107
|
+
pattern: /subprocess\.(call|run|Popen|check_output)\s*\([^)]*shell\s*=\s*True/gi,
|
|
108
|
+
severity: 'high',
|
|
109
|
+
description: 'subprocess with shell=True is vulnerable to shell injection',
|
|
110
|
+
suggestedFix: 'Use shell=False and pass arguments as a list',
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
// Telemetry/tracking packages (privacy concern)
|
|
114
|
+
{
|
|
115
|
+
name: 'Analytics package',
|
|
116
|
+
pattern: /require\s*\(\s*['"](analytics|segment|mixpanel|amplitude)['"]\s*\)|from\s+['"](analytics|segment|mixpanel|amplitude)['"]/gi,
|
|
117
|
+
severity: 'low',
|
|
118
|
+
description: 'Analytics package detected - ensure user consent is obtained',
|
|
119
|
+
suggestedFix: 'Implement proper consent mechanisms for user tracking',
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
// Outdated/vulnerable web frameworks
|
|
123
|
+
{
|
|
124
|
+
name: 'express-jwt (CVE history)',
|
|
125
|
+
pattern: /require\s*\(\s*['"]express-jwt['"]\s*\)|from\s+['"]express-jwt['"]/gi,
|
|
126
|
+
severity: 'medium',
|
|
127
|
+
description: 'express-jwt has had security vulnerabilities - ensure latest version',
|
|
128
|
+
suggestedFix: 'Update to latest version and consider jose or jsonwebtoken directly',
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
// Dangerous native modules
|
|
132
|
+
{
|
|
133
|
+
name: 'node-gyp native module',
|
|
134
|
+
pattern: /require\s*\(\s*['"]node-gyp['"]\s*\)|from\s+['"]node-gyp['"]/gi,
|
|
135
|
+
severity: 'low',
|
|
136
|
+
description: 'Native modules can introduce platform-specific vulnerabilities',
|
|
137
|
+
suggestedFix: 'Audit native dependencies and keep them updated',
|
|
138
|
+
},
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
// Check if line is a comment
|
|
142
|
+
function isComment(line: string): boolean {
|
|
143
|
+
const trimmed = line.trim()
|
|
144
|
+
return (
|
|
145
|
+
trimmed.startsWith('//') ||
|
|
146
|
+
trimmed.startsWith('#') ||
|
|
147
|
+
trimmed.startsWith('*') ||
|
|
148
|
+
trimmed.startsWith('/*')
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function detectRiskyImports(
|
|
153
|
+
content: string,
|
|
154
|
+
filePath: string
|
|
155
|
+
): Vulnerability[] {
|
|
156
|
+
const vulnerabilities: Vulnerability[] = []
|
|
157
|
+
const lines = content.split('\n')
|
|
158
|
+
|
|
159
|
+
lines.forEach((line, index) => {
|
|
160
|
+
// Skip comment lines
|
|
161
|
+
if (isComment(line)) return
|
|
162
|
+
|
|
163
|
+
for (const pkg of RISKY_PACKAGES) {
|
|
164
|
+
const regex = new RegExp(pkg.pattern.source, pkg.pattern.flags)
|
|
165
|
+
|
|
166
|
+
if (regex.test(line)) {
|
|
167
|
+
vulnerabilities.push({
|
|
168
|
+
id: `risky-import-${filePath}-${index + 1}-${pkg.name}`,
|
|
169
|
+
filePath,
|
|
170
|
+
lineNumber: index + 1,
|
|
171
|
+
lineContent: line.trim(),
|
|
172
|
+
severity: pkg.severity,
|
|
173
|
+
category: 'suspicious_package',
|
|
174
|
+
title: `Risky package: ${pkg.name}`,
|
|
175
|
+
description: pkg.description,
|
|
176
|
+
suggestedFix: pkg.suggestedFix,
|
|
177
|
+
confidence: 'high',
|
|
178
|
+
layer: 2,
|
|
179
|
+
})
|
|
180
|
+
break // Only report once per line
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
return vulnerabilities
|
|
186
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 2: Variable Heuristics
|
|
3
|
+
* Identifies variable names associated with sensitive data
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Vulnerability, SensitiveVariablePattern } from '../types'
|
|
7
|
+
|
|
8
|
+
// Patterns for sensitive variable names
|
|
9
|
+
export const SENSITIVE_VARIABLE_PATTERNS: SensitiveVariablePattern[] = [
|
|
10
|
+
// Password-related
|
|
11
|
+
{
|
|
12
|
+
pattern: /\b(password|passwd|pwd|pass)\s*[=:]/gi,
|
|
13
|
+
severity: 'high',
|
|
14
|
+
description: 'Variable name suggests password storage',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
pattern: /\b(user_?password|admin_?password|db_?password|database_?password)\s*[=:]/gi,
|
|
18
|
+
severity: 'critical',
|
|
19
|
+
description: 'Variable name suggests database/admin password',
|
|
20
|
+
},
|
|
21
|
+
// Token-related
|
|
22
|
+
{
|
|
23
|
+
pattern: /\b(auth_?token|access_?token|refresh_?token|bearer_?token)\s*[=:]/gi,
|
|
24
|
+
severity: 'high',
|
|
25
|
+
description: 'Variable name suggests authentication token',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
pattern: /\b(api_?token|api_?key|apikey)\s*[=:]/gi,
|
|
29
|
+
severity: 'high',
|
|
30
|
+
description: 'Variable name suggests API key/token',
|
|
31
|
+
},
|
|
32
|
+
// Secret-related
|
|
33
|
+
{
|
|
34
|
+
pattern: /\b(secret|secret_?key|private_?key|signing_?key)\s*[=:]/gi,
|
|
35
|
+
severity: 'high',
|
|
36
|
+
description: 'Variable name suggests secret/private key',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
pattern: /\b(client_?secret|app_?secret|jwt_?secret)\s*[=:]/gi,
|
|
40
|
+
severity: 'critical',
|
|
41
|
+
description: 'Variable name suggests application secret',
|
|
42
|
+
},
|
|
43
|
+
// Credential-related
|
|
44
|
+
{
|
|
45
|
+
pattern: /\b(credential|credentials|creds)\s*[=:]/gi,
|
|
46
|
+
severity: 'high',
|
|
47
|
+
description: 'Variable name suggests credentials',
|
|
48
|
+
},
|
|
49
|
+
// Connection strings
|
|
50
|
+
{
|
|
51
|
+
pattern: /\b(connection_?string|conn_?string|database_?url|db_?url)\s*[=:]/gi,
|
|
52
|
+
severity: 'high',
|
|
53
|
+
description: 'Variable name suggests database connection string',
|
|
54
|
+
},
|
|
55
|
+
// Encryption keys
|
|
56
|
+
{
|
|
57
|
+
pattern: /\b(encryption_?key|decrypt_?key|cipher_?key|aes_?key)\s*[=:]/gi,
|
|
58
|
+
severity: 'critical',
|
|
59
|
+
description: 'Variable name suggests encryption key',
|
|
60
|
+
},
|
|
61
|
+
// SSH/Certificate
|
|
62
|
+
{
|
|
63
|
+
pattern: /\b(ssh_?key|private_?key|cert_?key|ssl_?key)\s*[=:]/gi,
|
|
64
|
+
severity: 'critical',
|
|
65
|
+
description: 'Variable name suggests SSH/SSL key',
|
|
66
|
+
},
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
// Check if the value looks like a placeholder or env var reference
|
|
70
|
+
function isPlaceholderOrEnvRef(line: string): boolean {
|
|
71
|
+
const safePatterns = [
|
|
72
|
+
/[=:]\s*['"]?\s*$/, // Empty value
|
|
73
|
+
/[=:]\s*['"]?xxx/i, // xxx placeholder
|
|
74
|
+
/[=:]\s*['"]?your[-_]/i, // your-xxx placeholder
|
|
75
|
+
/[=:]\s*['"]?<[^>]+>/, // <placeholder>
|
|
76
|
+
/[=:]\s*['"]?\$\{/, // ${VAR} template
|
|
77
|
+
/[=:]\s*['"]?process\.env/, // process.env reference
|
|
78
|
+
/[=:]\s*['"]?env\(/, // env() function
|
|
79
|
+
/[=:]\s*['"]?getenv/i, // getenv function
|
|
80
|
+
/[=:]\s*['"]?os\.environ/, // Python os.environ
|
|
81
|
+
/[=:]\s*['"]?ENV\[/, // Ruby ENV
|
|
82
|
+
/[=:]\s*null\b/i, // null value
|
|
83
|
+
/[=:]\s*undefined\b/, // undefined value
|
|
84
|
+
/[=:]\s*None\b/, // Python None
|
|
85
|
+
/[=:]\s*['"]?TODO/i, // TODO placeholder
|
|
86
|
+
/[=:]\s*['"]?CHANGEME/i, // CHANGEME placeholder
|
|
87
|
+
/[=:]\s*['"]?REPLACE/i, // REPLACE placeholder
|
|
88
|
+
/\?\s*.*\s*:\s*/, // Ternary operator (conditional assignment)
|
|
89
|
+
/\|\|/, // OR fallback (e.g., ENV_VAR || '')
|
|
90
|
+
/\?\?/, // Nullish coalescing
|
|
91
|
+
/[A-Z_]{3,}_(?:KEY|TOKEN|SECRET)/, // References to env var constants
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
return safePatterns.some(pattern => pattern.test(line))
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Check if line is a comment
|
|
98
|
+
function isComment(line: string): boolean {
|
|
99
|
+
const trimmed = line.trim()
|
|
100
|
+
return (
|
|
101
|
+
trimmed.startsWith('//') ||
|
|
102
|
+
trimmed.startsWith('#') ||
|
|
103
|
+
trimmed.startsWith('*') ||
|
|
104
|
+
trimmed.startsWith('/*') ||
|
|
105
|
+
trimmed.startsWith('"""') ||
|
|
106
|
+
trimmed.startsWith("'''") ||
|
|
107
|
+
trimmed.startsWith('<!--')
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Check if it's a type definition or interface
|
|
112
|
+
function isTypeDefinition(line: string): boolean {
|
|
113
|
+
return (
|
|
114
|
+
/^\s*(type|interface|class)\s/.test(line) ||
|
|
115
|
+
/:\s*(string|number|boolean|any)\s*[;,}]/.test(line) ||
|
|
116
|
+
/\?\s*:\s*\w+/.test(line)
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function detectSensitiveVariables(
|
|
121
|
+
content: string,
|
|
122
|
+
filePath: string
|
|
123
|
+
): Vulnerability[] {
|
|
124
|
+
const vulnerabilities: Vulnerability[] = []
|
|
125
|
+
const lines = content.split('\n')
|
|
126
|
+
|
|
127
|
+
lines.forEach((line, index) => {
|
|
128
|
+
// Skip comments
|
|
129
|
+
if (isComment(line)) return
|
|
130
|
+
|
|
131
|
+
// Skip type definitions
|
|
132
|
+
if (isTypeDefinition(line)) return
|
|
133
|
+
|
|
134
|
+
// Skip if it's a placeholder/env reference
|
|
135
|
+
if (isPlaceholderOrEnvRef(line)) return
|
|
136
|
+
|
|
137
|
+
for (const pattern of SENSITIVE_VARIABLE_PATTERNS) {
|
|
138
|
+
const regex = new RegExp(pattern.pattern.source, pattern.pattern.flags)
|
|
139
|
+
|
|
140
|
+
if (regex.test(line)) {
|
|
141
|
+
// Extract the actual value to check if it's hardcoded
|
|
142
|
+
const valueMatch = line.match(/[=:]\s*['"]([^'"]+)['"]/i)
|
|
143
|
+
|
|
144
|
+
if (valueMatch && valueMatch[1].length > 3) {
|
|
145
|
+
// Has a non-trivial hardcoded value
|
|
146
|
+
vulnerabilities.push({
|
|
147
|
+
id: `var-${filePath}-${index + 1}`,
|
|
148
|
+
filePath,
|
|
149
|
+
lineNumber: index + 1,
|
|
150
|
+
lineContent: line.trim(),
|
|
151
|
+
severity: pattern.severity,
|
|
152
|
+
category: 'sensitive_variable',
|
|
153
|
+
title: 'Sensitive variable with hardcoded value',
|
|
154
|
+
description: pattern.description + '. The value appears to be hardcoded rather than loaded from environment.',
|
|
155
|
+
suggestedFix: 'Move this sensitive value to an environment variable or secure secrets manager.',
|
|
156
|
+
confidence: 'medium',
|
|
157
|
+
layer: 2,
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
break // Only report once per line
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
return vulnerabilities
|
|
166
|
+
}
|