@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
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Package Hallucination Test Fixtures
|
|
3
|
+
* Tests for detecting AI-hallucinated/fake package names in dependencies
|
|
4
|
+
*
|
|
5
|
+
* Background: USENIX research shows ~20% of AI-generated code references
|
|
6
|
+
* packages that don't exist, creating supply chain attack vectors.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { TestGroup } from '../../types'
|
|
10
|
+
|
|
11
|
+
export const aiPackageHallucinationTests: TestGroup = {
|
|
12
|
+
name: 'AI Package Hallucination Detection',
|
|
13
|
+
tier: 'A',
|
|
14
|
+
layer: 2,
|
|
15
|
+
description: 'Detection of AI-hallucinated and potentially fake package names in imports and dependencies',
|
|
16
|
+
|
|
17
|
+
truePositives: [
|
|
18
|
+
{
|
|
19
|
+
name: 'Package Hallucination - True Positives (Known Fakes)',
|
|
20
|
+
expectFindings: true,
|
|
21
|
+
expectedCategories: ['ai_package_hallucination'],
|
|
22
|
+
description: 'Known hallucinated packages that MUST be detected',
|
|
23
|
+
file: {
|
|
24
|
+
path: 'src/utils/helpers.ts',
|
|
25
|
+
content: `
|
|
26
|
+
// Known AI-hallucinated package names (verified fakes from research)
|
|
27
|
+
import { Chart } from 'react-charts' // Fake - react-chartjs-2 or recharts are real
|
|
28
|
+
import { MongoClient } from 'mongo-client' // Fake - mongodb is real
|
|
29
|
+
import { PostgresClient } from 'postgres-client' // Fake - pg is real
|
|
30
|
+
import fastJson from 'fast-json' // Fake - fast-json-stringify or ajv are real
|
|
31
|
+
import helpers from 'node-helpers' // Fake - doesn't exist
|
|
32
|
+
|
|
33
|
+
// Import with destructuring
|
|
34
|
+
const { utils } = require('easy-utils') // Fake
|
|
35
|
+
const tools = require('simple-tools') // Fake
|
|
36
|
+
|
|
37
|
+
// Dynamic import
|
|
38
|
+
const csvParser = await import('csv-parser-pro') // Fake - csv-parser or papaparse are real
|
|
39
|
+
`,
|
|
40
|
+
language: 'typescript',
|
|
41
|
+
size: 600,
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'Package Hallucination - True Positives (Suspicious Patterns)',
|
|
46
|
+
expectFindings: true,
|
|
47
|
+
expectedCategories: ['ai_package_hallucination'],
|
|
48
|
+
description: 'Suspicious package naming patterns that suggest hallucination',
|
|
49
|
+
file: {
|
|
50
|
+
path: 'src/api/services.ts',
|
|
51
|
+
content: `
|
|
52
|
+
// Unscoped generic utility names (frequently hallucinated)
|
|
53
|
+
import utils from 'utils' // Too generic - likely hallucinated
|
|
54
|
+
import helpers from 'helpers' // Too generic - likely hallucinated
|
|
55
|
+
import common from 'common' // Too generic - likely hallucinated
|
|
56
|
+
import tools from 'tools' // Too generic - likely hallucinated
|
|
57
|
+
|
|
58
|
+
// easy-* pattern (frequently hallucinated)
|
|
59
|
+
import easyConfig from 'easy-config' // Suspicious pattern
|
|
60
|
+
import easyDb from 'easy-database' // Suspicious pattern
|
|
61
|
+
import easyAuth from 'easy-auth' // Suspicious pattern
|
|
62
|
+
|
|
63
|
+
// simple-* pattern (frequently hallucinated)
|
|
64
|
+
import simpleApi from 'simple-api' // Suspicious pattern
|
|
65
|
+
import simpleServer from 'simple-server' // Suspicious pattern
|
|
66
|
+
import simpleCache from 'simple-cache' // Suspicious pattern
|
|
67
|
+
|
|
68
|
+
// node-* patterns for non-core modules (frequently hallucinated)
|
|
69
|
+
import nodeUtils from 'node-utils' // Suspicious - not a core module
|
|
70
|
+
import nodeHelpers from 'node-helpers' // Suspicious - not a core module
|
|
71
|
+
|
|
72
|
+
// fast-* patterns without real packages
|
|
73
|
+
import fastParser from 'fast-parser' // Suspicious pattern
|
|
74
|
+
import fastValidator from 'fast-validator' // Suspicious pattern
|
|
75
|
+
`,
|
|
76
|
+
language: 'typescript',
|
|
77
|
+
size: 900,
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'Package Hallucination - True Positives (package.json)',
|
|
82
|
+
expectFindings: true,
|
|
83
|
+
expectedCategories: ['ai_package_hallucination'],
|
|
84
|
+
description: 'Hallucinated packages in package.json dependencies',
|
|
85
|
+
file: {
|
|
86
|
+
path: 'package.json',
|
|
87
|
+
content: `{
|
|
88
|
+
"name": "my-app",
|
|
89
|
+
"dependencies": {
|
|
90
|
+
"react": "^18.0.0",
|
|
91
|
+
"react-charts": "^1.0.0",
|
|
92
|
+
"mongo-client": "^3.0.0",
|
|
93
|
+
"easy-config": "^2.0.0",
|
|
94
|
+
"utils": "^1.0.0",
|
|
95
|
+
"helpers": "^1.0.0",
|
|
96
|
+
"node-helpers": "^1.0.0"
|
|
97
|
+
},
|
|
98
|
+
"devDependencies": {
|
|
99
|
+
"simple-test": "^1.0.0",
|
|
100
|
+
"fast-bundler": "^1.0.0"
|
|
101
|
+
}
|
|
102
|
+
}`,
|
|
103
|
+
language: 'json',
|
|
104
|
+
size: 400,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'Package Hallucination - True Positives (requirements.txt)',
|
|
109
|
+
expectFindings: true,
|
|
110
|
+
expectedCategories: ['ai_package_hallucination'],
|
|
111
|
+
description: 'Hallucinated packages in Python requirements',
|
|
112
|
+
file: {
|
|
113
|
+
path: 'requirements.txt',
|
|
114
|
+
content: `# Real packages
|
|
115
|
+
flask==2.0.0
|
|
116
|
+
requests==2.28.0
|
|
117
|
+
|
|
118
|
+
# Likely hallucinated packages
|
|
119
|
+
easy-flask==1.0.0
|
|
120
|
+
simple-api==1.0.0
|
|
121
|
+
fast-db==2.0.0
|
|
122
|
+
python-helpers==1.0.0
|
|
123
|
+
utils==1.0.0
|
|
124
|
+
common==1.0.0
|
|
125
|
+
`,
|
|
126
|
+
language: 'text',
|
|
127
|
+
size: 250,
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
|
|
132
|
+
falseNegatives: [
|
|
133
|
+
{
|
|
134
|
+
name: 'Package Hallucination - False Negatives (Real Packages)',
|
|
135
|
+
expectFindings: false,
|
|
136
|
+
description: 'Real, well-known packages that should NOT be flagged',
|
|
137
|
+
allowedInfoFindings: [
|
|
138
|
+
{
|
|
139
|
+
category: 'suspicious_package',
|
|
140
|
+
maxCount: 2,
|
|
141
|
+
reason: 'Some real packages may trigger info-level findings from risky-imports detector',
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
category: 'ai_package_hallucination',
|
|
145
|
+
maxCount: 1,
|
|
146
|
+
reason: 'Edge cases may generate info-level findings',
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
file: {
|
|
150
|
+
path: 'src/app/real-packages.ts',
|
|
151
|
+
content: `
|
|
152
|
+
// Popular, well-known real packages - SHOULD NOT FLAG
|
|
153
|
+
import React from 'react'
|
|
154
|
+
import { useState } from 'react'
|
|
155
|
+
import express from 'express'
|
|
156
|
+
import axios from 'axios'
|
|
157
|
+
import lodash from 'lodash'
|
|
158
|
+
import { z } from 'zod'
|
|
159
|
+
import dayjs from 'dayjs'
|
|
160
|
+
import { MongoClient } from 'mongodb' // Real (not 'mongo-client')
|
|
161
|
+
import pg from 'pg' // Real postgres client
|
|
162
|
+
import Fastify from 'fastify' // Real
|
|
163
|
+
import csvParser from 'csv-parser' // Real (not 'csv-parser-pro')
|
|
164
|
+
|
|
165
|
+
// Scoped packages are generally real
|
|
166
|
+
import { Hono } from '@hono/hono'
|
|
167
|
+
import { createClient } from '@supabase/supabase-js'
|
|
168
|
+
import { OpenAI } from 'openai'
|
|
169
|
+
import Anthropic from '@anthropic-ai/sdk'
|
|
170
|
+
import { PrismaClient } from '@prisma/client'
|
|
171
|
+
|
|
172
|
+
// These are real 'simple-' packages that exist
|
|
173
|
+
import SimpleSchema from 'simpl-schema' // Real package
|
|
174
|
+
import simpleGit from 'simple-git' // Real package (has >10M weekly downloads)
|
|
175
|
+
|
|
176
|
+
// These are real 'fast-' packages that exist
|
|
177
|
+
import fastJson from 'fast-json-stringify' // Real package
|
|
178
|
+
import fastify from 'fastify' // Real package
|
|
179
|
+
import fastGlob from 'fast-glob' // Real package
|
|
180
|
+
|
|
181
|
+
// Real utility packages with specific names
|
|
182
|
+
import _ from 'underscore'
|
|
183
|
+
import __ from 'radash'
|
|
184
|
+
import clsx from 'clsx'
|
|
185
|
+
import nanoid from 'nanoid'
|
|
186
|
+
`,
|
|
187
|
+
language: 'typescript',
|
|
188
|
+
size: 1000,
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: 'Package Hallucination - False Negatives (Internal/Monorepo)',
|
|
193
|
+
expectFindings: false,
|
|
194
|
+
description: 'Internal monorepo packages that should NOT be flagged',
|
|
195
|
+
file: {
|
|
196
|
+
path: 'apps/web/src/index.ts',
|
|
197
|
+
content: `
|
|
198
|
+
// Internal monorepo packages - these are workspace packages, not external
|
|
199
|
+
import { scanner } from '@oculum/scanner'
|
|
200
|
+
import { shared } from '@oculum/shared'
|
|
201
|
+
import { Button } from '@mycompany/ui'
|
|
202
|
+
import { utils } from '@internal/utils' // Scoped internal is fine
|
|
203
|
+
|
|
204
|
+
// Relative imports should never be flagged
|
|
205
|
+
import { helper } from './utils'
|
|
206
|
+
import { common } from '../shared/common'
|
|
207
|
+
import api from '../../api'
|
|
208
|
+
|
|
209
|
+
// Aliased paths should not be flagged
|
|
210
|
+
import { config } from '@/config'
|
|
211
|
+
import { utils } from '~/utils'
|
|
212
|
+
import { helpers } from '#utils/helpers'
|
|
213
|
+
`,
|
|
214
|
+
language: 'typescript',
|
|
215
|
+
size: 500,
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
name: 'Package Hallucination - False Negatives (Test Files)',
|
|
220
|
+
expectFindings: false,
|
|
221
|
+
description: 'Test files may use mocks that should be downgraded',
|
|
222
|
+
allowedInfoFindings: [
|
|
223
|
+
{
|
|
224
|
+
category: 'ai_package_hallucination',
|
|
225
|
+
maxCount: 3,
|
|
226
|
+
reason: 'Test file mock packages may generate info-level findings',
|
|
227
|
+
},
|
|
228
|
+
],
|
|
229
|
+
file: {
|
|
230
|
+
path: 'src/__tests__/mocks/packages.test.ts',
|
|
231
|
+
content: `
|
|
232
|
+
// Test mocks - these might look suspicious but are test-only
|
|
233
|
+
import mockUtils from 'utils'
|
|
234
|
+
import mockHelpers from 'helpers'
|
|
235
|
+
|
|
236
|
+
jest.mock('utils', () => ({
|
|
237
|
+
format: jest.fn()
|
|
238
|
+
}))
|
|
239
|
+
|
|
240
|
+
jest.mock('helpers', () => ({
|
|
241
|
+
parse: jest.fn()
|
|
242
|
+
}))
|
|
243
|
+
|
|
244
|
+
describe('mock tests', () => {
|
|
245
|
+
it('should work', () => {
|
|
246
|
+
expect(mockUtils).toBeDefined()
|
|
247
|
+
})
|
|
248
|
+
})
|
|
249
|
+
`,
|
|
250
|
+
language: 'typescript',
|
|
251
|
+
size: 400,
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
],
|
|
255
|
+
}
|
|
@@ -10,7 +10,7 @@ export const aiPromptHygieneTests: TestGroup = {
|
|
|
10
10
|
tier: 'B',
|
|
11
11
|
layer: 2,
|
|
12
12
|
description: 'Detection of prompt injection vulnerabilities and unsafe prompt practices',
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
truePositives: [
|
|
15
15
|
{
|
|
16
16
|
name: 'AI Prompt Hygiene - True Positives',
|
|
@@ -87,6 +87,204 @@ export async function concatenatedPrompt(name: string, task: string) {
|
|
|
87
87
|
size: 1600,
|
|
88
88
|
},
|
|
89
89
|
},
|
|
90
|
+
// ========== NEW: Secrets in Prompts True Positives ==========
|
|
91
|
+
{
|
|
92
|
+
name: 'Secrets in Prompts - Provider Tokens',
|
|
93
|
+
expectFindings: true,
|
|
94
|
+
expectedCategories: ['hardcoded_secret'],
|
|
95
|
+
description: 'Various provider API keys/tokens in LLM prompt code that MUST be detected',
|
|
96
|
+
file: {
|
|
97
|
+
path: 'src/api/ai/secrets-in-prompts.ts',
|
|
98
|
+
content: `
|
|
99
|
+
import OpenAI from 'openai'
|
|
100
|
+
import Anthropic from '@anthropic-ai/sdk'
|
|
101
|
+
|
|
102
|
+
const openai = new OpenAI()
|
|
103
|
+
const anthropic = new Anthropic()
|
|
104
|
+
|
|
105
|
+
// 1. OpenAI API key in prompt context - CRITICAL
|
|
106
|
+
export async function openaiKeyInPrompt() {
|
|
107
|
+
const apiKey = "sk-1234567890abcdefghijklmnopqrstuvwxyz"
|
|
108
|
+
return openai.chat.completions.create({
|
|
109
|
+
model: 'gpt-4',
|
|
110
|
+
messages: [
|
|
111
|
+
{ role: 'system', content: \`Use API key \${apiKey} to call the service\` }
|
|
112
|
+
]
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// 2. GitHub token in prompt - CRITICAL
|
|
117
|
+
export async function githubTokenInPrompt() {
|
|
118
|
+
const token = "ghp_abcdefghijklmnopqrstuvwxyz1234567890"
|
|
119
|
+
return openai.chat.completions.create({
|
|
120
|
+
model: 'gpt-4',
|
|
121
|
+
messages: [
|
|
122
|
+
{ role: 'system', content: \`Access the repo using token: \${token}\` }
|
|
123
|
+
]
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 3. Stripe key in prompt - CRITICAL
|
|
128
|
+
export async function stripeKeyInPrompt() {
|
|
129
|
+
const stripeKey = "sk_live_1234567890abcdefghijklmnop"
|
|
130
|
+
return openai.chat.completions.create({
|
|
131
|
+
model: 'gpt-4',
|
|
132
|
+
messages: [
|
|
133
|
+
{ role: 'system', content: \`Process payment with Stripe key: \${stripeKey}\` }
|
|
134
|
+
]
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// 4. AWS credentials in prompt - CRITICAL
|
|
139
|
+
export async function awsCredentialsInPrompt() {
|
|
140
|
+
const awsKey = "AKIAIOSFODNN7EXAMPLE"
|
|
141
|
+
return openai.chat.completions.create({
|
|
142
|
+
model: 'gpt-4',
|
|
143
|
+
messages: [
|
|
144
|
+
{ role: 'system', content: \`AWS access key: \${awsKey}\` }
|
|
145
|
+
]
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// 5. Slack token in prompt - CRITICAL
|
|
150
|
+
export async function slackTokenInPrompt() {
|
|
151
|
+
const slackToken = "xoxb-123456789012-1234567890123-abcdefghijklmnopqrstuvwx"
|
|
152
|
+
return anthropic.messages.create({
|
|
153
|
+
model: 'claude-3-opus-20240229',
|
|
154
|
+
messages: [
|
|
155
|
+
{ role: 'user', content: \`Post to Slack using token: \${slackToken}\` }
|
|
156
|
+
],
|
|
157
|
+
max_tokens: 1024
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// 6. SendGrid key in prompt - CRITICAL
|
|
162
|
+
export async function sendgridKeyInPrompt() {
|
|
163
|
+
const sendgridKey = "SG.abcdefghijklmnopqrstuv.wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789012"
|
|
164
|
+
return openai.chat.completions.create({
|
|
165
|
+
model: 'gpt-4',
|
|
166
|
+
messages: [
|
|
167
|
+
{ role: 'system', content: \`Send email using SendGrid: \${sendgridKey}\` }
|
|
168
|
+
]
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 7. Database URL with credentials - CRITICAL
|
|
173
|
+
export async function dbUrlInPrompt() {
|
|
174
|
+
const dbUrl = "postgres://admin:secretpassword123@db.example.com:5432/mydb"
|
|
175
|
+
return openai.chat.completions.create({
|
|
176
|
+
model: 'gpt-4',
|
|
177
|
+
messages: [
|
|
178
|
+
{ role: 'system', content: \`Connect to database: \${dbUrl}\` }
|
|
179
|
+
]
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// 8. JWT token in prompt - HIGH
|
|
184
|
+
export async function jwtInPrompt() {
|
|
185
|
+
const jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
|
|
186
|
+
return openai.chat.completions.create({
|
|
187
|
+
model: 'gpt-4',
|
|
188
|
+
messages: [
|
|
189
|
+
{ role: 'system', content: \`User session: \${jwt}\` }
|
|
190
|
+
]
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// 9. Private key in prompt - CRITICAL
|
|
195
|
+
export async function privateKeyInPrompt() {
|
|
196
|
+
const privateKey = \`-----BEGIN RSA PRIVATE KEY-----
|
|
197
|
+
MIIEowIBAAKCAQEA0Z3Vx...
|
|
198
|
+
-----END RSA PRIVATE KEY-----\`
|
|
199
|
+
return openai.chat.completions.create({
|
|
200
|
+
model: 'gpt-4',
|
|
201
|
+
messages: [
|
|
202
|
+
{ role: 'system', content: \`Sign with key: \${privateKey}\` }
|
|
203
|
+
]
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// 10. HuggingFace token - CRITICAL
|
|
208
|
+
export async function hfTokenInPrompt() {
|
|
209
|
+
const hfToken = "hf_abcdefghijklmnopqrstuvwxyz1234567890"
|
|
210
|
+
return openai.chat.completions.create({
|
|
211
|
+
model: 'gpt-4',
|
|
212
|
+
messages: [
|
|
213
|
+
{ role: 'system', content: \`Download model with HF token: \${hfToken}\` }
|
|
214
|
+
]
|
|
215
|
+
})
|
|
216
|
+
}
|
|
217
|
+
`,
|
|
218
|
+
language: 'typescript',
|
|
219
|
+
size: 3500,
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
// ========== Variable Indirection - Secrets flowing to prompts ==========
|
|
223
|
+
{
|
|
224
|
+
name: 'Secrets in Prompts - Variable Flow',
|
|
225
|
+
expectFindings: true,
|
|
226
|
+
expectedCategories: ['hardcoded_secret'],
|
|
227
|
+
description: 'Secrets assigned to variables that flow into prompts',
|
|
228
|
+
file: {
|
|
229
|
+
path: 'src/api/ai/secrets-variable-flow.ts',
|
|
230
|
+
content: `
|
|
231
|
+
import OpenAI from 'openai'
|
|
232
|
+
|
|
233
|
+
const openai = new OpenAI()
|
|
234
|
+
|
|
235
|
+
// Secret assigned to variable, then used in prompt
|
|
236
|
+
export async function variableFlowSecret() {
|
|
237
|
+
const apiKey = "sk-abcdefghijklmnopqrstuvwxyz1234"
|
|
238
|
+
const authToken = "ghp_1234567890abcdefghijklmnopqrstuvwxyz"
|
|
239
|
+
|
|
240
|
+
// These secrets flow into the prompt via template interpolation
|
|
241
|
+
const systemPrompt = \`You have access to external APIs.
|
|
242
|
+
OpenAI key: \${apiKey}
|
|
243
|
+
GitHub token: \${authToken}\`
|
|
244
|
+
|
|
245
|
+
return openai.chat.completions.create({
|
|
246
|
+
model: 'gpt-4',
|
|
247
|
+
messages: [
|
|
248
|
+
{ role: 'system', content: systemPrompt }
|
|
249
|
+
]
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Secret via concatenation
|
|
254
|
+
export async function concatFlowSecret() {
|
|
255
|
+
const secretKey = "sk_live_abcdefghijklmnopqrstuvwx"
|
|
256
|
+
|
|
257
|
+
// Secret flows via string concatenation
|
|
258
|
+
const prompt = "Process payment with key: " + secretKey
|
|
259
|
+
|
|
260
|
+
return openai.chat.completions.create({
|
|
261
|
+
model: 'gpt-4',
|
|
262
|
+
messages: [
|
|
263
|
+
{ role: 'system', content: prompt }
|
|
264
|
+
]
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Multi-hop variable flow
|
|
269
|
+
export async function multiHopSecret() {
|
|
270
|
+
const credentials = {
|
|
271
|
+
apiToken: "xoxb-123456789012-1234567890123-abcdefghijkl"
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const token = credentials.apiToken
|
|
275
|
+
|
|
276
|
+
return openai.chat.completions.create({
|
|
277
|
+
model: 'gpt-4',
|
|
278
|
+
messages: [
|
|
279
|
+
{ role: 'system', content: \`Slack token for notifications: \${token}\` }
|
|
280
|
+
]
|
|
281
|
+
})
|
|
282
|
+
}
|
|
283
|
+
`,
|
|
284
|
+
language: 'typescript',
|
|
285
|
+
size: 1500,
|
|
286
|
+
},
|
|
287
|
+
},
|
|
90
288
|
],
|
|
91
289
|
|
|
92
290
|
falseNegatives: [
|
|
@@ -174,5 +372,106 @@ export async function allowedModel(model: string, prompt: string) {
|
|
|
174
372
|
size: 1500,
|
|
175
373
|
},
|
|
176
374
|
},
|
|
375
|
+
// ========== Safe Secrets Patterns ==========
|
|
376
|
+
{
|
|
377
|
+
name: 'Secrets in Prompts - Safe Patterns',
|
|
378
|
+
expectFindings: false,
|
|
379
|
+
description: 'Safe patterns for handling secrets near LLM code that should NOT be flagged',
|
|
380
|
+
allowedInfoFindings: [
|
|
381
|
+
{
|
|
382
|
+
category: 'hardcoded_secret',
|
|
383
|
+
maxCount: 1,
|
|
384
|
+
reason: 'Info-level for test variable names or placeholders',
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
category: 'ai_pattern',
|
|
388
|
+
maxCount: 1,
|
|
389
|
+
reason: 'Info-level BYOK pattern detection for user-provided API keys (feature, not vulnerability)',
|
|
390
|
+
},
|
|
391
|
+
],
|
|
392
|
+
file: {
|
|
393
|
+
path: 'src/api/ai/safe-secrets.ts',
|
|
394
|
+
content: `
|
|
395
|
+
import OpenAI from 'openai'
|
|
396
|
+
|
|
397
|
+
const openai = new OpenAI()
|
|
398
|
+
|
|
399
|
+
// 1. Using environment variables (SAFE)
|
|
400
|
+
export async function envVarSecret() {
|
|
401
|
+
const apiKey = process.env.OPENAI_API_KEY
|
|
402
|
+
const client = new OpenAI({ apiKey })
|
|
403
|
+
|
|
404
|
+
return client.chat.completions.create({
|
|
405
|
+
model: 'gpt-4',
|
|
406
|
+
messages: [
|
|
407
|
+
{ role: 'system', content: 'You are a helpful assistant.' }
|
|
408
|
+
]
|
|
409
|
+
})
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// 2. Server-side API call without exposing key to prompt (SAFE)
|
|
413
|
+
export async function serverSideCall() {
|
|
414
|
+
// Key is used for client auth, NOT exposed to prompt
|
|
415
|
+
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY)
|
|
416
|
+
|
|
417
|
+
const result = await openai.chat.completions.create({
|
|
418
|
+
model: 'gpt-4',
|
|
419
|
+
messages: [
|
|
420
|
+
{ role: 'user', content: 'What products should I buy?' }
|
|
421
|
+
]
|
|
422
|
+
})
|
|
423
|
+
|
|
424
|
+
// Use AI response to make server-side Stripe call
|
|
425
|
+
const products = await stripe.products.list()
|
|
426
|
+
return { aiResponse: result, products }
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// 3. Placeholder/example values (SAFE)
|
|
430
|
+
export async function examplePlaceholder() {
|
|
431
|
+
// These are clearly placeholders, not real secrets
|
|
432
|
+
const EXAMPLE_API_KEY = "your-api-key-here"
|
|
433
|
+
const TEST_TOKEN = "test_token_placeholder"
|
|
434
|
+
const DEMO_KEY = "demo_sk_1234"
|
|
435
|
+
|
|
436
|
+
// Documentation example
|
|
437
|
+
console.log("Replace EXAMPLE_API_KEY with your actual key")
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// 4. Test/mock variable names (SAFE)
|
|
441
|
+
export async function testVariables() {
|
|
442
|
+
const TEST_API_KEY = "sk-test1234567890abcdefghijklmnop"
|
|
443
|
+
const MOCK_SECRET = "mock_secret_for_testing"
|
|
444
|
+
const DUMMY_TOKEN = "dummy_ghp_1234567890"
|
|
445
|
+
|
|
446
|
+
// Used in unit tests, not production
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// 5. Import.meta.env reference (SAFE)
|
|
450
|
+
export async function importMetaEnv() {
|
|
451
|
+
const key = import.meta.env.VITE_API_KEY
|
|
452
|
+
return openai.chat.completions.create({
|
|
453
|
+
model: 'gpt-4',
|
|
454
|
+
messages: [{ role: 'user', content: 'Hello' }]
|
|
455
|
+
})
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// 6. Python os.environ (SAFE)
|
|
459
|
+
// const apiKey = os.environ.get('API_KEY')
|
|
460
|
+
// const token = os.getenv('AUTH_TOKEN')
|
|
461
|
+
|
|
462
|
+
// 7. Referencing user's own key (BYOK pattern - SAFE)
|
|
463
|
+
export async function byokPattern(userApiKey: string) {
|
|
464
|
+
// User provides their own key - this is the BYOK feature
|
|
465
|
+
const client = new OpenAI({ apiKey: userApiKey })
|
|
466
|
+
return client.chat.completions.create({
|
|
467
|
+
model: 'gpt-4',
|
|
468
|
+
messages: [{ role: 'user', content: 'Hello' }]
|
|
469
|
+
})
|
|
470
|
+
}
|
|
471
|
+
`,
|
|
472
|
+
language: 'typescript',
|
|
473
|
+
size: 2200,
|
|
474
|
+
},
|
|
475
|
+
},
|
|
177
476
|
],
|
|
178
477
|
}
|