@oculum/scanner 1.0.10 → 1.0.12
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/ai-context/index.d.ts +6 -0
- package/dist/ai-context/index.d.ts.map +1 -0
- package/dist/ai-context/index.js +13 -0
- package/dist/ai-context/index.js.map +1 -0
- package/dist/ai-context/manager.d.ts +67 -0
- package/dist/ai-context/manager.d.ts.map +1 -0
- package/dist/ai-context/manager.js +104 -0
- package/dist/ai-context/manager.js.map +1 -0
- package/dist/baseline/diff.d.ts +32 -0
- package/dist/baseline/diff.d.ts.map +1 -0
- package/dist/baseline/diff.js +119 -0
- package/dist/baseline/diff.js.map +1 -0
- package/dist/baseline/index.d.ts +9 -0
- package/dist/baseline/index.d.ts.map +1 -0
- package/dist/baseline/index.js +19 -0
- package/dist/baseline/index.js.map +1 -0
- package/dist/baseline/manager.d.ts +67 -0
- package/dist/baseline/manager.d.ts.map +1 -0
- package/dist/baseline/manager.js +180 -0
- package/dist/baseline/manager.js.map +1 -0
- package/dist/baseline/types.d.ts +91 -0
- package/dist/baseline/types.d.ts.map +1 -0
- package/dist/baseline/types.js +12 -0
- package/dist/baseline/types.js.map +1 -0
- package/dist/category-filter.d.ts +125 -0
- package/dist/category-filter.d.ts.map +1 -0
- package/dist/category-filter.js +360 -0
- package/dist/category-filter.js.map +1 -0
- package/dist/filtering/context-adjustments.d.ts +23 -0
- package/dist/filtering/context-adjustments.d.ts.map +1 -0
- package/dist/filtering/context-adjustments.js +100 -0
- package/dist/filtering/context-adjustments.js.map +1 -0
- package/dist/filtering/index.d.ts +3 -0
- package/dist/filtering/index.d.ts.map +1 -0
- package/dist/filtering/index.js +8 -0
- package/dist/filtering/index.js.map +1 -0
- package/dist/filtering/pipeline.d.ts +48 -0
- package/dist/filtering/pipeline.d.ts.map +1 -0
- package/dist/filtering/pipeline.js +76 -0
- package/dist/filtering/pipeline.js.map +1 -0
- package/dist/formatters/ai-context.d.ts +23 -0
- package/dist/formatters/ai-context.d.ts.map +1 -0
- package/dist/formatters/ai-context.js +238 -0
- package/dist/formatters/ai-context.js.map +1 -0
- package/dist/formatters/cli-terminal.d.ts +38 -0
- package/dist/formatters/cli-terminal.d.ts.map +1 -1
- package/dist/formatters/cli-terminal.js +365 -42
- package/dist/formatters/cli-terminal.js.map +1 -1
- package/dist/formatters/github-comment.d.ts +2 -2
- package/dist/formatters/github-comment.d.ts.map +1 -1
- package/dist/formatters/github-comment.js +77 -13
- package/dist/formatters/github-comment.js.map +1 -1
- package/dist/formatters/ide/claude-code.d.ts +17 -0
- package/dist/formatters/ide/claude-code.d.ts.map +1 -0
- package/dist/formatters/ide/claude-code.js +94 -0
- package/dist/formatters/ide/claude-code.js.map +1 -0
- package/dist/formatters/ide/cursor.d.ts +13 -0
- package/dist/formatters/ide/cursor.d.ts.map +1 -0
- package/dist/formatters/ide/cursor.js +125 -0
- package/dist/formatters/ide/cursor.js.map +1 -0
- package/dist/formatters/ide/index.d.ts +62 -0
- package/dist/formatters/ide/index.d.ts.map +1 -0
- package/dist/formatters/ide/index.js +184 -0
- package/dist/formatters/ide/index.js.map +1 -0
- package/dist/formatters/ide/windsurf.d.ts +13 -0
- package/dist/formatters/ide/windsurf.d.ts.map +1 -0
- package/dist/formatters/ide/windsurf.js +117 -0
- package/dist/formatters/ide/windsurf.js.map +1 -0
- package/dist/formatters/index.d.ts +3 -1
- package/dist/formatters/index.d.ts.map +1 -1
- package/dist/formatters/index.js +20 -1
- package/dist/formatters/index.js.map +1 -1
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +423 -56
- package/dist/index.js.map +1 -1
- package/dist/layer1/comments.d.ts +4 -1
- package/dist/layer1/comments.d.ts.map +1 -1
- package/dist/layer1/comments.js +1 -1
- package/dist/layer1/comments.js.map +1 -1
- package/dist/layer1/config-audit.d.ts +4 -1
- package/dist/layer1/config-audit.d.ts.map +1 -1
- package/dist/layer1/config-audit.js +65 -14
- package/dist/layer1/config-audit.js.map +1 -1
- package/dist/layer1/config-mcp-audit.d.ts +23 -0
- package/dist/layer1/config-mcp-audit.d.ts.map +1 -0
- package/dist/layer1/config-mcp-audit.js +239 -0
- package/dist/layer1/config-mcp-audit.js.map +1 -0
- package/dist/layer1/entropy.d.ts +4 -1
- package/dist/layer1/entropy.d.ts.map +1 -1
- package/dist/layer1/entropy.js +212 -1
- package/dist/layer1/entropy.js.map +1 -1
- package/dist/layer1/file-flags.d.ts +4 -1
- package/dist/layer1/file-flags.d.ts.map +1 -1
- package/dist/layer1/file-flags.js +12 -5
- package/dist/layer1/file-flags.js.map +1 -1
- package/dist/layer1/index.d.ts +1 -0
- package/dist/layer1/index.d.ts.map +1 -1
- package/dist/layer1/index.js +22 -19
- package/dist/layer1/index.js.map +1 -1
- package/dist/layer1/patterns.d.ts +4 -1
- package/dist/layer1/patterns.d.ts.map +1 -1
- package/dist/layer1/patterns.js +34 -4
- package/dist/layer1/patterns.js.map +1 -1
- package/dist/layer1/urls.d.ts +4 -1
- package/dist/layer1/urls.d.ts.map +1 -1
- package/dist/layer1/urls.js +162 -14
- package/dist/layer1/urls.js.map +1 -1
- package/dist/layer1/weak-crypto.d.ts +4 -1
- package/dist/layer1/weak-crypto.d.ts.map +1 -1
- package/dist/layer1/weak-crypto.js +144 -7
- package/dist/layer1/weak-crypto.js.map +1 -1
- package/dist/layer2/ai-agent-tools.d.ts +4 -1
- package/dist/layer2/ai-agent-tools.d.ts.map +1 -1
- package/dist/layer2/ai-agent-tools.js +964 -2
- package/dist/layer2/ai-agent-tools.js.map +1 -1
- package/dist/layer2/ai-endpoint-protection.d.ts +2 -0
- package/dist/layer2/ai-endpoint-protection.d.ts.map +1 -1
- package/dist/layer2/ai-endpoint-protection.js +18 -4
- package/dist/layer2/ai-endpoint-protection.js.map +1 -1
- package/dist/layer2/ai-execution-sinks.d.ts +4 -1
- package/dist/layer2/ai-execution-sinks.d.ts.map +1 -1
- package/dist/layer2/ai-execution-sinks.js +688 -29
- package/dist/layer2/ai-execution-sinks.js.map +1 -1
- package/dist/layer2/ai-fingerprinting.d.ts +4 -1
- package/dist/layer2/ai-fingerprinting.d.ts.map +1 -1
- package/dist/layer2/ai-fingerprinting.js +28 -32
- package/dist/layer2/ai-fingerprinting.js.map +1 -1
- package/dist/layer2/ai-mcp-security.d.ts +20 -0
- package/dist/layer2/ai-mcp-security.d.ts.map +1 -0
- package/dist/layer2/ai-mcp-security.js +877 -0
- package/dist/layer2/ai-mcp-security.js.map +1 -0
- package/dist/layer2/ai-package-hallucination.d.ts +22 -0
- package/dist/layer2/ai-package-hallucination.d.ts.map +1 -0
- package/dist/layer2/ai-package-hallucination.js +828 -0
- package/dist/layer2/ai-package-hallucination.js.map +1 -0
- package/dist/layer2/ai-prompt-hygiene.d.ts +4 -1
- package/dist/layer2/ai-prompt-hygiene.d.ts.map +1 -1
- package/dist/layer2/ai-prompt-hygiene.js +817 -17
- package/dist/layer2/ai-prompt-hygiene.js.map +1 -1
- package/dist/layer2/ai-rag-safety.d.ts +4 -1
- package/dist/layer2/ai-rag-safety.d.ts.map +1 -1
- package/dist/layer2/ai-rag-safety.js +454 -3
- package/dist/layer2/ai-rag-safety.js.map +1 -1
- package/dist/layer2/ai-schema-validation.d.ts +4 -1
- package/dist/layer2/ai-schema-validation.d.ts.map +1 -1
- package/dist/layer2/ai-schema-validation.js +2 -2
- package/dist/layer2/ai-schema-validation.js.map +1 -1
- package/dist/layer2/auth-antipatterns.d.ts +2 -0
- package/dist/layer2/auth-antipatterns.d.ts.map +1 -1
- package/dist/layer2/auth-antipatterns.js +209 -20
- package/dist/layer2/auth-antipatterns.js.map +1 -1
- package/dist/layer2/byok-patterns.d.ts +4 -1
- package/dist/layer2/byok-patterns.d.ts.map +1 -1
- package/dist/layer2/byok-patterns.js +5 -2
- package/dist/layer2/byok-patterns.js.map +1 -1
- package/dist/layer2/dangerous-functions/child-process.d.ts +16 -0
- package/dist/layer2/dangerous-functions/child-process.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions/child-process.js +74 -0
- package/dist/layer2/dangerous-functions/child-process.js.map +1 -0
- package/dist/layer2/dangerous-functions/dom-xss.d.ts +34 -0
- package/dist/layer2/dangerous-functions/dom-xss.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions/dom-xss.js +230 -0
- package/dist/layer2/dangerous-functions/dom-xss.js.map +1 -0
- package/dist/layer2/dangerous-functions/index.d.ts +16 -0
- package/dist/layer2/dangerous-functions/index.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions/index.js +1152 -0
- package/dist/layer2/dangerous-functions/index.js.map +1 -0
- package/dist/layer2/dangerous-functions/json-parse.d.ts +31 -0
- package/dist/layer2/dangerous-functions/json-parse.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions/json-parse.js +319 -0
- package/dist/layer2/dangerous-functions/json-parse.js.map +1 -0
- package/dist/layer2/dangerous-functions/math-random.d.ts +111 -0
- package/dist/layer2/dangerous-functions/math-random.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions/math-random.js +684 -0
- package/dist/layer2/dangerous-functions/math-random.js.map +1 -0
- package/dist/layer2/dangerous-functions/patterns.d.ts +21 -0
- package/dist/layer2/dangerous-functions/patterns.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions/patterns.js +163 -0
- package/dist/layer2/dangerous-functions/patterns.js.map +1 -0
- package/dist/layer2/dangerous-functions/request-validation.d.ts +13 -0
- package/dist/layer2/dangerous-functions/request-validation.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions/request-validation.js +119 -0
- package/dist/layer2/dangerous-functions/request-validation.js.map +1 -0
- package/dist/layer2/dangerous-functions/utils/control-flow.d.ts +24 -0
- package/dist/layer2/dangerous-functions/utils/control-flow.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions/utils/control-flow.js +70 -0
- package/dist/layer2/dangerous-functions/utils/control-flow.js.map +1 -0
- package/dist/layer2/dangerous-functions/utils/helpers.d.ts +31 -0
- package/dist/layer2/dangerous-functions/utils/helpers.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions/utils/helpers.js +147 -0
- package/dist/layer2/dangerous-functions/utils/helpers.js.map +1 -0
- package/dist/layer2/dangerous-functions/utils/index.d.ts +9 -0
- package/dist/layer2/dangerous-functions/utils/index.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions/utils/index.js +23 -0
- package/dist/layer2/dangerous-functions/utils/index.js.map +1 -0
- package/dist/layer2/dangerous-functions/utils/schema-validation.d.ts +22 -0
- package/dist/layer2/dangerous-functions/utils/schema-validation.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions/utils/schema-validation.js +102 -0
- package/dist/layer2/dangerous-functions/utils/schema-validation.js.map +1 -0
- package/dist/layer2/data-exposure.d.ts +4 -1
- package/dist/layer2/data-exposure.d.ts.map +1 -1
- package/dist/layer2/data-exposure.js +14 -38
- package/dist/layer2/data-exposure.js.map +1 -1
- package/dist/layer2/framework-checks.d.ts +4 -1
- package/dist/layer2/framework-checks.d.ts.map +1 -1
- package/dist/layer2/framework-checks.js +5 -2
- package/dist/layer2/framework-checks.js.map +1 -1
- package/dist/layer2/index.d.ts +12 -1
- package/dist/layer2/index.d.ts.map +1 -1
- package/dist/layer2/index.js +110 -45
- package/dist/layer2/index.js.map +1 -1
- package/dist/layer2/logic-gates.d.ts +4 -1
- package/dist/layer2/logic-gates.d.ts.map +1 -1
- package/dist/layer2/logic-gates.js +58 -20
- package/dist/layer2/logic-gates.js.map +1 -1
- package/dist/layer2/model-supply-chain.d.ts +23 -0
- package/dist/layer2/model-supply-chain.d.ts.map +1 -0
- package/dist/layer2/model-supply-chain.js +444 -0
- package/dist/layer2/model-supply-chain.js.map +1 -0
- package/dist/layer2/risky-imports.d.ts +4 -1
- package/dist/layer2/risky-imports.d.ts.map +1 -1
- package/dist/layer2/risky-imports.js +6 -2
- package/dist/layer2/risky-imports.js.map +1 -1
- package/dist/layer2/variables.d.ts +4 -1
- package/dist/layer2/variables.d.ts.map +1 -1
- package/dist/layer2/variables.js +6 -2
- package/dist/layer2/variables.js.map +1 -1
- package/dist/layer3/anthropic/auto-dismiss.d.ts +24 -0
- package/dist/layer3/anthropic/auto-dismiss.d.ts.map +1 -0
- package/dist/layer3/anthropic/auto-dismiss.js +199 -0
- package/dist/layer3/anthropic/auto-dismiss.js.map +1 -0
- package/dist/layer3/anthropic/clients.d.ts +44 -0
- package/dist/layer3/anthropic/clients.d.ts.map +1 -0
- package/dist/layer3/anthropic/clients.js +81 -0
- package/dist/layer3/anthropic/clients.js.map +1 -0
- package/dist/layer3/anthropic/index.d.ts +41 -0
- package/dist/layer3/anthropic/index.d.ts.map +1 -0
- package/dist/layer3/anthropic/index.js +141 -0
- package/dist/layer3/anthropic/index.js.map +1 -0
- package/dist/layer3/anthropic/prompts/index.d.ts +8 -0
- package/dist/layer3/anthropic/prompts/index.d.ts.map +1 -0
- package/dist/layer3/anthropic/prompts/index.js +14 -0
- package/dist/layer3/anthropic/prompts/index.js.map +1 -0
- package/dist/layer3/anthropic/prompts/semantic-analysis.d.ts +15 -0
- package/dist/layer3/anthropic/prompts/semantic-analysis.d.ts.map +1 -0
- package/dist/layer3/anthropic/prompts/semantic-analysis.js +169 -0
- package/dist/layer3/anthropic/prompts/semantic-analysis.js.map +1 -0
- package/dist/layer3/anthropic/prompts/validation.d.ts +12 -0
- package/dist/layer3/anthropic/prompts/validation.d.ts.map +1 -0
- package/dist/layer3/anthropic/prompts/validation.js +421 -0
- package/dist/layer3/anthropic/prompts/validation.js.map +1 -0
- package/dist/layer3/anthropic/providers/anthropic.d.ts +21 -0
- package/dist/layer3/anthropic/providers/anthropic.d.ts.map +1 -0
- package/dist/layer3/anthropic/providers/anthropic.js +266 -0
- package/dist/layer3/anthropic/providers/anthropic.js.map +1 -0
- package/dist/layer3/anthropic/providers/index.d.ts +8 -0
- package/dist/layer3/anthropic/providers/index.d.ts.map +1 -0
- package/dist/layer3/anthropic/providers/index.js +15 -0
- package/dist/layer3/anthropic/providers/index.js.map +1 -0
- package/dist/layer3/anthropic/providers/openai.d.ts +18 -0
- package/dist/layer3/anthropic/providers/openai.d.ts.map +1 -0
- package/dist/layer3/anthropic/providers/openai.js +340 -0
- package/dist/layer3/anthropic/providers/openai.js.map +1 -0
- package/dist/layer3/anthropic/request-builder.d.ts +20 -0
- package/dist/layer3/anthropic/request-builder.d.ts.map +1 -0
- package/dist/layer3/anthropic/request-builder.js +134 -0
- package/dist/layer3/anthropic/request-builder.js.map +1 -0
- package/dist/layer3/anthropic/types.d.ts +88 -0
- package/dist/layer3/anthropic/types.d.ts.map +1 -0
- package/dist/layer3/anthropic/types.js +38 -0
- package/dist/layer3/anthropic/types.js.map +1 -0
- package/dist/layer3/anthropic/utils/index.d.ts +9 -0
- package/dist/layer3/anthropic/utils/index.d.ts.map +1 -0
- package/dist/layer3/anthropic/utils/index.js +24 -0
- package/dist/layer3/anthropic/utils/index.js.map +1 -0
- package/dist/layer3/anthropic/utils/path-helpers.d.ts +21 -0
- package/dist/layer3/anthropic/utils/path-helpers.d.ts.map +1 -0
- package/dist/layer3/anthropic/utils/path-helpers.js +69 -0
- package/dist/layer3/anthropic/utils/path-helpers.js.map +1 -0
- package/dist/layer3/anthropic/utils/response-parser.d.ts +40 -0
- package/dist/layer3/anthropic/utils/response-parser.d.ts.map +1 -0
- package/dist/layer3/anthropic/utils/response-parser.js +285 -0
- package/dist/layer3/anthropic/utils/response-parser.js.map +1 -0
- package/dist/layer3/anthropic/utils/retry.d.ts +15 -0
- package/dist/layer3/anthropic/utils/retry.d.ts.map +1 -0
- package/dist/layer3/anthropic/utils/retry.js +62 -0
- package/dist/layer3/anthropic/utils/retry.js.map +1 -0
- package/dist/layer3/index.d.ts +1 -0
- package/dist/layer3/index.d.ts.map +1 -1
- package/dist/layer3/index.js +16 -6
- package/dist/layer3/index.js.map +1 -1
- package/dist/layer3/osv-check.d.ts +75 -0
- package/dist/layer3/osv-check.d.ts.map +1 -0
- package/dist/layer3/osv-check.js +308 -0
- package/dist/layer3/osv-check.js.map +1 -0
- package/dist/modes/incremental.js +1 -1
- package/dist/rules/framework-fixes.d.ts +48 -0
- package/dist/rules/framework-fixes.d.ts.map +1 -0
- package/dist/rules/framework-fixes.js +439 -0
- package/dist/rules/framework-fixes.js.map +1 -0
- package/dist/rules/index.d.ts +8 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +18 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/metadata.d.ts +43 -0
- package/dist/rules/metadata.d.ts.map +1 -0
- package/dist/rules/metadata.js +734 -0
- package/dist/rules/metadata.js.map +1 -0
- package/dist/suppression/config-loader.d.ts +74 -0
- package/dist/suppression/config-loader.d.ts.map +1 -0
- package/dist/suppression/config-loader.js +424 -0
- package/dist/suppression/config-loader.js.map +1 -0
- package/dist/suppression/hash.d.ts +48 -0
- package/dist/suppression/hash.d.ts.map +1 -0
- package/dist/suppression/hash.js +88 -0
- package/dist/suppression/hash.js.map +1 -0
- package/dist/suppression/index.d.ts +11 -0
- package/dist/suppression/index.d.ts.map +1 -0
- package/dist/suppression/index.js +39 -0
- package/dist/suppression/index.js.map +1 -0
- package/dist/suppression/inline-parser.d.ts +39 -0
- package/dist/suppression/inline-parser.d.ts.map +1 -0
- package/dist/suppression/inline-parser.js +218 -0
- package/dist/suppression/inline-parser.js.map +1 -0
- package/dist/suppression/manager.d.ts +94 -0
- package/dist/suppression/manager.d.ts.map +1 -0
- package/dist/suppression/manager.js +292 -0
- package/dist/suppression/manager.js.map +1 -0
- package/dist/suppression/types.d.ts +151 -0
- package/dist/suppression/types.d.ts.map +1 -0
- package/dist/suppression/types.js +28 -0
- package/dist/suppression/types.js.map +1 -0
- package/dist/tiers.d.ts +3 -3
- package/dist/tiers.d.ts.map +1 -1
- package/dist/tiers.js +34 -7
- package/dist/tiers.js.map +1 -1
- package/dist/types.d.ts +140 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +34 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/code-analysis.d.ts +39 -0
- package/dist/utils/code-analysis.d.ts.map +1 -0
- package/dist/utils/code-analysis.js +159 -0
- package/dist/utils/code-analysis.js.map +1 -0
- package/dist/utils/comment-analyzer.d.ts +38 -0
- package/dist/utils/comment-analyzer.d.ts.map +1 -0
- package/dist/utils/comment-analyzer.js +218 -0
- package/dist/utils/comment-analyzer.js.map +1 -0
- package/dist/utils/context-helpers.d.ts +112 -1
- package/dist/utils/context-helpers.d.ts.map +1 -1
- package/dist/utils/context-helpers.js +364 -11
- package/dist/utils/context-helpers.js.map +1 -1
- package/dist/utils/environment-context.d.ts +76 -0
- package/dist/utils/environment-context.d.ts.map +1 -0
- package/dist/utils/environment-context.js +271 -0
- package/dist/utils/environment-context.js.map +1 -0
- package/dist/utils/intent-detector.d.ts +66 -0
- package/dist/utils/intent-detector.d.ts.map +1 -0
- package/dist/utils/intent-detector.js +282 -0
- package/dist/utils/intent-detector.js.map +1 -0
- package/dist/utils/parsed-file.d.ts +51 -0
- package/dist/utils/parsed-file.d.ts.map +1 -0
- package/dist/utils/parsed-file.js +95 -0
- package/dist/utils/parsed-file.js.map +1 -0
- package/dist/utils/route-hierarchy.d.ts +50 -0
- package/dist/utils/route-hierarchy.d.ts.map +1 -0
- package/dist/utils/route-hierarchy.js +226 -0
- package/dist/utils/route-hierarchy.js.map +1 -0
- package/dist/utils/schema-semantics.d.ts +45 -0
- package/dist/utils/schema-semantics.d.ts.map +1 -0
- package/dist/utils/schema-semantics.js +193 -0
- package/dist/utils/schema-semantics.js.map +1 -0
- package/package.json +4 -2
- package/src/__tests__/benchmark/fixtures/layer1/mcp-config-audit.json +31 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-execution-sinks.ts +1489 -82
- package/src/__tests__/benchmark/fixtures/layer2/ai-mcp-security.ts +495 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-package-hallucination.ts +255 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-prompt-hygiene.ts +300 -1
- package/src/__tests__/benchmark/fixtures/layer2/ai-rag-safety.ts +139 -0
- package/src/__tests__/benchmark/fixtures/layer2/byok-patterns.ts +7 -0
- package/src/__tests__/benchmark/fixtures/layer2/data-exposure.ts +63 -0
- package/src/__tests__/benchmark/fixtures/layer2/excessive-agency.ts +221 -0
- package/src/__tests__/benchmark/fixtures/layer2/index.ts +30 -0
- package/src/__tests__/benchmark/fixtures/layer2/model-supply-chain.ts +204 -0
- package/src/__tests__/benchmark/fixtures/layer2/phase1-enhancements.ts +157 -0
- package/src/__tests__/benchmark/fixtures/layer2/phase5-excessive-agency.ts +580 -0
- package/src/__tests__/benchmark/fixtures/layer2/sprint6-ai-enhancements.ts +515 -0
- package/src/__tests__/benchmark/run-depth-validation.ts +9 -9
- package/src/__tests__/category-filter.test.ts +478 -0
- package/src/__tests__/regression/known-false-positives.test.ts +490 -0
- package/src/__tests__/snapshots/__snapshots__/anthropic-validation-refactor.test.ts.snap +762 -0
- package/src/__tests__/snapshots/__snapshots__/dangerous-functions-refactor.test.ts.snap +503 -0
- package/src/__tests__/snapshots/__snapshots__/scan-depth.test.ts.snap +0 -9
- package/src/__tests__/snapshots/anthropic-validation-refactor.test.ts +321 -0
- package/src/__tests__/snapshots/dangerous-functions-refactor.test.ts +439 -0
- package/src/__tests__/validation/run-validation.ts +7 -7
- package/src/ai-context/__tests__/manager.test.ts +193 -0
- package/src/ai-context/index.ts +15 -0
- package/src/ai-context/manager.ts +145 -0
- package/src/baseline/__tests__/diff.test.ts +261 -0
- package/src/baseline/__tests__/manager.test.ts +225 -0
- package/src/baseline/diff.ts +135 -0
- package/src/baseline/index.ts +29 -0
- package/src/baseline/manager.ts +230 -0
- package/src/baseline/types.ts +97 -0
- package/src/category-filter.ts +400 -0
- package/src/filtering/__tests__/pipeline.test.ts +134 -0
- package/src/filtering/context-adjustments.ts +111 -0
- package/src/filtering/index.ts +10 -0
- package/src/filtering/pipeline.ts +130 -0
- package/src/formatters/__tests__/ai-context.test.ts +254 -0
- package/src/formatters/ai-context.ts +302 -0
- package/src/formatters/cli-terminal.ts +444 -41
- package/src/formatters/github-comment.ts +82 -14
- package/src/formatters/ide/__tests__/ide.test.ts +319 -0
- package/src/formatters/ide/claude-code.ts +110 -0
- package/src/formatters/ide/cursor.ts +147 -0
- package/src/formatters/ide/index.ts +216 -0
- package/src/formatters/ide/windsurf.ts +135 -0
- package/src/formatters/index.ts +28 -0
- package/src/index.ts +506 -45
- package/src/layer1/comments.ts +3 -1
- package/src/layer1/config-audit.ts +74 -14
- package/src/layer1/config-mcp-audit.ts +278 -0
- package/src/layer1/entropy.ts +234 -1
- package/src/layer1/file-flags.ts +17 -6
- package/src/layer1/index.ts +29 -23
- package/src/layer1/patterns.ts +42 -4
- package/src/layer1/urls.ts +188 -14
- package/src/layer1/weak-crypto.ts +168 -16
- package/src/layer2/ai-agent-tools.ts +1043 -2
- package/src/layer2/ai-endpoint-protection.ts +19 -4
- package/src/layer2/ai-execution-sinks.ts +755 -29
- package/src/layer2/ai-fingerprinting.ts +33 -33
- package/src/layer2/ai-mcp-security.ts +933 -0
- package/src/layer2/ai-package-hallucination.ts +940 -0
- package/src/layer2/ai-prompt-hygiene.ts +898 -17
- package/src/layer2/ai-rag-safety.ts +467 -5
- package/src/layer2/ai-schema-validation.ts +4 -2
- package/src/layer2/auth-antipatterns.ts +235 -20
- package/src/layer2/byok-patterns.ts +9 -3
- package/src/layer2/dangerous-functions/child-process.ts +98 -0
- package/src/layer2/dangerous-functions/dom-xss.ts +292 -0
- package/src/layer2/dangerous-functions/index.ts +1533 -0
- package/src/layer2/dangerous-functions/json-parse.ts +385 -0
- package/src/layer2/dangerous-functions/math-random.ts +789 -0
- package/src/layer2/dangerous-functions/patterns.ts +176 -0
- package/src/layer2/dangerous-functions/request-validation.ts +145 -0
- package/src/layer2/dangerous-functions/utils/control-flow.ts +35 -0
- package/src/layer2/dangerous-functions/utils/helpers.ts +170 -0
- package/src/layer2/dangerous-functions/utils/index.ts +25 -0
- package/src/layer2/dangerous-functions/utils/schema-validation.ts +106 -0
- package/src/layer2/data-exposure.ts +18 -39
- package/src/layer2/framework-checks.ts +9 -2
- package/src/layer2/index.ts +124 -43
- package/src/layer2/logic-gates.ts +64 -22
- package/src/layer2/model-supply-chain.ts +531 -0
- package/src/layer2/risky-imports.ts +9 -2
- package/src/layer2/variables.ts +9 -2
- package/src/layer3/__tests__/osv-check.test.ts +384 -0
- package/src/layer3/anthropic/auto-dismiss.ts +223 -0
- package/src/layer3/anthropic/clients.ts +84 -0
- package/src/layer3/anthropic/index.ts +170 -0
- package/src/layer3/anthropic/prompts/index.ts +14 -0
- package/src/layer3/anthropic/prompts/semantic-analysis.ts +173 -0
- package/src/layer3/anthropic/prompts/validation.ts +419 -0
- package/src/layer3/anthropic/providers/anthropic.ts +310 -0
- package/src/layer3/anthropic/providers/index.ts +8 -0
- package/src/layer3/anthropic/providers/openai.ts +384 -0
- package/src/layer3/anthropic/request-builder.ts +150 -0
- package/src/layer3/anthropic/types.ts +148 -0
- package/src/layer3/anthropic/utils/index.ts +26 -0
- package/src/layer3/anthropic/utils/path-helpers.ts +68 -0
- package/src/layer3/anthropic/utils/response-parser.ts +322 -0
- package/src/layer3/anthropic/utils/retry.ts +75 -0
- package/src/layer3/index.ts +18 -5
- package/src/layer3/osv-check.ts +420 -0
- package/src/modes/incremental.ts +1 -1
- package/src/rules/__tests__/framework-fixes.test.ts +689 -0
- package/src/rules/__tests__/metadata.test.ts +218 -0
- package/src/rules/framework-fixes.ts +470 -0
- package/src/rules/index.ts +21 -0
- package/src/rules/metadata.ts +831 -0
- package/src/suppression/__tests__/config-loader.test.ts +382 -0
- package/src/suppression/__tests__/hash.test.ts +166 -0
- package/src/suppression/__tests__/inline-parser.test.ts +212 -0
- package/src/suppression/__tests__/manager.test.ts +415 -0
- package/src/suppression/config-loader.ts +462 -0
- package/src/suppression/hash.ts +95 -0
- package/src/suppression/index.ts +51 -0
- package/src/suppression/inline-parser.ts +273 -0
- package/src/suppression/manager.ts +379 -0
- package/src/suppression/types.ts +174 -0
- package/src/tiers.ts +45 -9
- package/src/types.ts +212 -8
- package/src/utils/__tests__/code-analysis.test.ts +165 -0
- package/src/utils/__tests__/parsed-file.test.ts +124 -0
- package/src/utils/code-analysis.ts +179 -0
- package/src/utils/comment-analyzer.ts +249 -0
- package/src/utils/context-helpers.ts +421 -11
- package/src/utils/environment-context.ts +304 -0
- package/src/utils/intent-detector.ts +318 -0
- package/src/utils/parsed-file.ts +103 -0
- package/src/utils/route-hierarchy.ts +250 -0
- package/src/utils/schema-semantics.ts +233 -0
- package/dist/layer2/dangerous-functions.d.ts +0 -7
- package/dist/layer2/dangerous-functions.d.ts.map +0 -1
- package/dist/layer2/dangerous-functions.js +0 -1701
- package/dist/layer2/dangerous-functions.js.map +0 -1
- package/dist/layer3/anthropic.d.ts +0 -87
- package/dist/layer3/anthropic.d.ts.map +0 -1
- package/dist/layer3/anthropic.js +0 -1948
- package/dist/layer3/anthropic.js.map +0 -1
- package/dist/layer3/openai.d.ts +0 -25
- package/dist/layer3/openai.d.ts.map +0 -1
- package/dist/layer3/openai.js +0 -238
- package/dist/layer3/openai.js.map +0 -1
- package/src/layer2/dangerous-functions.ts +0 -1940
- package/src/layer3/anthropic.ts +0 -2257
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dangerous Function Pattern Definitions
|
|
3
|
+
*
|
|
4
|
+
* This module defines the patterns for detecting dangerous function calls.
|
|
5
|
+
* These patterns are used by the main detection engine.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { VulnerabilitySeverity } from '../../types'
|
|
9
|
+
|
|
10
|
+
export interface DangerousFunctionPattern {
|
|
11
|
+
name: string
|
|
12
|
+
pattern: RegExp
|
|
13
|
+
severity: VulnerabilitySeverity
|
|
14
|
+
description: string
|
|
15
|
+
suggestedFix: string
|
|
16
|
+
languages?: string[] // Optional: restrict to specific languages
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const DANGEROUS_FUNCTIONS: DangerousFunctionPattern[] = [
|
|
20
|
+
// Code execution
|
|
21
|
+
{
|
|
22
|
+
name: 'eval() usage',
|
|
23
|
+
pattern: /\beval\s*\(/gi,
|
|
24
|
+
severity: 'critical',
|
|
25
|
+
description: 'eval() executes arbitrary code and is a major security risk',
|
|
26
|
+
suggestedFix: 'Use JSON.parse() for JSON data, or refactor to avoid dynamic code execution',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'Function constructor',
|
|
30
|
+
pattern: /new\s+Function\s*\(/gi,
|
|
31
|
+
severity: 'critical',
|
|
32
|
+
description: 'Function constructor can execute arbitrary code like eval()',
|
|
33
|
+
suggestedFix: 'Refactor to use static functions or safe alternatives',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'setTimeout/setInterval with string',
|
|
37
|
+
pattern: /set(Timeout|Interval)\s*\(\s*['"`]/gi,
|
|
38
|
+
severity: 'high',
|
|
39
|
+
description: 'setTimeout/setInterval with string argument acts like eval()',
|
|
40
|
+
suggestedFix: 'Pass a function reference instead of a string',
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
// Command injection
|
|
44
|
+
{
|
|
45
|
+
name: 'child_process exec',
|
|
46
|
+
pattern: /\b(exec|execSync|spawn|spawnSync|execFile)\s*\(/gi,
|
|
47
|
+
severity: 'high',
|
|
48
|
+
description: 'Shell command execution can lead to command injection',
|
|
49
|
+
suggestedFix: 'Validate and sanitize all inputs, prefer execFile over exec',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'os.system/subprocess (Python)',
|
|
53
|
+
pattern: /\b(os\.system|subprocess\.(call|run|Popen|check_output))\s*\(/gi,
|
|
54
|
+
severity: 'high',
|
|
55
|
+
description: 'Shell command execution can lead to command injection',
|
|
56
|
+
suggestedFix: 'Use subprocess with shell=False and pass arguments as a list',
|
|
57
|
+
languages: ['py'],
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
// SQL injection risks
|
|
61
|
+
// Note: .execute is too generic (used by axios, tRPC, request utilities)
|
|
62
|
+
// Focus on .query and .raw which are more SQL-specific
|
|
63
|
+
{
|
|
64
|
+
name: 'Raw SQL query construction',
|
|
65
|
+
pattern: /\.(query|raw)\s*\(\s*[`'"].*\$\{|\.query\s*\(\s*['"].*\+/gi,
|
|
66
|
+
severity: 'critical',
|
|
67
|
+
description: 'String concatenation in SQL queries can lead to SQL injection',
|
|
68
|
+
suggestedFix: 'Use parameterized queries or prepared statements',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'SQL template literal',
|
|
72
|
+
pattern: /`SELECT.*FROM.*WHERE.*\$\{|`INSERT.*INTO.*VALUES.*\$\{|`UPDATE.*SET.*\$\{|`DELETE.*FROM.*WHERE.*\$\{/gi,
|
|
73
|
+
severity: 'critical',
|
|
74
|
+
description: 'Template literals in SQL queries can lead to SQL injection',
|
|
75
|
+
suggestedFix: 'Use parameterized queries with placeholders (?, $1, etc.)',
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
// XSS risks
|
|
79
|
+
{
|
|
80
|
+
name: 'innerHTML assignment',
|
|
81
|
+
pattern: /\.innerHTML\s*=|\.outerHTML\s*=/gi,
|
|
82
|
+
severity: 'high',
|
|
83
|
+
description: 'Direct innerHTML assignment can lead to XSS vulnerabilities',
|
|
84
|
+
suggestedFix: 'Use textContent for text, or sanitize HTML with DOMPurify',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'document.write',
|
|
88
|
+
pattern: /document\.write\s*\(/gi,
|
|
89
|
+
severity: 'high',
|
|
90
|
+
description: 'document.write can introduce XSS vulnerabilities',
|
|
91
|
+
suggestedFix: 'Use DOM manipulation methods instead',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'dangerouslySetInnerHTML',
|
|
95
|
+
pattern: /dangerouslySetInnerHTML\s*=\s*\{\s*\{\s*__html\s*:/gi,
|
|
96
|
+
severity: 'high',
|
|
97
|
+
description: 'dangerouslySetInnerHTML can lead to XSS if content is not sanitized',
|
|
98
|
+
suggestedFix: 'Sanitize HTML content with DOMPurify before rendering',
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
// Deserialization
|
|
102
|
+
{
|
|
103
|
+
name: 'Unsafe deserialization',
|
|
104
|
+
pattern: /\b(pickle\.loads?|yaml\.load\s*\((?!.*Loader)|unserialize|Marshal\.load)\s*\(/gi,
|
|
105
|
+
severity: 'critical',
|
|
106
|
+
description: 'Unsafe deserialization can lead to remote code execution',
|
|
107
|
+
suggestedFix: 'Use safe loaders (yaml.safe_load) or validate input before deserializing',
|
|
108
|
+
},
|
|
109
|
+
// Note: JSON.parse is handled specially with source-aware severity - see json-parse.ts
|
|
110
|
+
// Note: request.json() is NOT a dangerous function - see request-validation.ts
|
|
111
|
+
|
|
112
|
+
// File system risks
|
|
113
|
+
{
|
|
114
|
+
name: 'Dynamic file path',
|
|
115
|
+
pattern: /\b(readFile|writeFile|readFileSync|writeFileSync|createReadStream|createWriteStream)\s*\(\s*[^'"]/gi,
|
|
116
|
+
severity: 'medium',
|
|
117
|
+
description: 'Dynamic file paths can lead to path traversal attacks',
|
|
118
|
+
suggestedFix: 'Validate and sanitize file paths, use path.resolve with a base directory',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: 'Path traversal risk',
|
|
122
|
+
pattern: /path\.(join|resolve)\s*\([^)]*req\.(params|query|body)/gi,
|
|
123
|
+
severity: 'high',
|
|
124
|
+
description: 'User input in file paths can lead to path traversal attacks',
|
|
125
|
+
suggestedFix: 'Validate paths and ensure they stay within allowed directories',
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
// Crypto weaknesses
|
|
129
|
+
{
|
|
130
|
+
name: 'Math.random for security',
|
|
131
|
+
pattern: /Math\.random\s*\(\s*\)/gi,
|
|
132
|
+
severity: 'medium',
|
|
133
|
+
description: 'Math.random() is not cryptographically secure',
|
|
134
|
+
suggestedFix: 'Use crypto.randomBytes() or crypto.getRandomValues() for security-sensitive operations',
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
// Regex DoS
|
|
138
|
+
{
|
|
139
|
+
name: 'Potentially unsafe regex',
|
|
140
|
+
pattern: /new\s+RegExp\s*\(\s*[^'"]/gi,
|
|
141
|
+
severity: 'medium',
|
|
142
|
+
description: 'Dynamic regex construction can lead to ReDoS attacks',
|
|
143
|
+
suggestedFix: 'Validate regex patterns and consider using safe-regex library',
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
// Prototype pollution
|
|
147
|
+
{
|
|
148
|
+
name: 'Object.assign with user input',
|
|
149
|
+
pattern: /Object\.assign\s*\(\s*\{\s*\}\s*,\s*(req\.|request\.|body|params|query)/gi,
|
|
150
|
+
severity: 'high',
|
|
151
|
+
description: 'Object.assign with user input can lead to prototype pollution',
|
|
152
|
+
suggestedFix: 'Validate and sanitize input, or use a safe merge function',
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: 'Spread operator with user input',
|
|
156
|
+
pattern: /\{\s*\.\.\.req\.(body|params|query)|\.\.\.request\.(body|params|query)/gi,
|
|
157
|
+
severity: 'medium',
|
|
158
|
+
description: 'Spreading user input can lead to mass assignment vulnerabilities',
|
|
159
|
+
suggestedFix: 'Explicitly pick allowed properties instead of spreading all input',
|
|
160
|
+
},
|
|
161
|
+
]
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Check if file matches language filter
|
|
165
|
+
*/
|
|
166
|
+
export function matchesLanguage(filePath: string, languages?: string[]): boolean {
|
|
167
|
+
if (!languages || languages.length === 0) return true
|
|
168
|
+
|
|
169
|
+
const ext = filePath.split('.').pop()?.toLowerCase() || ''
|
|
170
|
+
return languages.some(lang => {
|
|
171
|
+
if (lang === 'py') return ext === 'py'
|
|
172
|
+
if (lang === 'js') return ['js', 'jsx', 'mjs', 'cjs'].includes(ext)
|
|
173
|
+
if (lang === 'ts') return ['ts', 'tsx'].includes(ext)
|
|
174
|
+
return ext === lang
|
|
175
|
+
})
|
|
176
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request Body Validation Detection
|
|
3
|
+
*
|
|
4
|
+
* Detection logic for request.json() / req.json() usage without
|
|
5
|
+
* proper schema validation.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Vulnerability } from '../../types'
|
|
9
|
+
import { isComment } from '../../utils/context-helpers'
|
|
10
|
+
import { hasManualValidation } from './utils/schema-validation'
|
|
11
|
+
import { hasThrowingAuthHelper } from './utils/helpers'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Detect request.json() / req.json() and suggest schema validation
|
|
15
|
+
* This is NOT a dangerous function - it's a prompt for best practices
|
|
16
|
+
*/
|
|
17
|
+
export function detectRequestJsonValidation(
|
|
18
|
+
content: string,
|
|
19
|
+
filePath: string,
|
|
20
|
+
isTestFile: boolean,
|
|
21
|
+
vulnerabilities: Vulnerability[]
|
|
22
|
+
): void {
|
|
23
|
+
// Only check API route files
|
|
24
|
+
if (
|
|
25
|
+
!/\/(api|routes?|handlers?|controllers?)\//i.test(filePath) &&
|
|
26
|
+
!/route\.(ts|js)$/i.test(filePath)
|
|
27
|
+
) {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Skip if route has throwing auth helper - these are already protected routes
|
|
32
|
+
// and the schema validation suggestion is lower priority
|
|
33
|
+
if (hasThrowingAuthHelper(content)) {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const lines = content.split('\n')
|
|
38
|
+
// Matches: request.json(), req.json(), await request.json(), etc.
|
|
39
|
+
const requestJsonPattern = /\b(request|req)\.json\s*\(\s*\)/gi
|
|
40
|
+
|
|
41
|
+
// Check if file has schema validation (library-based)
|
|
42
|
+
const hasSchemaLibrary =
|
|
43
|
+
/\b(zod|yup|joi|ajv|superstruct|valibot|typebox)\b/i.test(content) ||
|
|
44
|
+
/\.parse\s*\(|\.validate\s*\(|\.safeParse\s*\(/i.test(content)
|
|
45
|
+
|
|
46
|
+
// If file has schema library validation, don't report
|
|
47
|
+
if (hasSchemaLibrary) return
|
|
48
|
+
|
|
49
|
+
// Check for manual validation patterns (less robust but still indicates intent)
|
|
50
|
+
const hasManualCheck = hasManualValidation(content)
|
|
51
|
+
|
|
52
|
+
// Track instances for potential aggregation
|
|
53
|
+
const instances: { lineNumber: number; lineContent: string }[] = []
|
|
54
|
+
|
|
55
|
+
lines.forEach((line, index) => {
|
|
56
|
+
if (isComment(line)) return
|
|
57
|
+
|
|
58
|
+
requestJsonPattern.lastIndex = 0
|
|
59
|
+
if (!requestJsonPattern.test(line)) return
|
|
60
|
+
|
|
61
|
+
// Check if there's validation nearby (within 10 lines after)
|
|
62
|
+
const startCheck = index
|
|
63
|
+
const endCheck = Math.min(lines.length, index + 10)
|
|
64
|
+
const nearbyContent = lines.slice(startCheck, endCheck).join('\n')
|
|
65
|
+
|
|
66
|
+
// If there's validation in the nearby lines, skip
|
|
67
|
+
if (
|
|
68
|
+
/\.parse\s*\(|\.validate\s*\(|\.safeParse\s*\(|schema\./i.test(
|
|
69
|
+
nearbyContent
|
|
70
|
+
)
|
|
71
|
+
) {
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// If manual validation is present, skip individual reporting but track for aggregate
|
|
76
|
+
if (hasManualCheck) {
|
|
77
|
+
instances.push({ lineNumber: index + 1, lineContent: line.trim() })
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (isTestFile) {
|
|
82
|
+
return // Don't report in test files
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
instances.push({ lineNumber: index + 1, lineContent: line.trim() })
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
// Don't report if no instances found
|
|
89
|
+
if (instances.length === 0) return
|
|
90
|
+
|
|
91
|
+
// If manual validation exists, create a single info-level note
|
|
92
|
+
if (hasManualCheck && instances.length > 0) {
|
|
93
|
+
vulnerabilities.push({
|
|
94
|
+
id: `request-json-manual-${filePath}`,
|
|
95
|
+
filePath,
|
|
96
|
+
lineNumber: instances[0].lineNumber,
|
|
97
|
+
lineContent: instances[0].lineContent,
|
|
98
|
+
severity: 'info',
|
|
99
|
+
category: 'dangerous_function',
|
|
100
|
+
title: 'Request body with manual validation',
|
|
101
|
+
description: `API endpoint parses request body with manual validation patterns detected. Consider using a schema library (zod, yup) for more robust type-safe validation.`,
|
|
102
|
+
suggestedFix:
|
|
103
|
+
'While manual validation works, schema libraries provide better TypeScript integration and error messages.',
|
|
104
|
+
confidence: 'low',
|
|
105
|
+
layer: 2,
|
|
106
|
+
})
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Aggregate if multiple instances without validation
|
|
111
|
+
if (instances.length >= 2) {
|
|
112
|
+
const lineNumbers = instances.map(i => i.lineNumber).slice(0, 5)
|
|
113
|
+
vulnerabilities.push({
|
|
114
|
+
id: `request-json-aggregated-${filePath}`,
|
|
115
|
+
filePath,
|
|
116
|
+
lineNumber: instances[0].lineNumber,
|
|
117
|
+
lineContent: `${instances.length} instances`,
|
|
118
|
+
severity: 'info',
|
|
119
|
+
category: 'dangerous_function',
|
|
120
|
+
title: `Request body without schema validation (${instances.length} instances)`,
|
|
121
|
+
description: `API endpoint parses request body without visible schema validation at lines: ${lineNumbers.join(', ')}. Consider validating the shape of incoming data.`,
|
|
122
|
+
suggestedFix:
|
|
123
|
+
'Add schema validation (e.g., zod): const body = await request.json(); const data = schema.parse(body);',
|
|
124
|
+
confidence: 'low',
|
|
125
|
+
layer: 2,
|
|
126
|
+
})
|
|
127
|
+
} else {
|
|
128
|
+
// Single instance
|
|
129
|
+
vulnerabilities.push({
|
|
130
|
+
id: `request-json-${filePath}-${instances[0].lineNumber}`,
|
|
131
|
+
filePath,
|
|
132
|
+
lineNumber: instances[0].lineNumber,
|
|
133
|
+
lineContent: instances[0].lineContent,
|
|
134
|
+
severity: 'info',
|
|
135
|
+
category: 'dangerous_function',
|
|
136
|
+
title: 'Request body without schema validation',
|
|
137
|
+
description:
|
|
138
|
+
'API endpoint parses request body without visible schema validation. Consider validating the shape of incoming data.',
|
|
139
|
+
suggestedFix:
|
|
140
|
+
'Add schema validation (e.g., zod): const body = await request.json(); const data = schema.parse(body);',
|
|
141
|
+
confidence: 'low',
|
|
142
|
+
layer: 2,
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Control Flow Analysis Utilities
|
|
3
|
+
*
|
|
4
|
+
* Backward-compatible wrappers around shared code-analysis utilities.
|
|
5
|
+
* Existing callers pass (content: string, lineNumber: number) — these
|
|
6
|
+
* wrappers create a temporary ParsedFile to delegate to the shared implementation.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { ParsedFile } from '../../../utils/parsed-file'
|
|
10
|
+
import * as codeAnalysis from '../../../utils/code-analysis'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check if a line is inside a try-catch block
|
|
14
|
+
* Looks for enclosing try { ... } catch pattern
|
|
15
|
+
*/
|
|
16
|
+
export function isInsideTryCatch(content: string, lineNumber: number): boolean {
|
|
17
|
+
return codeAnalysis.isInsideTryCatch(new ParsedFile(content, ''), lineNumber)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Simpler heuristic: check if there's a try-catch in the same function scope
|
|
22
|
+
* Looks for try { before the line and } catch after, within reasonable bounds
|
|
23
|
+
*/
|
|
24
|
+
export function hasTryCatchNearby(content: string, lineNumber: number, windowSize: number = 20): boolean {
|
|
25
|
+
return codeAnalysis.hasTryCatchNearby(new ParsedFile(content, ''), lineNumber, windowSize)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Extract function context where a call is being made
|
|
30
|
+
* Looks backwards from the current line to find enclosing function name
|
|
31
|
+
* Returns lowercase function name or null if not found
|
|
32
|
+
*/
|
|
33
|
+
export function extractFunctionContext(content: string, lineNumber: number): string | null {
|
|
34
|
+
return codeAnalysis.extractFunctionContext(new ParsedFile(content, ''), lineNumber)
|
|
35
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* General Helper Utilities
|
|
3
|
+
*
|
|
4
|
+
* Small utility functions used across the dangerous functions detection module.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Get a specific line from content by line number (0-indexed)
|
|
9
|
+
*/
|
|
10
|
+
export function getLineContent(content: string, lineNumber: number): string {
|
|
11
|
+
const lines = content.split('\n')
|
|
12
|
+
return lines[lineNumber] || ''
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Get a range of lines from content
|
|
17
|
+
*/
|
|
18
|
+
export function getLineRange(
|
|
19
|
+
content: string,
|
|
20
|
+
startLine: number,
|
|
21
|
+
endLine: number
|
|
22
|
+
): string {
|
|
23
|
+
const lines = content.split('\n')
|
|
24
|
+
const start = Math.max(0, startLine)
|
|
25
|
+
const end = Math.min(lines.length, endLine)
|
|
26
|
+
return lines.slice(start, end).join('\n')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Check if eval/exec/Function has only static literal inputs (no user data)
|
|
31
|
+
* Static inputs like eval('({ mode: "production" })') are low risk
|
|
32
|
+
*
|
|
33
|
+
* Returns true ONLY if the argument is a string literal (not a variable)
|
|
34
|
+
*/
|
|
35
|
+
export function hasOnlyStaticInputs(
|
|
36
|
+
lineContent: string,
|
|
37
|
+
content: string,
|
|
38
|
+
lineNumber: number
|
|
39
|
+
): boolean {
|
|
40
|
+
// Check if the argument to eval/exec/Function is a string literal ONLY
|
|
41
|
+
// If it's a variable, it's NOT static (could come from anywhere)
|
|
42
|
+
//
|
|
43
|
+
// String literal patterns:
|
|
44
|
+
// - Single quotes: 'content with "double quotes" inside' (no $ interpolation)
|
|
45
|
+
// - Double quotes: "content" (no $ interpolation)
|
|
46
|
+
// - Backticks without ${}: `content` (template literal but no interpolation)
|
|
47
|
+
//
|
|
48
|
+
// Note: We allow quotes INSIDE the string (e.g., 'text "with" quotes')
|
|
49
|
+
// but NOT $ (which would indicate interpolation)
|
|
50
|
+
const staticPatterns = [
|
|
51
|
+
// Single-quoted string: eval('...') - can contain anything except single quotes and $
|
|
52
|
+
/eval\s*\(\s*'[^'$]*'\s*\)/,
|
|
53
|
+
// Double-quoted string: eval("...") - can contain anything except double quotes and $
|
|
54
|
+
/eval\s*\(\s*"[^"$]*"\s*\)/,
|
|
55
|
+
// Backtick without interpolation: eval(`...`) - must not have ${ inside
|
|
56
|
+
/eval\s*\(\s*`[^`$]*`\s*\)/,
|
|
57
|
+
// Function constructor with string literal
|
|
58
|
+
/new\s+Function\s*\(\s*'[^'$]*'\s*\)/,
|
|
59
|
+
/new\s+Function\s*\(\s*"[^"$]*"\s*\)/,
|
|
60
|
+
// execSync with string literal
|
|
61
|
+
/execSync\s*\(\s*'[^'$]*'\s*\)/,
|
|
62
|
+
/execSync\s*\(\s*"[^"$]*"\s*\)/,
|
|
63
|
+
// exec with string literal
|
|
64
|
+
/exec\s*\(\s*'[^'$]*'/,
|
|
65
|
+
/exec\s*\(\s*"[^"$]*"/,
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
// Only return true if it matches a static pattern (string literal)
|
|
69
|
+
// If it's a variable like eval(code), we can't assume it's static
|
|
70
|
+
return staticPatterns.some(p => p.test(lineContent))
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Check if path traversal protection is in place
|
|
75
|
+
* Looks for common sanitization patterns that prevent directory traversal attacks
|
|
76
|
+
*/
|
|
77
|
+
export function hasPathTraversalProtection(
|
|
78
|
+
context: string,
|
|
79
|
+
lineContent: string
|
|
80
|
+
): boolean {
|
|
81
|
+
const protectionPatterns = [
|
|
82
|
+
// Path normalization with base directory check (same line)
|
|
83
|
+
/path\.resolve\s*\([^)]+\).*\.startsWith\s*\(/i,
|
|
84
|
+
|
|
85
|
+
// startsWith check with common safe directory variable names
|
|
86
|
+
/\.startsWith\s*\([^)]*(?:baseDir|basePath|rootDir|uploadDir|allowedDir|safeDir|SAFE_)/i,
|
|
87
|
+
|
|
88
|
+
// MULTI-LINE PATTERN: path.resolve followed by startsWith check in context
|
|
89
|
+
// This handles the common case where resolve and startsWith are on separate lines:
|
|
90
|
+
// const resolved = path.resolve(baseDir, userPath)
|
|
91
|
+
// if (!resolved.startsWith(baseDir)) throw new Error()
|
|
92
|
+
// We check for BOTH patterns being present in the context
|
|
93
|
+
// (handled below as combined check)
|
|
94
|
+
|
|
95
|
+
// Explicit ".." rejection
|
|
96
|
+
/\.includes\s*\(\s*['"`]\.\.['"`]\s*\)/i,
|
|
97
|
+
/\.indexOf\s*\(\s*['"`]\.\.['"`]\s*\)/i,
|
|
98
|
+
/['"`]\.\.['"`].*(?:throw|reject|return|error)/i,
|
|
99
|
+
// Replace ".." pattern (sanitization)
|
|
100
|
+
/\.replace\s*\([^)]*\\?\.\\?\.\s*[^)]*,\s*['"`]['"`]\s*\)/i,
|
|
101
|
+
|
|
102
|
+
// Path sanitization libraries
|
|
103
|
+
/sanitizePath|sanitizeFilename|sanitize-filename/i,
|
|
104
|
+
/path-sanitizer|secure-path/i,
|
|
105
|
+
|
|
106
|
+
// Explicit path validation
|
|
107
|
+
/validatePath|isValidPath|checkPath|verifyPath/i,
|
|
108
|
+
/isPathAllowed|isAllowedPath|pathIsAllowed/i,
|
|
109
|
+
|
|
110
|
+
// Normalize and check pattern
|
|
111
|
+
/path\.normalize\s*\([^)]+\).*(?:startsWith|includes|indexOf)/i,
|
|
112
|
+
|
|
113
|
+
// Regex validation for safe characters only
|
|
114
|
+
/\/\^?\[a-zA-Z0-9_\-\.\\\/\]\+\$?\//, // Only alphanumeric, dash, underscore, dot
|
|
115
|
+
|
|
116
|
+
// Allowlist/whitelist patterns
|
|
117
|
+
/allowedExtensions|allowedTypes|whitelist/i,
|
|
118
|
+
/\.endsWith\s*\(\s*['"`]\.\w+['"`]\s*\)/i, // Extension check
|
|
119
|
+
|
|
120
|
+
// Path.basename to strip directory
|
|
121
|
+
/path\.basename\s*\(/i,
|
|
122
|
+
|
|
123
|
+
// Zod/validation for filename patterns
|
|
124
|
+
/z\.string\s*\(\s*\)\.regex\s*\(/i,
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
// Check single-line patterns
|
|
128
|
+
if (protectionPatterns.some(p => p.test(context) || p.test(lineContent))) {
|
|
129
|
+
return true
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Multi-line pattern: path.resolve + startsWith check on separate lines
|
|
133
|
+
// This is a very common secure pattern:
|
|
134
|
+
// const resolved = path.resolve(safeBaseDir, userInput)
|
|
135
|
+
// if (!resolved.startsWith(safeBaseDir)) { throw ... }
|
|
136
|
+
const hasPathResolve = /path\.resolve\s*\(/i.test(context)
|
|
137
|
+
const hasStartsWithCheck = /\.startsWith\s*\(/i.test(context)
|
|
138
|
+
const hasThrowOnFailure = /(throw|return|reject)\s+.*(error|invalid|denied)/i.test(context)
|
|
139
|
+
|
|
140
|
+
if (hasPathResolve && hasStartsWithCheck && hasThrowOnFailure) {
|
|
141
|
+
return true
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return false
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Check if route has throwing auth helper (getCurrentUserId, requireAuth, etc.)
|
|
149
|
+
* Routes with throwing auth helpers are already protected
|
|
150
|
+
*/
|
|
151
|
+
export function hasThrowingAuthHelper(content: string): boolean {
|
|
152
|
+
const throwingAuthPatterns = [
|
|
153
|
+
/\bgetCurrentUserId\s*\(/i,
|
|
154
|
+
/\brequireAuth\s*\(/i,
|
|
155
|
+
/\bensureAuth\s*\(/i,
|
|
156
|
+
/\bauth\s*\(\s*\)\s*\.protect\s*\(/i, // Clerk: auth().protect()
|
|
157
|
+
/\bcurrentUser\s*\(\s*\)/i, // Clerk: currentUser()
|
|
158
|
+
/\bgetServerSession\s*\([^)]*\)/i, // NextAuth
|
|
159
|
+
/\bauth\s*\(\s*\)/i, // Generic auth() call
|
|
160
|
+
/\bcheckAuth\s*\(/i,
|
|
161
|
+
/\bverifyAuth\s*\(/i,
|
|
162
|
+
/\bvalidateAuth\s*\(/i,
|
|
163
|
+
/\bassertAuth\s*\(/i,
|
|
164
|
+
/\bgetAuth\s*\(/i,
|
|
165
|
+
/\brequireUser\s*\(/i,
|
|
166
|
+
/\bgetUser\s*\(\s*\)/i, // supabase.auth.getUser()
|
|
167
|
+
/const\s+\{\s*user\s*\}\s*=\s*await/i, // Destructuring pattern
|
|
168
|
+
]
|
|
169
|
+
return throwingAuthPatterns.some(p => p.test(content))
|
|
170
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility Functions Index
|
|
3
|
+
*
|
|
4
|
+
* Re-exports all utility functions from the dangerous-functions module.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
isInsideTryCatch,
|
|
9
|
+
hasTryCatchNearby,
|
|
10
|
+
extractFunctionContext,
|
|
11
|
+
} from './control-flow'
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
hasSchemaValidationNearby,
|
|
15
|
+
hasManualValidation,
|
|
16
|
+
hasSQLWhitelistValidation,
|
|
17
|
+
} from './schema-validation'
|
|
18
|
+
|
|
19
|
+
export {
|
|
20
|
+
getLineContent,
|
|
21
|
+
getLineRange,
|
|
22
|
+
hasOnlyStaticInputs,
|
|
23
|
+
hasPathTraversalProtection,
|
|
24
|
+
hasThrowingAuthHelper,
|
|
25
|
+
} from './helpers'
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema Validation Detection Utilities
|
|
3
|
+
*
|
|
4
|
+
* Functions for detecting schema validation patterns (zod, yup, joi, etc.)
|
|
5
|
+
* and manual validation patterns.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Check if schema validation is applied near a JSON.parse call
|
|
10
|
+
* Looks for zod, yup, joi, or similar validation patterns
|
|
11
|
+
*/
|
|
12
|
+
export function hasSchemaValidationNearby(content: string, lineNumber: number): boolean {
|
|
13
|
+
const lines = content.split('\n')
|
|
14
|
+
const start = Math.max(0, lineNumber - 5)
|
|
15
|
+
const end = Math.min(lines.length, lineNumber + 10)
|
|
16
|
+
const context = lines.slice(start, end).join('\n')
|
|
17
|
+
|
|
18
|
+
const schemaValidationPatterns = [
|
|
19
|
+
// Zod patterns
|
|
20
|
+
/z\.(object|string|number|array|boolean)\s*\(/i,
|
|
21
|
+
/\.parse\s*\(/i,
|
|
22
|
+
/\.safeParse\s*\(/i,
|
|
23
|
+
/schema\.parse/i,
|
|
24
|
+
/Schema\.parse/i,
|
|
25
|
+
// Yup patterns
|
|
26
|
+
/yup\.(object|string|number|array|boolean)\s*\(/i,
|
|
27
|
+
/\.validate\s*\(/i,
|
|
28
|
+
/\.validateSync\s*\(/i,
|
|
29
|
+
// Joi patterns
|
|
30
|
+
/Joi\.(object|string|number|array|boolean)\s*\(/i,
|
|
31
|
+
/\.validateAsync\s*\(/i,
|
|
32
|
+
// Valibot patterns
|
|
33
|
+
/v\.(object|string|number|array|boolean)\s*\(/i,
|
|
34
|
+
// AJV patterns
|
|
35
|
+
/ajv\.compile/i,
|
|
36
|
+
/validate\s*\(\s*schema/i,
|
|
37
|
+
// TypeBox patterns
|
|
38
|
+
/Type\.(Object|String|Number|Array|Boolean)\s*\(/i,
|
|
39
|
+
// Generic validation patterns
|
|
40
|
+
/validateSchema/i,
|
|
41
|
+
/schemaValidator/i,
|
|
42
|
+
/parseAndValidate/i,
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
return schemaValidationPatterns.some(p => p.test(context))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Check if this file appears to have form/input validation elsewhere
|
|
50
|
+
* (manual checks on body fields, type guards, etc.)
|
|
51
|
+
*/
|
|
52
|
+
export function hasManualValidation(content: string): boolean {
|
|
53
|
+
const manualValidationPatterns = [
|
|
54
|
+
// Type checking / type guards
|
|
55
|
+
/typeof\s+\w+\s*[!=]==?\s*['"](?:string|number|boolean|object)['"]|Array\.isArray\s*\(/i,
|
|
56
|
+
// Field existence checks followed by throws/returns
|
|
57
|
+
/if\s*\(\s*!(?:body|data|input)\.\w+\s*\)\s*\{?\s*(throw|return)/i,
|
|
58
|
+
// Property access with type assertion comments or inline validation
|
|
59
|
+
/\b(body|data|input)\s*as\s+\w+/i, // Type assertion
|
|
60
|
+
// Manual validation with error handling
|
|
61
|
+
/if\s*\(\s*![\w.]+\s*\|\|\s*typeof\s+[\w.]+/i,
|
|
62
|
+
// Using type predicates
|
|
63
|
+
/is\w+\s*\([\w.]+\)/i, // isFoo(bar) pattern
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
return manualValidationPatterns.some(p => p.test(content))
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Check if SQL query uses whitelist validation pattern
|
|
71
|
+
* e.g., columns validated against allowedColumns array before use
|
|
72
|
+
*/
|
|
73
|
+
export function hasSQLWhitelistValidation(content: string, lineNumber: number): boolean {
|
|
74
|
+
const lines = content.split('\n')
|
|
75
|
+
const contextStart = Math.max(0, lineNumber - 20)
|
|
76
|
+
const contextEnd = Math.min(lines.length, lineNumber + 5)
|
|
77
|
+
const context = lines.slice(contextStart, contextEnd).join('\n')
|
|
78
|
+
|
|
79
|
+
// Whitelist/allowlist validation patterns
|
|
80
|
+
const whitelistPatterns = [
|
|
81
|
+
// Array-based whitelists
|
|
82
|
+
/allowed\w*\s*=\s*\[/i, // allowedColumns = [...]
|
|
83
|
+
/whitelist\w*\s*=\s*\[/i, // whitelistFields = [...]
|
|
84
|
+
/valid\w*\s*=\s*\[/i, // validColumns = [...]
|
|
85
|
+
/\.filter\s*\([^)]*\.includes\s*\(/i, // .filter(c => allowed.includes(c))
|
|
86
|
+
/\.includes\s*\([^)]*\)/i, // allowedColumns.includes(col)
|
|
87
|
+
/\.every\s*\([^)]*\.includes/i, // columns.every(c => allowed.includes(c))
|
|
88
|
+
/if\s*\(\s*!.*\.includes/i, // if (!allowed.includes(...))
|
|
89
|
+
|
|
90
|
+
// Object-based whitelists (Record<string, string>)
|
|
91
|
+
/\w+\s+in\s+\w*(?:sortable|allowed|valid|whitelist)\w*/i, // sorter in sortableFields
|
|
92
|
+
/\w+\s+in\s+\w+Fields/i, // key in someFields
|
|
93
|
+
/:\s*Record<string,\s*string>/i, // Type annotation: Record<string, string>
|
|
94
|
+
/const\s+\w+Fields\s*:\s*\{[^}]*\}\s*=/i, // const xyzFields: {...} = (inline type)
|
|
95
|
+
/const\s+\w+Fields\s*=\s*\{[^}]*\}/i, // const xyzFields = { ... }
|
|
96
|
+
/if\s*\([^)]*\s+in\s+\w+Fields\s*\)/i, // if (x in yFields)
|
|
97
|
+
/&&\s*\w+\s+in\s+\w+/i, // && sorter in sortableFields
|
|
98
|
+
|
|
99
|
+
// Enum-based validation (ASC/DESC, etc.)
|
|
100
|
+
/===?\s*['"](?:ASC|DESC)['"]/i, // === 'ASC' or === 'DESC'
|
|
101
|
+
/===?\s*\w+\.(?:Asc|Desc|ASC|DESC)/i, // === SortType.Asc
|
|
102
|
+
/toLowerCase\s*\(\s*\)\s*===?\s*\w+\.(?:asc|desc)/i, // .toLowerCase() === SortType.asc
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
return whitelistPatterns.some(p => p.test(context))
|
|
106
|
+
}
|