@oculum/scanner 1.0.9 → 1.0.11
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/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/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 +1 -1
- package/dist/formatters/github-comment.d.ts.map +1 -1
- package/dist/formatters/github-comment.js +75 -11
- package/dist/formatters/github-comment.js.map +1 -1
- package/dist/formatters/index.d.ts +1 -1
- package/dist/formatters/index.d.ts.map +1 -1
- package/dist/formatters/index.js +4 -1
- package/dist/formatters/index.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +155 -16
- package/dist/index.js.map +1 -1
- package/dist/layer1/config-audit.d.ts.map +1 -1
- package/dist/layer1/config-audit.js +20 -3
- package/dist/layer1/config-audit.js.map +1 -1
- package/dist/layer1/config-mcp-audit.d.ts +20 -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/index.d.ts +1 -0
- package/dist/layer1/index.d.ts.map +1 -1
- package/dist/layer1/index.js +9 -1
- package/dist/layer1/index.js.map +1 -1
- package/dist/layer2/ai-agent-tools.d.ts.map +1 -1
- package/dist/layer2/ai-agent-tools.js +303 -0
- package/dist/layer2/ai-agent-tools.js.map +1 -1
- package/dist/layer2/ai-endpoint-protection.d.ts.map +1 -1
- package/dist/layer2/ai-endpoint-protection.js +17 -3
- package/dist/layer2/ai-endpoint-protection.js.map +1 -1
- package/dist/layer2/ai-execution-sinks.d.ts.map +1 -1
- package/dist/layer2/ai-execution-sinks.js +462 -12
- package/dist/layer2/ai-execution-sinks.js.map +1 -1
- package/dist/layer2/ai-fingerprinting.d.ts.map +1 -1
- package/dist/layer2/ai-fingerprinting.js +3 -0
- package/dist/layer2/ai-fingerprinting.js.map +1 -1
- package/dist/layer2/ai-mcp-security.d.ts +17 -0
- package/dist/layer2/ai-mcp-security.d.ts.map +1 -0
- package/dist/layer2/ai-mcp-security.js +679 -0
- package/dist/layer2/ai-mcp-security.js.map +1 -0
- package/dist/layer2/ai-package-hallucination.d.ts +19 -0
- package/dist/layer2/ai-package-hallucination.d.ts.map +1 -0
- package/dist/layer2/ai-package-hallucination.js +696 -0
- package/dist/layer2/ai-package-hallucination.js.map +1 -0
- package/dist/layer2/ai-prompt-hygiene.d.ts.map +1 -1
- package/dist/layer2/ai-prompt-hygiene.js +495 -9
- package/dist/layer2/ai-prompt-hygiene.js.map +1 -1
- package/dist/layer2/ai-rag-safety.d.ts.map +1 -1
- package/dist/layer2/ai-rag-safety.js +372 -1
- package/dist/layer2/ai-rag-safety.js.map +1 -1
- package/dist/layer2/auth-antipatterns.d.ts.map +1 -1
- package/dist/layer2/auth-antipatterns.js +4 -0
- package/dist/layer2/auth-antipatterns.js.map +1 -1
- package/dist/layer2/byok-patterns.d.ts.map +1 -1
- package/dist/layer2/byok-patterns.js +3 -0
- 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 +29 -0
- package/dist/layer2/dangerous-functions/dom-xss.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions/dom-xss.js +179 -0
- package/dist/layer2/dangerous-functions/dom-xss.js.map +1 -0
- package/dist/layer2/dangerous-functions/index.d.ts +13 -0
- package/dist/layer2/dangerous-functions/index.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions/index.js +621 -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 +61 -0
- package/dist/layer2/dangerous-functions/math-random.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions/math-random.js +459 -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 +161 -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 +23 -0
- package/dist/layer2/dangerous-functions/utils/control-flow.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions/utils/control-flow.js +149 -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 +124 -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 +89 -0
- package/dist/layer2/dangerous-functions/utils/schema-validation.js.map +1 -0
- package/dist/layer2/data-exposure.d.ts.map +1 -1
- package/dist/layer2/data-exposure.js +3 -0
- package/dist/layer2/data-exposure.js.map +1 -1
- package/dist/layer2/framework-checks.d.ts.map +1 -1
- package/dist/layer2/framework-checks.js +3 -0
- package/dist/layer2/framework-checks.js.map +1 -1
- package/dist/layer2/index.d.ts +3 -0
- package/dist/layer2/index.d.ts.map +1 -1
- package/dist/layer2/index.js +61 -2
- package/dist/layer2/index.js.map +1 -1
- package/dist/layer2/logic-gates.d.ts.map +1 -1
- package/dist/layer2/logic-gates.js +4 -0
- package/dist/layer2/logic-gates.js.map +1 -1
- package/dist/layer2/model-supply-chain.d.ts +20 -0
- package/dist/layer2/model-supply-chain.d.ts.map +1 -0
- package/dist/layer2/model-supply-chain.js +376 -0
- package/dist/layer2/model-supply-chain.js.map +1 -0
- package/dist/layer2/risky-imports.d.ts.map +1 -1
- package/dist/layer2/risky-imports.js +4 -0
- package/dist/layer2/risky-imports.js.map +1 -1
- package/dist/layer2/variables.d.ts.map +1 -1
- package/dist/layer2/variables.js +4 -0
- 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 +188 -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/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 +1 -1
- package/dist/tiers.d.ts.map +1 -1
- package/dist/tiers.js +27 -0
- package/dist/tiers.js.map +1 -1
- package/dist/types.d.ts +62 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/context-helpers.d.ts +4 -0
- package/dist/utils/context-helpers.d.ts.map +1 -1
- package/dist/utils/context-helpers.js +13 -9
- package/dist/utils/context-helpers.js.map +1 -1
- 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 +18 -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__/snapshots/__snapshots__/anthropic-validation-refactor.test.ts.snap +758 -0
- package/src/__tests__/snapshots/__snapshots__/dangerous-functions-refactor.test.ts.snap +503 -0
- package/src/__tests__/snapshots/anthropic-validation-refactor.test.ts +321 -0
- package/src/__tests__/snapshots/dangerous-functions-refactor.test.ts +439 -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/formatters/cli-terminal.ts +444 -41
- package/src/formatters/github-comment.ts +79 -11
- package/src/formatters/index.ts +4 -0
- package/src/index.ts +197 -14
- package/src/layer1/config-audit.ts +24 -3
- package/src/layer1/config-mcp-audit.ts +276 -0
- package/src/layer1/index.ts +16 -6
- package/src/layer2/ai-agent-tools.ts +336 -0
- package/src/layer2/ai-endpoint-protection.ts +16 -3
- package/src/layer2/ai-execution-sinks.ts +516 -12
- package/src/layer2/ai-fingerprinting.ts +5 -1
- package/src/layer2/ai-mcp-security.ts +730 -0
- package/src/layer2/ai-package-hallucination.ts +791 -0
- package/src/layer2/ai-prompt-hygiene.ts +547 -9
- package/src/layer2/ai-rag-safety.ts +382 -3
- package/src/layer2/auth-antipatterns.ts +5 -0
- package/src/layer2/byok-patterns.ts +5 -1
- package/src/layer2/dangerous-functions/child-process.ts +98 -0
- package/src/layer2/dangerous-functions/dom-xss.ts +220 -0
- package/src/layer2/dangerous-functions/index.ts +949 -0
- package/src/layer2/dangerous-functions/json-parse.ts +385 -0
- package/src/layer2/dangerous-functions/math-random.ts +537 -0
- package/src/layer2/dangerous-functions/patterns.ts +174 -0
- package/src/layer2/dangerous-functions/request-validation.ts +145 -0
- package/src/layer2/dangerous-functions/utils/control-flow.ts +162 -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 +91 -0
- package/src/layer2/data-exposure.ts +5 -1
- package/src/layer2/framework-checks.ts +5 -0
- package/src/layer2/index.ts +63 -1
- package/src/layer2/logic-gates.ts +5 -0
- package/src/layer2/model-supply-chain.ts +456 -0
- package/src/layer2/risky-imports.ts +5 -0
- package/src/layer2/variables.ts +5 -0
- package/src/layer3/__tests__/osv-check.test.ts +384 -0
- package/src/layer3/anthropic/auto-dismiss.ts +212 -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/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 +36 -0
- package/src/types.ts +90 -0
- package/src/utils/context-helpers.ts +13 -9
- 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
|
@@ -124,6 +124,50 @@ function hasTenantContextVerification(context: string): boolean {
|
|
|
124
124
|
return tenantContextPatterns.some(p => p.test(context))
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Check if this is an MCP file with proper security controls
|
|
129
|
+
* MCP files with sanitization and authorization should be downgraded
|
|
130
|
+
*/
|
|
131
|
+
function isMCPFileWithSafePatterns(content: string, filePath: string): boolean {
|
|
132
|
+
// Check if this is an MCP file
|
|
133
|
+
const mcpPatterns = [
|
|
134
|
+
/McpServer/i,
|
|
135
|
+
/@modelcontextprotocol/i,
|
|
136
|
+
/server\.tool\s*\(/i,
|
|
137
|
+
/@server\.tool/i,
|
|
138
|
+
/\/mcp\//i,
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
if (!mcpPatterns.some(p => p.test(content) || p.test(filePath))) {
|
|
142
|
+
return false
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Check for content sanitization patterns
|
|
146
|
+
const sanitizationPatterns = [
|
|
147
|
+
/sanitize|DOMPurify|purify/i,
|
|
148
|
+
/escapeHtml|escape_html/i,
|
|
149
|
+
/validateSchema|schema\.parse|safeParse/i,
|
|
150
|
+
/ALLOWED_TAGS/i,
|
|
151
|
+
/filterHtml|cleanHtml/i,
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
// Check for authorization patterns
|
|
155
|
+
const authorizationPatterns = [
|
|
156
|
+
/if\s*\([^)]*ownerId\s*[!=]==?/i,
|
|
157
|
+
/if\s*\([^)]*userId\s*[!=]==?/i,
|
|
158
|
+
/if\s*\([^)]*tenantId\s*[!=]==?/i,
|
|
159
|
+
/throw.*Error.*(?:auth|Forbidden|Unauthorized)/i,
|
|
160
|
+
/Not\s*authorized/i,
|
|
161
|
+
/checkPermission|hasPermission|isAuthorized/i,
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
const hasSanitization = sanitizationPatterns.some(p => p.test(content))
|
|
165
|
+
const hasAuthorization = authorizationPatterns.some(p => p.test(content))
|
|
166
|
+
|
|
167
|
+
// MCP file with BOTH sanitization AND authorization is safe
|
|
168
|
+
return hasSanitization && hasAuthorization
|
|
169
|
+
}
|
|
170
|
+
|
|
127
171
|
/**
|
|
128
172
|
* Patterns indicating strong/verified restrictions (actual implementation)
|
|
129
173
|
*/
|
|
@@ -412,6 +456,197 @@ const OVERPERMISSIVE_TOOL_PATTERNS: ToolPattern[] = [
|
|
|
412
456
|
},
|
|
413
457
|
]
|
|
414
458
|
|
|
459
|
+
// ============================================================================
|
|
460
|
+
// Phase 2: Excessive Agency Detection
|
|
461
|
+
// ============================================================================
|
|
462
|
+
|
|
463
|
+
interface ExcessiveAgencyPattern {
|
|
464
|
+
name: string
|
|
465
|
+
pattern: RegExp
|
|
466
|
+
baseSeverity: VulnerabilitySeverity
|
|
467
|
+
description: string
|
|
468
|
+
suggestedFix: string
|
|
469
|
+
framework?: 'crewai' | 'autogen' | 'langchain' | 'generic'
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Check if agent has proper iteration limits
|
|
474
|
+
*/
|
|
475
|
+
function hasIterationLimits(context: string): boolean {
|
|
476
|
+
const limitPatterns = [
|
|
477
|
+
/maxIterations\s*[:=]\s*\d{1,2}\b/i, // 1-99
|
|
478
|
+
/max_iterations\s*[:=]\s*\d{1,2}\b/i,
|
|
479
|
+
/iteration_limit\s*[:=]\s*\d{1,2}\b/i,
|
|
480
|
+
/max_steps\s*[:=]\s*\d{1,2}\b/i,
|
|
481
|
+
]
|
|
482
|
+
return limitPatterns.some(p => p.test(context))
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Check if agent has timeout configured
|
|
487
|
+
*/
|
|
488
|
+
function hasTimeoutConfigured(context: string): boolean {
|
|
489
|
+
const timeoutPatterns = [
|
|
490
|
+
/timeout\s*[:=]\s*[1-9]\d*/i, // Positive number
|
|
491
|
+
/max_execution_time\s*[:=]\s*[1-9]/i,
|
|
492
|
+
/execution_timeout\s*[:=]\s*[1-9]/i,
|
|
493
|
+
]
|
|
494
|
+
return timeoutPatterns.some(p => p.test(context))
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Check if human-in-the-loop is enabled
|
|
499
|
+
*/
|
|
500
|
+
function hasHumanInLoop(context: string): boolean {
|
|
501
|
+
const humanPatterns = [
|
|
502
|
+
/humanInLoop\s*[:=]\s*true/i,
|
|
503
|
+
/human_in_loop\s*[:=]\s*True/i,
|
|
504
|
+
/requireApproval\s*[:=]\s*true/i,
|
|
505
|
+
/require_approval\s*[:=]\s*True/i,
|
|
506
|
+
/human_input_mode\s*[:=]\s*['"`](?:ALWAYS|TERMINATE)['"`]/i,
|
|
507
|
+
/confirm_before\s*[:=]\s*true/i,
|
|
508
|
+
]
|
|
509
|
+
return humanPatterns.some(p => p.test(context))
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Check if Docker is configured for code execution
|
|
514
|
+
*/
|
|
515
|
+
function hasDockerConfigured(context: string): boolean {
|
|
516
|
+
const dockerPatterns = [
|
|
517
|
+
/use_docker\s*[:=]\s*True/i,
|
|
518
|
+
/docker\s*[:=]\s*true/i,
|
|
519
|
+
/container\s*[:=]\s*true/i,
|
|
520
|
+
/sandboxed\s*[:=]\s*true/i,
|
|
521
|
+
]
|
|
522
|
+
return dockerPatterns.some(p => p.test(context))
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Check if budget/cost limits are configured
|
|
527
|
+
*/
|
|
528
|
+
function hasBudgetLimits(context: string): boolean {
|
|
529
|
+
const budgetPatterns = [
|
|
530
|
+
/budgetLimit|budget_limit/i,
|
|
531
|
+
/costLimit|cost_limit/i,
|
|
532
|
+
/max_cost|maxCost/i,
|
|
533
|
+
/spending_limit/i,
|
|
534
|
+
/token_limit|tokenLimit/i,
|
|
535
|
+
]
|
|
536
|
+
return budgetPatterns.some(p => p.test(context))
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Excessive agency patterns for unbounded agent autonomy
|
|
541
|
+
*/
|
|
542
|
+
const EXCESSIVE_AGENCY_PATTERNS: ExcessiveAgencyPattern[] = [
|
|
543
|
+
// ========== Generic Unbounded Loops ==========
|
|
544
|
+
{
|
|
545
|
+
name: 'Unbounded agent loop',
|
|
546
|
+
pattern: /while\s*\(\s*(?:true|1|True)\s*\)[\s\S]{0,100}(?:agent|step|run|execute|iterate)/gi,
|
|
547
|
+
baseSeverity: 'high',
|
|
548
|
+
description: 'Agent runs in an unbounded loop without explicit termination condition. This can lead to infinite execution, resource exhaustion, or runaway costs.',
|
|
549
|
+
suggestedFix: 'Add maxIterations limit: while (iterations < maxIterations) { ... }. Consider adding timeout and cost limits.',
|
|
550
|
+
framework: 'generic',
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
name: 'No iteration limit configured',
|
|
554
|
+
pattern: /maxIterations\s*[:=]\s*(?:-1|null|undefined|None|Infinity|float\s*\(\s*['"`]inf)/gi,
|
|
555
|
+
baseSeverity: 'high',
|
|
556
|
+
description: 'Agent configured with no iteration limit. This allows unbounded execution which can consume excessive resources.',
|
|
557
|
+
suggestedFix: 'Set a reasonable iteration limit: maxIterations: 10 (adjust based on your use case).',
|
|
558
|
+
framework: 'generic',
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
name: 'No timeout configured',
|
|
562
|
+
pattern: /timeout\s*[:=]\s*(?:-1|0|null|undefined|None|false|False)/gi,
|
|
563
|
+
baseSeverity: 'medium',
|
|
564
|
+
description: 'Agent timeout is disabled or set to zero. Long-running agents can hang indefinitely.',
|
|
565
|
+
suggestedFix: 'Configure a reasonable timeout: timeout: 300000 (5 minutes). Adjust based on expected execution time.',
|
|
566
|
+
framework: 'generic',
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
name: 'Auto-approve without human oversight',
|
|
570
|
+
pattern: /(?:autoApprove|auto_approve)\s*[:=]\s*(?:true|True)/gi,
|
|
571
|
+
baseSeverity: 'high',
|
|
572
|
+
description: 'Agent auto-approves actions without human review. Combined with destructive capabilities, this is dangerous.',
|
|
573
|
+
suggestedFix: 'Enable human-in-the-loop for sensitive operations: autoApprove: false, or implement approval workflows for destructive actions.',
|
|
574
|
+
framework: 'generic',
|
|
575
|
+
},
|
|
576
|
+
{
|
|
577
|
+
name: 'Human-in-loop disabled',
|
|
578
|
+
pattern: /(?:humanInLoop|human_in_loop)\s*[:=]\s*(?:false|False)/gi,
|
|
579
|
+
baseSeverity: 'medium',
|
|
580
|
+
description: 'Human oversight is explicitly disabled. The agent can take actions without human review.',
|
|
581
|
+
suggestedFix: 'Enable human-in-the-loop for sensitive operations: humanInLoop: true. Add confirmation prompts for destructive actions.',
|
|
582
|
+
framework: 'generic',
|
|
583
|
+
},
|
|
584
|
+
|
|
585
|
+
// ========== CrewAI Specific ==========
|
|
586
|
+
{
|
|
587
|
+
name: 'CrewAI unsafe code execution mode',
|
|
588
|
+
pattern: /code_execution_mode\s*[:=]\s*['"`]unsafe['"`]/gi,
|
|
589
|
+
baseSeverity: 'critical',
|
|
590
|
+
description: 'CrewAI agent configured with unsafe code execution mode. This allows arbitrary code execution without sandboxing.',
|
|
591
|
+
suggestedFix: 'Use safe mode: code_execution_mode="safe". This runs code in a restricted environment.',
|
|
592
|
+
framework: 'crewai',
|
|
593
|
+
},
|
|
594
|
+
{
|
|
595
|
+
name: 'CrewAI code execution without Docker',
|
|
596
|
+
pattern: /allow_code_execution\s*[:=]\s*True(?![\s\S]{0,50}use_docker\s*[:=]\s*True)/gi,
|
|
597
|
+
baseSeverity: 'high',
|
|
598
|
+
description: 'CrewAI agent allows code execution without Docker containerization. Code runs directly on the host system.',
|
|
599
|
+
suggestedFix: 'Enable Docker for code execution: Agent(..., allow_code_execution=True, code_execution_config={"use_docker": True})',
|
|
600
|
+
framework: 'crewai',
|
|
601
|
+
},
|
|
602
|
+
|
|
603
|
+
// ========== AutoGen Specific ==========
|
|
604
|
+
{
|
|
605
|
+
name: 'AutoGen use_docker=False',
|
|
606
|
+
pattern: /(?:code_execution_config|LocalCommandLineCodeExecutor)\s*[\s\S]{0,50}use_docker\s*[:=]\s*False/gi,
|
|
607
|
+
baseSeverity: 'critical',
|
|
608
|
+
description: 'AutoGen code execution configured without Docker. Code executes directly on the host, enabling full system access.',
|
|
609
|
+
suggestedFix: 'Use Docker: code_execution_config={"use_docker": True}. Or use DockerCommandLineCodeExecutor for sandboxed execution.',
|
|
610
|
+
framework: 'autogen',
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
name: 'AutoGen NEVER human input mode',
|
|
614
|
+
pattern: /human_input_mode\s*[:=]\s*['"`]NEVER['"`]/gi,
|
|
615
|
+
baseSeverity: 'high',
|
|
616
|
+
description: 'AutoGen agent configured to never request human input. Agent can execute indefinitely without human oversight.',
|
|
617
|
+
suggestedFix: 'Use "ALWAYS" or "TERMINATE" for human_input_mode. "TERMINATE" allows agent to complete but requests input on termination.',
|
|
618
|
+
framework: 'autogen',
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
name: 'AutoGen UserProxyAgent without reply limit',
|
|
622
|
+
pattern: /UserProxyAgent\s*\((?![^)]*max_consecutive_auto_reply)[^)]*\)/gi,
|
|
623
|
+
baseSeverity: 'medium',
|
|
624
|
+
description: 'AutoGen UserProxyAgent without max_consecutive_auto_reply limit. Agent can auto-reply indefinitely.',
|
|
625
|
+
suggestedFix: 'Add reply limit: UserProxyAgent(..., max_consecutive_auto_reply=10). Adjust limit based on expected conversation length.',
|
|
626
|
+
framework: 'autogen',
|
|
627
|
+
},
|
|
628
|
+
|
|
629
|
+
// ========== LangChain Specific ==========
|
|
630
|
+
{
|
|
631
|
+
name: 'LangChain AgentExecutor without limits',
|
|
632
|
+
pattern: /AgentExecutor\s*\([^)]*(?!max_iterations)[^)]*\)/gi,
|
|
633
|
+
baseSeverity: 'medium',
|
|
634
|
+
description: 'LangChain AgentExecutor without max_iterations. Agent can loop indefinitely on complex tasks.',
|
|
635
|
+
suggestedFix: 'Set iteration limit: AgentExecutor(..., max_iterations=15). Add early_stopping_method="generate" to gracefully stop.',
|
|
636
|
+
framework: 'langchain',
|
|
637
|
+
},
|
|
638
|
+
|
|
639
|
+
// ========== Overpermissioned Agents ==========
|
|
640
|
+
{
|
|
641
|
+
name: 'Agent with excessive tools',
|
|
642
|
+
pattern: /tools\s*[:=]\s*\[(?:[^\]]*,){10,}[^\]]*\]/gi,
|
|
643
|
+
baseSeverity: 'medium',
|
|
644
|
+
description: 'Agent configured with more than 10 tools. Overpermissioned agents have larger attack surface if compromised via prompt injection.',
|
|
645
|
+
suggestedFix: 'Follow principle of least privilege. Split into specialized agents with focused tool sets. Remove unused tools.',
|
|
646
|
+
framework: 'generic',
|
|
647
|
+
},
|
|
648
|
+
]
|
|
649
|
+
|
|
415
650
|
/**
|
|
416
651
|
* Patterns for missing authorization in tools
|
|
417
652
|
*/
|
|
@@ -506,6 +741,8 @@ export function detectAIAgentTools(
|
|
|
506
741
|
|
|
507
742
|
// Calculate severity
|
|
508
743
|
let severity = pattern.baseSeverity
|
|
744
|
+
const isMCPSafe = isMCPFileWithSafePatterns(content, filePath)
|
|
745
|
+
|
|
509
746
|
if (isTestFile) {
|
|
510
747
|
severity = 'info'
|
|
511
748
|
} else if (isExample) {
|
|
@@ -515,6 +752,9 @@ export function detectAIAgentTools(
|
|
|
515
752
|
// Library code - tool definitions are intentionally flexible
|
|
516
753
|
// Consumers add restrictions when they use the tools
|
|
517
754
|
severity = 'info'
|
|
755
|
+
} else if (isMCPSafe) {
|
|
756
|
+
// MCP file with proper security controls (sanitization + authorization)
|
|
757
|
+
severity = 'info'
|
|
518
758
|
} else if (hasPartialMitigation || hasUserContext || hasTenantContext) {
|
|
519
759
|
// Partial mitigation - downgrade
|
|
520
760
|
if (severity === 'critical') severity = 'high'
|
|
@@ -532,6 +772,8 @@ export function detectAIAgentTools(
|
|
|
532
772
|
description += ' (In example/demo directory - not production code.)'
|
|
533
773
|
} else if (isLibrary) {
|
|
534
774
|
description += ' (Library code - tool definitions are generic; consumers add restrictions.)'
|
|
775
|
+
} else if (isMCPSafe) {
|
|
776
|
+
description += ' (MCP file with sanitization and authorization controls detected.)'
|
|
535
777
|
}
|
|
536
778
|
|
|
537
779
|
vulnerabilities.push({
|
|
@@ -597,5 +839,99 @@ export function detectAIAgentTools(
|
|
|
597
839
|
}
|
|
598
840
|
}
|
|
599
841
|
|
|
842
|
+
// Scan for excessive agency patterns (Phase 2)
|
|
843
|
+
for (const pattern of EXCESSIVE_AGENCY_PATTERNS) {
|
|
844
|
+
const regex = new RegExp(pattern.pattern.source, pattern.pattern.flags)
|
|
845
|
+
let match
|
|
846
|
+
|
|
847
|
+
while ((match = regex.exec(content)) !== null) {
|
|
848
|
+
const lineNumber = content.substring(0, match.index).split('\n').length
|
|
849
|
+
const lineContent = lines[lineNumber - 1]?.trim() || ''
|
|
850
|
+
|
|
851
|
+
// Skip comments
|
|
852
|
+
if (isComment(lineContent)) continue
|
|
853
|
+
|
|
854
|
+
// Get surrounding context for mitigation checks
|
|
855
|
+
const { context } = findToolDefinitionContext(content, lineNumber)
|
|
856
|
+
|
|
857
|
+
// Check for mitigations
|
|
858
|
+
let isMitigated = false
|
|
859
|
+
let isPartiallyMitigated = false
|
|
860
|
+
let description = pattern.description
|
|
861
|
+
|
|
862
|
+
// Check iteration limits
|
|
863
|
+
if (hasIterationLimits(context)) {
|
|
864
|
+
isPartiallyMitigated = true
|
|
865
|
+
description += ' (Iteration limits detected nearby.)'
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// Check timeout configuration
|
|
869
|
+
if (hasTimeoutConfigured(context)) {
|
|
870
|
+
isPartiallyMitigated = true
|
|
871
|
+
description += ' (Timeout configured.)'
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// Check human-in-the-loop
|
|
875
|
+
if (hasHumanInLoop(context)) {
|
|
876
|
+
isPartiallyMitigated = true
|
|
877
|
+
description += ' (Human-in-loop enabled.)'
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// Check Docker for code execution patterns
|
|
881
|
+
if (pattern.framework === 'crewai' || pattern.framework === 'autogen') {
|
|
882
|
+
if (hasDockerConfigured(context)) {
|
|
883
|
+
isMitigated = true
|
|
884
|
+
description += ' (Docker containerization detected.)'
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// Check budget limits
|
|
889
|
+
if (hasBudgetLimits(context)) {
|
|
890
|
+
isPartiallyMitigated = true
|
|
891
|
+
description += ' (Budget limits configured.)'
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
// Calculate severity
|
|
895
|
+
let severity = pattern.baseSeverity
|
|
896
|
+
const isMCPSafe = isMCPFileWithSafePatterns(content, filePath)
|
|
897
|
+
|
|
898
|
+
if (isMitigated) {
|
|
899
|
+
severity = 'info'
|
|
900
|
+
} else if (isTestFile) {
|
|
901
|
+
severity = 'info'
|
|
902
|
+
description += ' (In test file.)'
|
|
903
|
+
} else if (isExample) {
|
|
904
|
+
severity = 'info'
|
|
905
|
+
description += ' (In example/demo directory.)'
|
|
906
|
+
} else if (isLibrary) {
|
|
907
|
+
severity = 'info'
|
|
908
|
+
description += ' (Library code.)'
|
|
909
|
+
} else if (isPartiallyMitigated) {
|
|
910
|
+
// Downgrade if partial mitigations present
|
|
911
|
+
if (severity === 'critical') severity = 'high'
|
|
912
|
+
else if (severity === 'high') severity = 'medium'
|
|
913
|
+
else if (severity === 'medium') severity = 'low'
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// Skip fully mitigated or info-level in non-agent files
|
|
917
|
+
if (isMitigated && severity === 'info') continue
|
|
918
|
+
|
|
919
|
+
vulnerabilities.push({
|
|
920
|
+
id: `ai-agency-${filePath}-${lineNumber}-${pattern.name.replace(/\s+/g, '-')}`,
|
|
921
|
+
filePath,
|
|
922
|
+
lineNumber,
|
|
923
|
+
lineContent,
|
|
924
|
+
severity,
|
|
925
|
+
category: 'ai_excessive_agency',
|
|
926
|
+
title: pattern.name,
|
|
927
|
+
description,
|
|
928
|
+
suggestedFix: pattern.suggestedFix,
|
|
929
|
+
confidence: severity === 'info' ? 'low' : 'medium',
|
|
930
|
+
layer: 2,
|
|
931
|
+
requiresAIValidation: severity !== 'info' && severity !== 'low',
|
|
932
|
+
})
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
|
|
600
936
|
return vulnerabilities
|
|
601
937
|
}
|
|
@@ -136,6 +136,12 @@ function isBYOKEndpoint(content: string): boolean {
|
|
|
136
136
|
// Headers with user's key
|
|
137
137
|
/headers\[['"`]x-openai-key['"`]\]/i,
|
|
138
138
|
/headers\[['"`]x-api-key['"`]\]/i,
|
|
139
|
+
// Destructuring from request body
|
|
140
|
+
/const\s*\{\s*[^}]*apiKey[^}]*\}\s*=\s*await\s*(?:request|req)\.json\(\)/i,
|
|
141
|
+
/const\s*\{\s*[^}]*api_key[^}]*\}\s*=\s*await\s*(?:request|req)\.json\(\)/i,
|
|
142
|
+
// OpenAI/Anthropic client with user-provided key
|
|
143
|
+
/new\s+OpenAI\s*\(\s*\{\s*apiKey\s*[,}]/i,
|
|
144
|
+
/new\s+Anthropic\s*\(\s*\{\s*apiKey\s*[,}]/i,
|
|
139
145
|
]
|
|
140
146
|
return byokPatterns.some(p => p.test(content))
|
|
141
147
|
}
|
|
@@ -327,10 +333,17 @@ export function detectAIEndpointProtection(
|
|
|
327
333
|
notes.push('Missing authentication and rate limiting')
|
|
328
334
|
}
|
|
329
335
|
|
|
330
|
-
// BYOK endpoints have lower risk
|
|
336
|
+
// BYOK endpoints have lower risk - user provides own API key
|
|
331
337
|
if (isByok && severity !== 'info') {
|
|
332
|
-
|
|
333
|
-
|
|
338
|
+
// BYOK with auth = info (user pays for own usage, access controlled)
|
|
339
|
+
// BYOK without auth = low (potential abuse but user still pays)
|
|
340
|
+
if (handlerHasAuth || fileHasAuth) {
|
|
341
|
+
severity = 'info'
|
|
342
|
+
notes.push('BYOK endpoint with authentication - user pays for their own usage')
|
|
343
|
+
} else {
|
|
344
|
+
severity = 'low'
|
|
345
|
+
notes.push('BYOK endpoint without auth - potential abuse but user provides API key')
|
|
346
|
+
}
|
|
334
347
|
}
|
|
335
348
|
|
|
336
349
|
// Downgrade test files
|