circle-ir-ai 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +105 -0
- package/LICENSE +15 -0
- package/README.md +336 -0
- package/dist/action-queue/aggregator.d.ts +40 -0
- package/dist/action-queue/aggregator.d.ts.map +1 -0
- package/dist/action-queue/aggregator.js +375 -0
- package/dist/action-queue/aggregator.js.map +1 -0
- package/dist/action-queue/index.d.ts +14 -0
- package/dist/action-queue/index.d.ts.map +1 -0
- package/dist/action-queue/index.js +17 -0
- package/dist/action-queue/index.js.map +1 -0
- package/dist/action-queue/queue.d.ts +74 -0
- package/dist/action-queue/queue.d.ts.map +1 -0
- package/dist/action-queue/queue.js +433 -0
- package/dist/action-queue/queue.js.map +1 -0
- package/dist/action-queue/types.d.ts +162 -0
- package/dist/action-queue/types.d.ts.map +1 -0
- package/dist/action-queue/types.js +44 -0
- package/dist/action-queue/types.js.map +1 -0
- package/dist/agents/enrichment-agent.d.ts +16 -0
- package/dist/agents/enrichment-agent.d.ts.map +1 -0
- package/dist/agents/enrichment-agent.js +102 -0
- package/dist/agents/enrichment-agent.js.map +1 -0
- package/dist/agents/index.d.ts +12 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +15 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/mastra/agents.d.ts +373 -0
- package/dist/agents/mastra/agents.d.ts.map +1 -0
- package/dist/agents/mastra/agents.js +347 -0
- package/dist/agents/mastra/agents.js.map +1 -0
- package/dist/agents/mastra/index.d.ts +12 -0
- package/dist/agents/mastra/index.d.ts.map +1 -0
- package/dist/agents/mastra/index.js +17 -0
- package/dist/agents/mastra/index.js.map +1 -0
- package/dist/agents/mastra/instance.d.ts +383 -0
- package/dist/agents/mastra/instance.d.ts.map +1 -0
- package/dist/agents/mastra/instance.js +37 -0
- package/dist/agents/mastra/instance.js.map +1 -0
- package/dist/agents/mastra/steps.d.ts +300 -0
- package/dist/agents/mastra/steps.d.ts.map +1 -0
- package/dist/agents/mastra/steps.js +468 -0
- package/dist/agents/mastra/steps.js.map +1 -0
- package/dist/agents/mastra/swarm.d.ts +106 -0
- package/dist/agents/mastra/swarm.d.ts.map +1 -0
- package/dist/agents/mastra/swarm.js +501 -0
- package/dist/agents/mastra/swarm.js.map +1 -0
- package/dist/agents/mastra/workflow.d.ts +81 -0
- package/dist/agents/mastra/workflow.d.ts.map +1 -0
- package/dist/agents/mastra/workflow.js +460 -0
- package/dist/agents/mastra/workflow.js.map +1 -0
- package/dist/agents/multi/agents/security.d.ts +29 -0
- package/dist/agents/multi/agents/security.d.ts.map +1 -0
- package/dist/agents/multi/agents/security.js +830 -0
- package/dist/agents/multi/agents/security.js.map +1 -0
- package/dist/agents/multi/extractor.d.ts +21 -0
- package/dist/agents/multi/extractor.d.ts.map +1 -0
- package/dist/agents/multi/extractor.js +483 -0
- package/dist/agents/multi/extractor.js.map +1 -0
- package/dist/agents/multi/index.d.ts +32 -0
- package/dist/agents/multi/index.d.ts.map +1 -0
- package/dist/agents/multi/index.js +34 -0
- package/dist/agents/multi/index.js.map +1 -0
- package/dist/agents/multi/runner.d.ts +79 -0
- package/dist/agents/multi/runner.d.ts.map +1 -0
- package/dist/agents/multi/runner.js +323 -0
- package/dist/agents/multi/runner.js.map +1 -0
- package/dist/agents/security-agent.d.ts +16 -0
- package/dist/agents/security-agent.d.ts.map +1 -0
- package/dist/agents/security-agent.js +299 -0
- package/dist/agents/security-agent.js.map +1 -0
- package/dist/agents/types.d.ts +373 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +14 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/agents/verification-agent.d.ts +23 -0
- package/dist/agents/verification-agent.d.ts.map +1 -0
- package/dist/agents/verification-agent.js +217 -0
- package/dist/agents/verification-agent.js.map +1 -0
- package/dist/agents/workflow.d.ts +30 -0
- package/dist/agents/workflow.d.ts.map +1 -0
- package/dist/agents/workflow.js +79 -0
- package/dist/agents/workflow.js.map +1 -0
- package/dist/analysis/enriched.d.ts +16 -0
- package/dist/analysis/enriched.d.ts.map +1 -0
- package/dist/analysis/enriched.js +297 -0
- package/dist/analysis/enriched.js.map +1 -0
- package/dist/analysis/llm-correlated-predicates.d.ts +80 -0
- package/dist/analysis/llm-correlated-predicates.d.ts.map +1 -0
- package/dist/analysis/llm-correlated-predicates.js +255 -0
- package/dist/analysis/llm-correlated-predicates.js.map +1 -0
- package/dist/analysis/llm-cross-file-taint.d.ts +86 -0
- package/dist/analysis/llm-cross-file-taint.d.ts.map +1 -0
- package/dist/analysis/llm-cross-file-taint.js +264 -0
- package/dist/analysis/llm-cross-file-taint.js.map +1 -0
- package/dist/analysis/pattern-discovery.d.ts +79 -0
- package/dist/analysis/pattern-discovery.d.ts.map +1 -0
- package/dist/analysis/pattern-discovery.js +447 -0
- package/dist/analysis/pattern-discovery.js.map +1 -0
- package/dist/cache/file-cache.d.ts +89 -0
- package/dist/cache/file-cache.d.ts.map +1 -0
- package/dist/cache/file-cache.js +208 -0
- package/dist/cache/file-cache.js.map +1 -0
- package/dist/cache/index.d.ts +6 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +5 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cli/args.d.ts +52 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +422 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/colors.d.ts +31 -0
- package/dist/cli/colors.d.ts.map +1 -0
- package/dist/cli/colors.js +80 -0
- package/dist/cli/colors.js.map +1 -0
- package/dist/cli/commands/analyze-skill.d.ts +33 -0
- package/dist/cli/commands/analyze-skill.d.ts.map +1 -0
- package/dist/cli/commands/analyze-skill.js +217 -0
- package/dist/cli/commands/analyze-skill.js.map +1 -0
- package/dist/cli/commands/analyze.d.ts +18 -0
- package/dist/cli/commands/analyze.d.ts.map +1 -0
- package/dist/cli/commands/analyze.js +30 -0
- package/dist/cli/commands/analyze.js.map +1 -0
- package/dist/cli/commands/benchmark-runner.d.ts +42 -0
- package/dist/cli/commands/benchmark-runner.d.ts.map +1 -0
- package/dist/cli/commands/benchmark-runner.js +18 -0
- package/dist/cli/commands/benchmark-runner.js.map +1 -0
- package/dist/cli/commands/benchmark.d.ts +11 -0
- package/dist/cli/commands/benchmark.d.ts.map +1 -0
- package/dist/cli/commands/benchmark.js +90 -0
- package/dist/cli/commands/benchmark.js.map +1 -0
- package/dist/cli/commands/dead-code.d.ts +11 -0
- package/dist/cli/commands/dead-code.d.ts.map +1 -0
- package/dist/cli/commands/dead-code.js +65 -0
- package/dist/cli/commands/dead-code.js.map +1 -0
- package/dist/cli/commands/generate-spec.d.ts +11 -0
- package/dist/cli/commands/generate-spec.d.ts.map +1 -0
- package/dist/cli/commands/generate-spec.js +67 -0
- package/dist/cli/commands/generate-spec.js.map +1 -0
- package/dist/cli/commands/health.d.ts +11 -0
- package/dist/cli/commands/health.d.ts.map +1 -0
- package/dist/cli/commands/health.js +67 -0
- package/dist/cli/commands/health.js.map +1 -0
- package/dist/cli/commands/project.d.ts +21 -0
- package/dist/cli/commands/project.d.ts.map +1 -0
- package/dist/cli/commands/project.js +92 -0
- package/dist/cli/commands/project.js.map +1 -0
- package/dist/cli/commands/scan.d.ts +11 -0
- package/dist/cli/commands/scan.d.ts.map +1 -0
- package/dist/cli/commands/scan.js +68 -0
- package/dist/cli/commands/scan.js.map +1 -0
- package/dist/cli/commands/secrets.d.ts +11 -0
- package/dist/cli/commands/secrets.d.ts.map +1 -0
- package/dist/cli/commands/secrets.js +71 -0
- package/dist/cli/commands/secrets.js.map +1 -0
- package/dist/cli/commands/swarm.d.ts +20 -0
- package/dist/cli/commands/swarm.d.ts.map +1 -0
- package/dist/cli/commands/swarm.js +174 -0
- package/dist/cli/commands/swarm.js.map +1 -0
- package/dist/cli/config.d.ts +103 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +307 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/discovery.d.ts +31 -0
- package/dist/cli/discovery.d.ts.map +1 -0
- package/dist/cli/discovery.js +212 -0
- package/dist/cli/discovery.js.map +1 -0
- package/dist/cli/formatters/index.d.ts +15 -0
- package/dist/cli/formatters/index.d.ts.map +1 -0
- package/dist/cli/formatters/index.js +51 -0
- package/dist/cli/formatters/index.js.map +1 -0
- package/dist/cli/formatters/json.d.ts +11 -0
- package/dist/cli/formatters/json.d.ts.map +1 -0
- package/dist/cli/formatters/json.js +12 -0
- package/dist/cli/formatters/json.js.map +1 -0
- package/dist/cli/formatters/project-json.d.ts +11 -0
- package/dist/cli/formatters/project-json.d.ts.map +1 -0
- package/dist/cli/formatters/project-json.js +12 -0
- package/dist/cli/formatters/project-json.js.map +1 -0
- package/dist/cli/formatters/project-sarif.d.ts +11 -0
- package/dist/cli/formatters/project-sarif.d.ts.map +1 -0
- package/dist/cli/formatters/project-sarif.js +127 -0
- package/dist/cli/formatters/project-sarif.js.map +1 -0
- package/dist/cli/formatters/project-summary.d.ts +11 -0
- package/dist/cli/formatters/project-summary.d.ts.map +1 -0
- package/dist/cli/formatters/project-summary.js +202 -0
- package/dist/cli/formatters/project-summary.js.map +1 -0
- package/dist/cli/formatters/sarif-shared.d.ts +101 -0
- package/dist/cli/formatters/sarif-shared.d.ts.map +1 -0
- package/dist/cli/formatters/sarif-shared.js +57 -0
- package/dist/cli/formatters/sarif-shared.js.map +1 -0
- package/dist/cli/formatters/sarif.d.ts +12 -0
- package/dist/cli/formatters/sarif.d.ts.map +1 -0
- package/dist/cli/formatters/sarif.js +92 -0
- package/dist/cli/formatters/sarif.js.map +1 -0
- package/dist/cli/formatters/summary.d.ts +11 -0
- package/dist/cli/formatters/summary.d.ts.map +1 -0
- package/dist/cli/formatters/summary.js +240 -0
- package/dist/cli/formatters/summary.js.map +1 -0
- package/dist/cli/formatters/two-phase-summary.d.ts +11 -0
- package/dist/cli/formatters/two-phase-summary.d.ts.map +1 -0
- package/dist/cli/formatters/two-phase-summary.js +188 -0
- package/dist/cli/formatters/two-phase-summary.js.map +1 -0
- package/dist/cli/index.d.ts +15 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +555 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/components/clustering.d.ts +60 -0
- package/dist/components/clustering.d.ts.map +1 -0
- package/dist/components/clustering.js +129 -0
- package/dist/components/clustering.js.map +1 -0
- package/dist/components/enrichment.d.ts +45 -0
- package/dist/components/enrichment.d.ts.map +1 -0
- package/dist/components/enrichment.js +193 -0
- package/dist/components/enrichment.js.map +1 -0
- package/dist/components/index.d.ts +29 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +56 -0
- package/dist/components/index.js.map +1 -0
- package/dist/dead-code/detector.d.ts +200 -0
- package/dist/dead-code/detector.d.ts.map +1 -0
- package/dist/dead-code/detector.js +1003 -0
- package/dist/dead-code/detector.js.map +1 -0
- package/dist/dead-code/index.d.ts +7 -0
- package/dist/dead-code/index.d.ts.map +1 -0
- package/dist/dead-code/index.js +7 -0
- package/dist/dead-code/index.js.map +1 -0
- package/dist/extractors/index.d.ts +15 -0
- package/dist/extractors/index.d.ts.map +1 -0
- package/dist/extractors/index.js +14 -0
- package/dist/extractors/index.js.map +1 -0
- package/dist/extractors/natural-language.d.ts +46 -0
- package/dist/extractors/natural-language.d.ts.map +1 -0
- package/dist/extractors/natural-language.js +228 -0
- package/dist/extractors/natural-language.js.map +1 -0
- package/dist/extractors/tree-sitter.d.ts +33 -0
- package/dist/extractors/tree-sitter.d.ts.map +1 -0
- package/dist/extractors/tree-sitter.js +69 -0
- package/dist/extractors/tree-sitter.js.map +1 -0
- package/dist/extractors/types.d.ts +62 -0
- package/dist/extractors/types.d.ts.map +1 -0
- package/dist/extractors/types.js +54 -0
- package/dist/extractors/types.js.map +1 -0
- package/dist/health-score/calculator.d.ts +123 -0
- package/dist/health-score/calculator.d.ts.map +1 -0
- package/dist/health-score/calculator.js +444 -0
- package/dist/health-score/calculator.js.map +1 -0
- package/dist/health-score/index.d.ts +12 -0
- package/dist/health-score/index.d.ts.map +1 -0
- package/dist/health-score/index.js +14 -0
- package/dist/health-score/index.js.map +1 -0
- package/dist/health-score/metrics.d.ts +142 -0
- package/dist/health-score/metrics.d.ts.map +1 -0
- package/dist/health-score/metrics.js +332 -0
- package/dist/health-score/metrics.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/ax-client.d.ts +477 -0
- package/dist/llm/ax-client.d.ts.map +1 -0
- package/dist/llm/ax-client.js +1641 -0
- package/dist/llm/ax-client.js.map +1 -0
- package/dist/llm/config.d.ts +58 -0
- package/dist/llm/config.d.ts.map +1 -0
- package/dist/llm/config.js +97 -0
- package/dist/llm/config.js.map +1 -0
- package/dist/llm/discovery.d.ts +123 -0
- package/dist/llm/discovery.d.ts.map +1 -0
- package/dist/llm/discovery.js +505 -0
- package/dist/llm/discovery.js.map +1 -0
- package/dist/llm/enrichment.d.ts +108 -0
- package/dist/llm/enrichment.d.ts.map +1 -0
- package/dist/llm/enrichment.js +312 -0
- package/dist/llm/enrichment.js.map +1 -0
- package/dist/llm/index.d.ts +13 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +22 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/language-context.d.ts +64 -0
- package/dist/llm/language-context.d.ts.map +1 -0
- package/dist/llm/language-context.js +492 -0
- package/dist/llm/language-context.js.map +1 -0
- package/dist/llm/pattern-verification.d.ts +39 -0
- package/dist/llm/pattern-verification.d.ts.map +1 -0
- package/dist/llm/pattern-verification.js +127 -0
- package/dist/llm/pattern-verification.js.map +1 -0
- package/dist/llm/prompt-security.d.ts +120 -0
- package/dist/llm/prompt-security.d.ts.map +1 -0
- package/dist/llm/prompt-security.js +301 -0
- package/dist/llm/prompt-security.js.map +1 -0
- package/dist/llm/prompts/index.d.ts +31 -0
- package/dist/llm/prompts/index.d.ts.map +1 -0
- package/dist/llm/prompts/index.js +92 -0
- package/dist/llm/prompts/index.js.map +1 -0
- package/dist/llm/prompts/rust.d.ts +30 -0
- package/dist/llm/prompts/rust.d.ts.map +1 -0
- package/dist/llm/prompts/rust.js +121 -0
- package/dist/llm/prompts/rust.js.map +1 -0
- package/dist/llm/schemas.d.ts +892 -0
- package/dist/llm/schemas.d.ts.map +1 -0
- package/dist/llm/schemas.js +258 -0
- package/dist/llm/schemas.js.map +1 -0
- package/dist/llm/verification.d.ts +127 -0
- package/dist/llm/verification.d.ts.map +1 -0
- package/dist/llm/verification.js +394 -0
- package/dist/llm/verification.js.map +1 -0
- package/dist/project/analyzer.d.ts +30 -0
- package/dist/project/analyzer.d.ts.map +1 -0
- package/dist/project/analyzer.js +358 -0
- package/dist/project/analyzer.js.map +1 -0
- package/dist/project/call-graph.d.ts +22 -0
- package/dist/project/call-graph.d.ts.map +1 -0
- package/dist/project/call-graph.js +246 -0
- package/dist/project/call-graph.js.map +1 -0
- package/dist/project/index.d.ts +18 -0
- package/dist/project/index.d.ts.map +1 -0
- package/dist/project/index.js +20 -0
- package/dist/project/index.js.map +1 -0
- package/dist/project/taint-paths.d.ts +22 -0
- package/dist/project/taint-paths.d.ts.map +1 -0
- package/dist/project/taint-paths.js +265 -0
- package/dist/project/taint-paths.js.map +1 -0
- package/dist/project/two-phase-analyzer.d.ts +143 -0
- package/dist/project/two-phase-analyzer.d.ts.map +1 -0
- package/dist/project/two-phase-analyzer.js +646 -0
- package/dist/project/two-phase-analyzer.js.map +1 -0
- package/dist/project/type-hierarchy.d.ts +28 -0
- package/dist/project/type-hierarchy.d.ts.map +1 -0
- package/dist/project/type-hierarchy.js +218 -0
- package/dist/project/type-hierarchy.js.map +1 -0
- package/dist/secret-scan/index.d.ts +12 -0
- package/dist/secret-scan/index.d.ts.map +1 -0
- package/dist/secret-scan/index.js +14 -0
- package/dist/secret-scan/index.js.map +1 -0
- package/dist/secret-scan/patterns.d.ts +38 -0
- package/dist/secret-scan/patterns.d.ts.map +1 -0
- package/dist/secret-scan/patterns.js +473 -0
- package/dist/secret-scan/patterns.js.map +1 -0
- package/dist/secret-scan/scanner.d.ts +162 -0
- package/dist/secret-scan/scanner.d.ts.map +1 -0
- package/dist/secret-scan/scanner.js +511 -0
- package/dist/secret-scan/scanner.js.map +1 -0
- package/dist/security-scan/index.d.ts +12 -0
- package/dist/security-scan/index.d.ts.map +1 -0
- package/dist/security-scan/index.js +15 -0
- package/dist/security-scan/index.js.map +1 -0
- package/dist/security-scan/owasp-mapping.d.ts +29 -0
- package/dist/security-scan/owasp-mapping.d.ts.map +1 -0
- package/dist/security-scan/owasp-mapping.js +246 -0
- package/dist/security-scan/owasp-mapping.js.map +1 -0
- package/dist/security-scan/scanner.d.ts +204 -0
- package/dist/security-scan/scanner.d.ts.map +1 -0
- package/dist/security-scan/scanner.js +693 -0
- package/dist/security-scan/scanner.js.map +1 -0
- package/dist/security-scan/trend-tracker.d.ts +150 -0
- package/dist/security-scan/trend-tracker.d.ts.map +1 -0
- package/dist/security-scan/trend-tracker.js +299 -0
- package/dist/security-scan/trend-tracker.js.map +1 -0
- package/dist/skills/bundle-loader.d.ts +26 -0
- package/dist/skills/bundle-loader.d.ts.map +1 -0
- package/dist/skills/bundle-loader.js +284 -0
- package/dist/skills/bundle-loader.js.map +1 -0
- package/dist/skills/capability-mismatch.d.ts +21 -0
- package/dist/skills/capability-mismatch.d.ts.map +1 -0
- package/dist/skills/capability-mismatch.js +188 -0
- package/dist/skills/capability-mismatch.js.map +1 -0
- package/dist/skills/index.d.ts +10 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +9 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/skill-analyzer.d.ts +16 -0
- package/dist/skills/skill-analyzer.d.ts.map +1 -0
- package/dist/skills/skill-analyzer.js +361 -0
- package/dist/skills/skill-analyzer.js.map +1 -0
- package/dist/skills/types.d.ts +195 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +7 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/specifica/conflict-resolver.d.ts +23 -0
- package/dist/specifica/conflict-resolver.d.ts.map +1 -0
- package/dist/specifica/conflict-resolver.js +129 -0
- package/dist/specifica/conflict-resolver.js.map +1 -0
- package/dist/specifica/evidence-aggregator.d.ts +33 -0
- package/dist/specifica/evidence-aggregator.d.ts.map +1 -0
- package/dist/specifica/evidence-aggregator.js +236 -0
- package/dist/specifica/evidence-aggregator.js.map +1 -0
- package/dist/specifica/evidence-extractor.d.ts +13 -0
- package/dist/specifica/evidence-extractor.d.ts.map +1 -0
- package/dist/specifica/evidence-extractor.js +431 -0
- package/dist/specifica/evidence-extractor.js.map +1 -0
- package/dist/specifica/feature-clustering.d.ts +19 -0
- package/dist/specifica/feature-clustering.d.ts.map +1 -0
- package/dist/specifica/feature-clustering.js +231 -0
- package/dist/specifica/feature-clustering.js.map +1 -0
- package/dist/specifica/generator.d.ts +16 -0
- package/dist/specifica/generator.d.ts.map +1 -0
- package/dist/specifica/generator.js +277 -0
- package/dist/specifica/generator.js.map +1 -0
- package/dist/specifica/index.d.ts +15 -0
- package/dist/specifica/index.d.ts.map +1 -0
- package/dist/specifica/index.js +18 -0
- package/dist/specifica/index.js.map +1 -0
- package/dist/specifica/prompts.d.ts +21 -0
- package/dist/specifica/prompts.d.ts.map +1 -0
- package/dist/specifica/prompts.js +196 -0
- package/dist/specifica/prompts.js.map +1 -0
- package/dist/specifica/spec-generator.d.ts +22 -0
- package/dist/specifica/spec-generator.d.ts.map +1 -0
- package/dist/specifica/spec-generator.js +229 -0
- package/dist/specifica/spec-generator.js.map +1 -0
- package/dist/specifica/types.d.ts +213 -0
- package/dist/specifica/types.d.ts.map +1 -0
- package/dist/specifica/types.js +7 -0
- package/dist/specifica/types.js.map +1 -0
- package/dist/utils/logger.d.ts +17 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +51 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +99 -0
|
@@ -0,0 +1,830 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Agents
|
|
3
|
+
*
|
|
4
|
+
* Specialized agents for detecting security vulnerabilities.
|
|
5
|
+
* These agents analyze the enriched IR for different vulnerability types.
|
|
6
|
+
*/
|
|
7
|
+
import { registerAgent } from '../runner.js';
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// SQL Injection Agent
|
|
10
|
+
// ============================================================================
|
|
11
|
+
export const sqlInjectionAgent = {
|
|
12
|
+
id: 'security.sql-injection',
|
|
13
|
+
name: 'SQL Injection Detector',
|
|
14
|
+
description: 'Detects SQL injection vulnerabilities by analyzing taint flows to SQL sinks',
|
|
15
|
+
category: 'security',
|
|
16
|
+
async analyze(ir, options) {
|
|
17
|
+
const findings = [];
|
|
18
|
+
const startTime = Date.now();
|
|
19
|
+
// Get SQL-related sinks from base IR
|
|
20
|
+
const sqlSinks = ir.base.taint.sinks.filter(s => s.type === 'sql_injection');
|
|
21
|
+
const sources = ir.base.taint.sources;
|
|
22
|
+
// Check for SQL patterns in strings
|
|
23
|
+
const sqlStrings = ir.strings.filter(s => s.pattern === 'sql');
|
|
24
|
+
for (const sink of sqlSinks) {
|
|
25
|
+
// Check if there's a taint path from any source
|
|
26
|
+
const hasSourceInSameMethod = sources.some(src => src.line < sink.line && findContainingMethod(src.line, ir) === findContainingMethod(sink.line, ir));
|
|
27
|
+
if (hasSourceInSameMethod) {
|
|
28
|
+
findings.push({
|
|
29
|
+
id: `sqli-${sink.line}`,
|
|
30
|
+
type: 'sql-injection',
|
|
31
|
+
message: `Potential SQL injection at line ${sink.line}. User input may flow to SQL query.`,
|
|
32
|
+
severity: 'critical',
|
|
33
|
+
confidence: 0.9,
|
|
34
|
+
cwe: 'CWE-89',
|
|
35
|
+
owasp: 'A03:2021',
|
|
36
|
+
location: {
|
|
37
|
+
file: ir.filePath,
|
|
38
|
+
line: sink.line,
|
|
39
|
+
},
|
|
40
|
+
sink: { line: sink.line, type: sink.type },
|
|
41
|
+
remediation: 'Use parameterized queries (PreparedStatement) instead of string concatenation.',
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Check for string concatenation in SQL patterns
|
|
46
|
+
for (const str of sqlStrings) {
|
|
47
|
+
if (str.context === 'argument' || str.context === 'assignment') {
|
|
48
|
+
// Check if there's a source in the same method
|
|
49
|
+
const method = str.inMethod;
|
|
50
|
+
const hasSourceInMethod = sources.some(src => findContainingMethod(src.line, ir) === method);
|
|
51
|
+
if (hasSourceInMethod && !findings.some(f => f.location.line === str.line)) {
|
|
52
|
+
findings.push({
|
|
53
|
+
id: `sqli-string-${str.line}`,
|
|
54
|
+
type: 'sql-injection',
|
|
55
|
+
message: `SQL query pattern detected at line ${str.line}. Verify parameterization.`,
|
|
56
|
+
severity: 'high',
|
|
57
|
+
confidence: 0.7,
|
|
58
|
+
cwe: 'CWE-89',
|
|
59
|
+
location: {
|
|
60
|
+
file: ir.filePath,
|
|
61
|
+
line: str.line,
|
|
62
|
+
column: str.column,
|
|
63
|
+
},
|
|
64
|
+
remediation: 'Use parameterized queries instead of string concatenation.',
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
agentId: sqlInjectionAgent.id,
|
|
71
|
+
agentName: sqlInjectionAgent.name,
|
|
72
|
+
category: 'security',
|
|
73
|
+
success: true,
|
|
74
|
+
findings,
|
|
75
|
+
processingTimeMs: Date.now() - startTime,
|
|
76
|
+
};
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// XSS Agent
|
|
81
|
+
// ============================================================================
|
|
82
|
+
export const xssAgent = {
|
|
83
|
+
id: 'security.xss',
|
|
84
|
+
name: 'XSS Detector',
|
|
85
|
+
description: 'Detects Cross-Site Scripting vulnerabilities',
|
|
86
|
+
category: 'security',
|
|
87
|
+
async analyze(ir, options) {
|
|
88
|
+
const findings = [];
|
|
89
|
+
const startTime = Date.now();
|
|
90
|
+
// Get XSS sinks from base IR
|
|
91
|
+
const xssSinks = ir.base.taint.sinks.filter(s => s.type === 'xss');
|
|
92
|
+
const sources = ir.base.taint.sources;
|
|
93
|
+
for (const sink of xssSinks) {
|
|
94
|
+
const hasSourceInSameMethod = sources.some(src => src.line < sink.line && findContainingMethod(src.line, ir) === findContainingMethod(sink.line, ir));
|
|
95
|
+
if (hasSourceInSameMethod) {
|
|
96
|
+
findings.push({
|
|
97
|
+
id: `xss-${sink.line}`,
|
|
98
|
+
type: 'xss',
|
|
99
|
+
message: `Potential XSS vulnerability at line ${sink.line}. User input may be written to response.`,
|
|
100
|
+
severity: 'high',
|
|
101
|
+
confidence: 0.85,
|
|
102
|
+
cwe: 'CWE-79',
|
|
103
|
+
owasp: 'A03:2021',
|
|
104
|
+
location: {
|
|
105
|
+
file: ir.filePath,
|
|
106
|
+
line: sink.line,
|
|
107
|
+
},
|
|
108
|
+
sink: { line: sink.line, type: sink.type },
|
|
109
|
+
remediation: 'Encode output using appropriate escaping (HTML, JavaScript, URL encoding).',
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Check for HTML patterns in strings with sources
|
|
114
|
+
const htmlStrings = ir.strings.filter(s => s.pattern === 'html');
|
|
115
|
+
for (const str of htmlStrings) {
|
|
116
|
+
const method = str.inMethod;
|
|
117
|
+
const hasSourceInMethod = sources.some(src => findContainingMethod(src.line, ir) === method);
|
|
118
|
+
if (hasSourceInMethod) {
|
|
119
|
+
findings.push({
|
|
120
|
+
id: `xss-html-${str.line}`,
|
|
121
|
+
type: 'xss',
|
|
122
|
+
message: `HTML content generation at line ${str.line}. Verify proper encoding.`,
|
|
123
|
+
severity: 'medium',
|
|
124
|
+
confidence: 0.6,
|
|
125
|
+
cwe: 'CWE-79',
|
|
126
|
+
location: {
|
|
127
|
+
file: ir.filePath,
|
|
128
|
+
line: str.line,
|
|
129
|
+
},
|
|
130
|
+
remediation: 'Use a templating engine with automatic HTML escaping.',
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
agentId: xssAgent.id,
|
|
136
|
+
agentName: xssAgent.name,
|
|
137
|
+
category: 'security',
|
|
138
|
+
success: true,
|
|
139
|
+
findings,
|
|
140
|
+
processingTimeMs: Date.now() - startTime,
|
|
141
|
+
};
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
// ============================================================================
|
|
145
|
+
// Command Injection Agent
|
|
146
|
+
// ============================================================================
|
|
147
|
+
export const commandInjectionAgent = {
|
|
148
|
+
id: 'security.command-injection',
|
|
149
|
+
name: 'Command Injection Detector',
|
|
150
|
+
description: 'Detects OS command injection vulnerabilities',
|
|
151
|
+
category: 'security',
|
|
152
|
+
async analyze(ir, options) {
|
|
153
|
+
const findings = [];
|
|
154
|
+
const startTime = Date.now();
|
|
155
|
+
// Get command injection sinks from base IR
|
|
156
|
+
const cmdSinks = ir.base.taint.sinks.filter(s => s.type === 'command_injection');
|
|
157
|
+
const sources = ir.base.taint.sources;
|
|
158
|
+
for (const sink of cmdSinks) {
|
|
159
|
+
const hasSourceInSameMethod = sources.some(src => src.line < sink.line && findContainingMethod(src.line, ir) === findContainingMethod(sink.line, ir));
|
|
160
|
+
if (hasSourceInSameMethod) {
|
|
161
|
+
findings.push({
|
|
162
|
+
id: `cmd-${sink.line}`,
|
|
163
|
+
type: 'command-injection',
|
|
164
|
+
message: `Potential command injection at line ${sink.line}. User input may flow to system command.`,
|
|
165
|
+
severity: 'critical',
|
|
166
|
+
confidence: 0.9,
|
|
167
|
+
cwe: 'CWE-78',
|
|
168
|
+
owasp: 'A03:2021',
|
|
169
|
+
location: {
|
|
170
|
+
file: ir.filePath,
|
|
171
|
+
line: sink.line,
|
|
172
|
+
},
|
|
173
|
+
sink: { line: sink.line, type: sink.type },
|
|
174
|
+
remediation: 'Avoid shell commands with user input. Use allowlists and ProcessBuilder with array arguments.',
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
agentId: commandInjectionAgent.id,
|
|
180
|
+
agentName: commandInjectionAgent.name,
|
|
181
|
+
category: 'security',
|
|
182
|
+
success: true,
|
|
183
|
+
findings,
|
|
184
|
+
processingTimeMs: Date.now() - startTime,
|
|
185
|
+
};
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
// ============================================================================
|
|
189
|
+
// Path Traversal Agent
|
|
190
|
+
// ============================================================================
|
|
191
|
+
export const pathTraversalAgent = {
|
|
192
|
+
id: 'security.path-traversal',
|
|
193
|
+
name: 'Path Traversal Detector',
|
|
194
|
+
description: 'Detects path traversal/directory traversal vulnerabilities',
|
|
195
|
+
category: 'security',
|
|
196
|
+
async analyze(ir, options) {
|
|
197
|
+
const findings = [];
|
|
198
|
+
const startTime = Date.now();
|
|
199
|
+
// Get path traversal sinks from base IR
|
|
200
|
+
const pathSinks = ir.base.taint.sinks.filter(s => s.type === 'path_traversal');
|
|
201
|
+
const sources = ir.base.taint.sources;
|
|
202
|
+
for (const sink of pathSinks) {
|
|
203
|
+
const hasSourceInSameMethod = sources.some(src => src.line < sink.line && findContainingMethod(src.line, ir) === findContainingMethod(sink.line, ir));
|
|
204
|
+
if (hasSourceInSameMethod) {
|
|
205
|
+
findings.push({
|
|
206
|
+
id: `path-${sink.line}`,
|
|
207
|
+
type: 'path-traversal',
|
|
208
|
+
message: `Potential path traversal at line ${sink.line}. User input may control file path.`,
|
|
209
|
+
severity: 'high',
|
|
210
|
+
confidence: 0.85,
|
|
211
|
+
cwe: 'CWE-22',
|
|
212
|
+
owasp: 'A01:2021',
|
|
213
|
+
location: {
|
|
214
|
+
file: ir.filePath,
|
|
215
|
+
line: sink.line,
|
|
216
|
+
},
|
|
217
|
+
sink: { line: sink.line, type: sink.type },
|
|
218
|
+
remediation: 'Validate and canonicalize paths. Use allowlists for allowed directories.',
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// Check for path patterns in strings
|
|
223
|
+
const pathStrings = ir.strings.filter(s => s.pattern === 'path');
|
|
224
|
+
for (const str of pathStrings) {
|
|
225
|
+
if (str.value.includes('..')) {
|
|
226
|
+
findings.push({
|
|
227
|
+
id: `path-pattern-${str.line}`,
|
|
228
|
+
type: 'path-traversal',
|
|
229
|
+
message: `Path pattern with ".." detected at line ${str.line}. Review for traversal issues.`,
|
|
230
|
+
severity: 'medium',
|
|
231
|
+
confidence: 0.5,
|
|
232
|
+
cwe: 'CWE-22',
|
|
233
|
+
location: {
|
|
234
|
+
file: ir.filePath,
|
|
235
|
+
line: str.line,
|
|
236
|
+
},
|
|
237
|
+
remediation: 'Avoid using ".." in path construction. Canonicalize and validate paths.',
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
agentId: pathTraversalAgent.id,
|
|
243
|
+
agentName: pathTraversalAgent.name,
|
|
244
|
+
category: 'security',
|
|
245
|
+
success: true,
|
|
246
|
+
findings,
|
|
247
|
+
processingTimeMs: Date.now() - startTime,
|
|
248
|
+
};
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
// ============================================================================
|
|
252
|
+
// Deserialization Agent
|
|
253
|
+
// ============================================================================
|
|
254
|
+
export const deserializationAgent = {
|
|
255
|
+
id: 'security.deserialization',
|
|
256
|
+
name: 'Insecure Deserialization Detector',
|
|
257
|
+
description: 'Detects insecure deserialization vulnerabilities',
|
|
258
|
+
category: 'security',
|
|
259
|
+
async analyze(ir, options) {
|
|
260
|
+
const findings = [];
|
|
261
|
+
const startTime = Date.now();
|
|
262
|
+
const deserSinks = ir.base.taint.sinks.filter(s => s.type === 'deserialization');
|
|
263
|
+
const sources = ir.base.taint.sources;
|
|
264
|
+
for (const sink of deserSinks) {
|
|
265
|
+
const hasSourceInSameMethod = sources.some(src => src.line < sink.line && findContainingMethod(src.line, ir) === findContainingMethod(sink.line, ir));
|
|
266
|
+
if (hasSourceInSameMethod) {
|
|
267
|
+
findings.push({
|
|
268
|
+
id: `deser-${sink.line}`,
|
|
269
|
+
type: 'insecure-deserialization',
|
|
270
|
+
message: `Insecure deserialization at line ${sink.line}. User input may control deserialized object.`,
|
|
271
|
+
severity: 'critical',
|
|
272
|
+
confidence: 0.9,
|
|
273
|
+
cwe: 'CWE-502',
|
|
274
|
+
owasp: 'A08:2021',
|
|
275
|
+
location: {
|
|
276
|
+
file: ir.filePath,
|
|
277
|
+
line: sink.line,
|
|
278
|
+
},
|
|
279
|
+
sink: { line: sink.line, type: sink.type },
|
|
280
|
+
remediation: 'Avoid deserializing untrusted data. Use allowlists for allowed classes or safer formats like JSON.',
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
// Check for dangerous deserialization patterns in calls
|
|
285
|
+
for (const call of ir.base.calls || []) {
|
|
286
|
+
if (/readObject|readUnshared|XMLDecoder/.test(call.method_name)) {
|
|
287
|
+
if (!findings.some(f => f.location.line === call.location.line)) {
|
|
288
|
+
findings.push({
|
|
289
|
+
id: `deser-call-${call.location.line}`,
|
|
290
|
+
type: 'insecure-deserialization',
|
|
291
|
+
message: `Potentially dangerous deserialization call: ${call.method_name} at line ${call.location.line}.`,
|
|
292
|
+
severity: 'high',
|
|
293
|
+
confidence: 0.7,
|
|
294
|
+
cwe: 'CWE-502',
|
|
295
|
+
location: {
|
|
296
|
+
file: ir.filePath,
|
|
297
|
+
line: call.location.line,
|
|
298
|
+
},
|
|
299
|
+
remediation: 'Review deserialization usage. Consider using ObjectInputFilter or safer alternatives.',
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return {
|
|
305
|
+
agentId: deserializationAgent.id,
|
|
306
|
+
agentName: deserializationAgent.name,
|
|
307
|
+
category: 'security',
|
|
308
|
+
success: true,
|
|
309
|
+
findings,
|
|
310
|
+
processingTimeMs: Date.now() - startTime,
|
|
311
|
+
};
|
|
312
|
+
},
|
|
313
|
+
};
|
|
314
|
+
// ============================================================================
|
|
315
|
+
// XXE Agent
|
|
316
|
+
// ============================================================================
|
|
317
|
+
export const xxeAgent = {
|
|
318
|
+
id: 'security.xxe',
|
|
319
|
+
name: 'XXE Detector',
|
|
320
|
+
description: 'Detects XML External Entity (XXE) vulnerabilities',
|
|
321
|
+
category: 'security',
|
|
322
|
+
async analyze(ir, options) {
|
|
323
|
+
const findings = [];
|
|
324
|
+
const startTime = Date.now();
|
|
325
|
+
const xxeSinks = ir.base.taint.sinks.filter(s => s.type === 'xxe');
|
|
326
|
+
const sources = ir.base.taint.sources;
|
|
327
|
+
for (const sink of xxeSinks) {
|
|
328
|
+
const hasSourceInSameMethod = sources.some(src => src.line < sink.line && findContainingMethod(src.line, ir) === findContainingMethod(sink.line, ir));
|
|
329
|
+
if (hasSourceInSameMethod) {
|
|
330
|
+
findings.push({
|
|
331
|
+
id: `xxe-${sink.line}`,
|
|
332
|
+
type: 'xxe',
|
|
333
|
+
message: `Potential XXE vulnerability at line ${sink.line}. XML parser may process external entities.`,
|
|
334
|
+
severity: 'high',
|
|
335
|
+
confidence: 0.85,
|
|
336
|
+
cwe: 'CWE-611',
|
|
337
|
+
owasp: 'A05:2021',
|
|
338
|
+
location: {
|
|
339
|
+
file: ir.filePath,
|
|
340
|
+
line: sink.line,
|
|
341
|
+
},
|
|
342
|
+
sink: { line: sink.line, type: sink.type },
|
|
343
|
+
remediation: 'Disable external entity processing: setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)',
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
// Check for XML parser creation without security configuration
|
|
348
|
+
for (const call of ir.base.calls || []) {
|
|
349
|
+
if (/DocumentBuilderFactory|SAXParserFactory|XMLInputFactory/.test(call.receiver || '')) {
|
|
350
|
+
if (call.method_name === 'newInstance') {
|
|
351
|
+
findings.push({
|
|
352
|
+
id: `xxe-factory-${call.location.line}`,
|
|
353
|
+
type: 'xxe',
|
|
354
|
+
message: `XML parser created at line ${call.location.line}. Verify XXE protections are enabled.`,
|
|
355
|
+
severity: 'medium',
|
|
356
|
+
confidence: 0.6,
|
|
357
|
+
cwe: 'CWE-611',
|
|
358
|
+
location: {
|
|
359
|
+
file: ir.filePath,
|
|
360
|
+
line: call.location.line,
|
|
361
|
+
},
|
|
362
|
+
remediation: 'Configure parser to disable DTDs and external entities before use.',
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return {
|
|
368
|
+
agentId: xxeAgent.id,
|
|
369
|
+
agentName: xxeAgent.name,
|
|
370
|
+
category: 'security',
|
|
371
|
+
success: true,
|
|
372
|
+
findings,
|
|
373
|
+
processingTimeMs: Date.now() - startTime,
|
|
374
|
+
};
|
|
375
|
+
},
|
|
376
|
+
};
|
|
377
|
+
// ============================================================================
|
|
378
|
+
// LDAP Injection Agent
|
|
379
|
+
// ============================================================================
|
|
380
|
+
export const ldapInjectionAgent = {
|
|
381
|
+
id: 'security.ldap-injection',
|
|
382
|
+
name: 'LDAP Injection Detector',
|
|
383
|
+
description: 'Detects LDAP injection vulnerabilities',
|
|
384
|
+
category: 'security',
|
|
385
|
+
async analyze(ir, options) {
|
|
386
|
+
const findings = [];
|
|
387
|
+
const startTime = Date.now();
|
|
388
|
+
const ldapSinks = ir.base.taint.sinks.filter(s => s.type === 'ldap_injection');
|
|
389
|
+
const sources = ir.base.taint.sources;
|
|
390
|
+
for (const sink of ldapSinks) {
|
|
391
|
+
const hasSourceInSameMethod = sources.some(src => src.line < sink.line && findContainingMethod(src.line, ir) === findContainingMethod(sink.line, ir));
|
|
392
|
+
if (hasSourceInSameMethod) {
|
|
393
|
+
findings.push({
|
|
394
|
+
id: `ldap-${sink.line}`,
|
|
395
|
+
type: 'ldap-injection',
|
|
396
|
+
message: `Potential LDAP injection at line ${sink.line}. User input may flow to LDAP query.`,
|
|
397
|
+
severity: 'high',
|
|
398
|
+
confidence: 0.85,
|
|
399
|
+
cwe: 'CWE-90',
|
|
400
|
+
owasp: 'A03:2021',
|
|
401
|
+
location: {
|
|
402
|
+
file: ir.filePath,
|
|
403
|
+
line: sink.line,
|
|
404
|
+
},
|
|
405
|
+
sink: { line: sink.line, type: sink.type },
|
|
406
|
+
remediation: 'Escape special LDAP characters or use parameterized LDAP queries.',
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return {
|
|
411
|
+
agentId: ldapInjectionAgent.id,
|
|
412
|
+
agentName: ldapInjectionAgent.name,
|
|
413
|
+
category: 'security',
|
|
414
|
+
success: true,
|
|
415
|
+
findings,
|
|
416
|
+
processingTimeMs: Date.now() - startTime,
|
|
417
|
+
};
|
|
418
|
+
},
|
|
419
|
+
};
|
|
420
|
+
// ============================================================================
|
|
421
|
+
// XPath Injection Agent
|
|
422
|
+
// ============================================================================
|
|
423
|
+
export const xpathInjectionAgent = {
|
|
424
|
+
id: 'security.xpath-injection',
|
|
425
|
+
name: 'XPath Injection Detector',
|
|
426
|
+
description: 'Detects XPath injection vulnerabilities',
|
|
427
|
+
category: 'security',
|
|
428
|
+
async analyze(ir, options) {
|
|
429
|
+
const findings = [];
|
|
430
|
+
const startTime = Date.now();
|
|
431
|
+
const xpathSinks = ir.base.taint.sinks.filter(s => s.type === 'xpath_injection');
|
|
432
|
+
const sources = ir.base.taint.sources;
|
|
433
|
+
for (const sink of xpathSinks) {
|
|
434
|
+
const hasSourceInSameMethod = sources.some(src => src.line < sink.line && findContainingMethod(src.line, ir) === findContainingMethod(sink.line, ir));
|
|
435
|
+
if (hasSourceInSameMethod) {
|
|
436
|
+
findings.push({
|
|
437
|
+
id: `xpath-${sink.line}`,
|
|
438
|
+
type: 'xpath-injection',
|
|
439
|
+
message: `Potential XPath injection at line ${sink.line}. User input may flow to XPath query.`,
|
|
440
|
+
severity: 'high',
|
|
441
|
+
confidence: 0.85,
|
|
442
|
+
cwe: 'CWE-643',
|
|
443
|
+
owasp: 'A03:2021',
|
|
444
|
+
location: {
|
|
445
|
+
file: ir.filePath,
|
|
446
|
+
line: sink.line,
|
|
447
|
+
},
|
|
448
|
+
sink: { line: sink.line, type: sink.type },
|
|
449
|
+
remediation: 'Use parameterized XPath queries or escape special characters.',
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return {
|
|
454
|
+
agentId: xpathInjectionAgent.id,
|
|
455
|
+
agentName: xpathInjectionAgent.name,
|
|
456
|
+
category: 'security',
|
|
457
|
+
success: true,
|
|
458
|
+
findings,
|
|
459
|
+
processingTimeMs: Date.now() - startTime,
|
|
460
|
+
};
|
|
461
|
+
},
|
|
462
|
+
};
|
|
463
|
+
// ============================================================================
|
|
464
|
+
// SSRF Agent
|
|
465
|
+
// ============================================================================
|
|
466
|
+
export const ssrfAgent = {
|
|
467
|
+
id: 'security.ssrf',
|
|
468
|
+
name: 'SSRF Detector',
|
|
469
|
+
description: 'Detects Server-Side Request Forgery vulnerabilities',
|
|
470
|
+
category: 'security',
|
|
471
|
+
async analyze(ir, options) {
|
|
472
|
+
const findings = [];
|
|
473
|
+
const startTime = Date.now();
|
|
474
|
+
const ssrfSinks = ir.base.taint.sinks.filter(s => s.type === 'ssrf');
|
|
475
|
+
const sources = ir.base.taint.sources;
|
|
476
|
+
for (const sink of ssrfSinks) {
|
|
477
|
+
const hasSourceInSameMethod = sources.some(src => src.line < sink.line && findContainingMethod(src.line, ir) === findContainingMethod(sink.line, ir));
|
|
478
|
+
if (hasSourceInSameMethod) {
|
|
479
|
+
findings.push({
|
|
480
|
+
id: `ssrf-${sink.line}`,
|
|
481
|
+
type: 'ssrf',
|
|
482
|
+
message: `Potential SSRF at line ${sink.line}. User input may control outbound request URL.`,
|
|
483
|
+
severity: 'high',
|
|
484
|
+
confidence: 0.85,
|
|
485
|
+
cwe: 'CWE-918',
|
|
486
|
+
owasp: 'A10:2021',
|
|
487
|
+
location: {
|
|
488
|
+
file: ir.filePath,
|
|
489
|
+
line: sink.line,
|
|
490
|
+
},
|
|
491
|
+
sink: { line: sink.line, type: sink.type },
|
|
492
|
+
remediation: 'Validate and allowlist destination URLs. Block internal/private IP ranges.',
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
// Check for URL patterns in strings with sources
|
|
497
|
+
const urlStrings = ir.strings.filter(s => s.pattern === 'url');
|
|
498
|
+
for (const str of urlStrings) {
|
|
499
|
+
const method = str.inMethod;
|
|
500
|
+
const hasSourceInMethod = sources.some(src => findContainingMethod(src.line, ir) === method);
|
|
501
|
+
if (hasSourceInMethod && str.context === 'argument') {
|
|
502
|
+
findings.push({
|
|
503
|
+
id: `ssrf-url-${str.line}`,
|
|
504
|
+
type: 'ssrf',
|
|
505
|
+
message: `URL construction at line ${str.line} in method with user input. Verify SSRF protections.`,
|
|
506
|
+
severity: 'medium',
|
|
507
|
+
confidence: 0.6,
|
|
508
|
+
cwe: 'CWE-918',
|
|
509
|
+
location: {
|
|
510
|
+
file: ir.filePath,
|
|
511
|
+
line: str.line,
|
|
512
|
+
},
|
|
513
|
+
remediation: 'Validate URLs against an allowlist of permitted hosts.',
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return {
|
|
518
|
+
agentId: ssrfAgent.id,
|
|
519
|
+
agentName: ssrfAgent.name,
|
|
520
|
+
category: 'security',
|
|
521
|
+
success: true,
|
|
522
|
+
findings,
|
|
523
|
+
processingTimeMs: Date.now() - startTime,
|
|
524
|
+
};
|
|
525
|
+
},
|
|
526
|
+
};
|
|
527
|
+
// ============================================================================
|
|
528
|
+
// Code Injection Agent
|
|
529
|
+
// ============================================================================
|
|
530
|
+
export const codeInjectionAgent = {
|
|
531
|
+
id: 'security.code-injection',
|
|
532
|
+
name: 'Code Injection Detector',
|
|
533
|
+
description: 'Detects code injection and expression language injection vulnerabilities',
|
|
534
|
+
category: 'security',
|
|
535
|
+
async analyze(ir, options) {
|
|
536
|
+
const findings = [];
|
|
537
|
+
const startTime = Date.now();
|
|
538
|
+
const codeSinks = ir.base.taint.sinks.filter(s => s.type === 'code_injection');
|
|
539
|
+
const sources = ir.base.taint.sources;
|
|
540
|
+
for (const sink of codeSinks) {
|
|
541
|
+
const hasSourceInSameMethod = sources.some(src => src.line < sink.line && findContainingMethod(src.line, ir) === findContainingMethod(sink.line, ir));
|
|
542
|
+
if (hasSourceInSameMethod) {
|
|
543
|
+
findings.push({
|
|
544
|
+
id: `code-${sink.line}`,
|
|
545
|
+
type: 'code-injection',
|
|
546
|
+
message: `Potential code injection at line ${sink.line}. User input may be executed as code.`,
|
|
547
|
+
severity: 'critical',
|
|
548
|
+
confidence: 0.9,
|
|
549
|
+
cwe: 'CWE-94',
|
|
550
|
+
owasp: 'A03:2021',
|
|
551
|
+
location: {
|
|
552
|
+
file: ir.filePath,
|
|
553
|
+
line: sink.line,
|
|
554
|
+
},
|
|
555
|
+
sink: { line: sink.line, type: sink.type },
|
|
556
|
+
remediation: 'Avoid dynamic code execution with user input. Use sandboxing if necessary.',
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
// Check for dangerous method calls
|
|
561
|
+
for (const call of ir.base.calls || []) {
|
|
562
|
+
if (/eval|ScriptEngine\.eval|GroovyShell\.evaluate|SpEL/.test(call.method_name)) {
|
|
563
|
+
findings.push({
|
|
564
|
+
id: `code-eval-${call.location.line}`,
|
|
565
|
+
type: 'code-injection',
|
|
566
|
+
message: `Dynamic code execution at line ${call.location.line}: ${call.method_name}`,
|
|
567
|
+
severity: 'high',
|
|
568
|
+
confidence: 0.8,
|
|
569
|
+
cwe: 'CWE-94',
|
|
570
|
+
location: {
|
|
571
|
+
file: ir.filePath,
|
|
572
|
+
line: call.location.line,
|
|
573
|
+
},
|
|
574
|
+
remediation: 'Review dynamic code execution. Ensure user input cannot reach this call.',
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
return {
|
|
579
|
+
agentId: codeInjectionAgent.id,
|
|
580
|
+
agentName: codeInjectionAgent.name,
|
|
581
|
+
category: 'security',
|
|
582
|
+
success: true,
|
|
583
|
+
findings,
|
|
584
|
+
processingTimeMs: Date.now() - startTime,
|
|
585
|
+
};
|
|
586
|
+
},
|
|
587
|
+
};
|
|
588
|
+
// ============================================================================
|
|
589
|
+
// Hardcoded Secrets Agent
|
|
590
|
+
// ============================================================================
|
|
591
|
+
export const hardcodedSecretsAgent = {
|
|
592
|
+
id: 'security.hardcoded-secrets',
|
|
593
|
+
name: 'Hardcoded Secrets Detector',
|
|
594
|
+
description: 'Detects hardcoded passwords, API keys, and other secrets',
|
|
595
|
+
category: 'security',
|
|
596
|
+
async analyze(ir, options) {
|
|
597
|
+
const findings = [];
|
|
598
|
+
const startTime = Date.now();
|
|
599
|
+
// Patterns for detecting secrets
|
|
600
|
+
const secretPatterns = [
|
|
601
|
+
{ pattern: /password\s*=\s*["'][^"']+["']/i, type: 'hardcoded-password', severity: 'high' },
|
|
602
|
+
{ pattern: /api[_-]?key\s*=\s*["'][^"']+["']/i, type: 'hardcoded-api-key', severity: 'high' },
|
|
603
|
+
{ pattern: /secret\s*=\s*["'][^"']+["']/i, type: 'hardcoded-secret', severity: 'high' },
|
|
604
|
+
{ pattern: /token\s*=\s*["'][A-Za-z0-9_\-]{20,}["']/i, type: 'hardcoded-token', severity: 'high' },
|
|
605
|
+
{ pattern: /private[_-]?key/i, type: 'hardcoded-private-key', severity: 'critical' },
|
|
606
|
+
{ pattern: /-----BEGIN (RSA |EC |DSA )?PRIVATE KEY-----/, type: 'embedded-private-key', severity: 'critical' },
|
|
607
|
+
{ pattern: /aws[_-]?(access[_-]?key|secret)/i, type: 'aws-credentials', severity: 'critical' },
|
|
608
|
+
];
|
|
609
|
+
// Check strings for secret patterns
|
|
610
|
+
for (const str of ir.strings) {
|
|
611
|
+
for (const { pattern, type, severity } of secretPatterns) {
|
|
612
|
+
if (pattern.test(str.raw) || pattern.test(str.value)) {
|
|
613
|
+
findings.push({
|
|
614
|
+
id: `secret-${type}-${str.line}`,
|
|
615
|
+
type,
|
|
616
|
+
message: `Potential ${type.replace(/-/g, ' ')} detected at line ${str.line}.`,
|
|
617
|
+
severity,
|
|
618
|
+
confidence: 0.8,
|
|
619
|
+
cwe: 'CWE-798',
|
|
620
|
+
owasp: 'A07:2021',
|
|
621
|
+
location: {
|
|
622
|
+
file: ir.filePath,
|
|
623
|
+
line: str.line,
|
|
624
|
+
column: str.column,
|
|
625
|
+
},
|
|
626
|
+
remediation: 'Move secrets to environment variables or a secrets manager.',
|
|
627
|
+
});
|
|
628
|
+
break; // Only one finding per string
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
// Note: Field-level checks skipped - FieldInfo doesn't include line numbers.
|
|
633
|
+
// The string literal checks above catch most hardcoded secrets.
|
|
634
|
+
return {
|
|
635
|
+
agentId: hardcodedSecretsAgent.id,
|
|
636
|
+
agentName: hardcodedSecretsAgent.name,
|
|
637
|
+
category: 'security',
|
|
638
|
+
success: true,
|
|
639
|
+
findings,
|
|
640
|
+
processingTimeMs: Date.now() - startTime,
|
|
641
|
+
};
|
|
642
|
+
},
|
|
643
|
+
};
|
|
644
|
+
// ============================================================================
|
|
645
|
+
// Insecure Crypto Agent
|
|
646
|
+
// ============================================================================
|
|
647
|
+
export const insecureCryptoAgent = {
|
|
648
|
+
id: 'security.insecure-crypto',
|
|
649
|
+
name: 'Insecure Cryptography Detector',
|
|
650
|
+
description: 'Detects use of weak or broken cryptographic algorithms',
|
|
651
|
+
category: 'security',
|
|
652
|
+
async analyze(ir, options) {
|
|
653
|
+
const findings = [];
|
|
654
|
+
const startTime = Date.now();
|
|
655
|
+
// Weak algorithms to detect
|
|
656
|
+
const weakAlgorithms = [
|
|
657
|
+
{ pattern: /MD5|md5/, name: 'MD5', cwe: 'CWE-328' },
|
|
658
|
+
{ pattern: /SHA-?1(?![0-9])|sha1/i, name: 'SHA-1', cwe: 'CWE-328' },
|
|
659
|
+
{ pattern: /DES(?!ede)|des(?!ede)/i, name: 'DES', cwe: 'CWE-327' },
|
|
660
|
+
{ pattern: /RC4|rc4|ARCFOUR/i, name: 'RC4', cwe: 'CWE-327' },
|
|
661
|
+
{ pattern: /Blowfish/i, name: 'Blowfish', cwe: 'CWE-327' },
|
|
662
|
+
{ pattern: /ECB/, name: 'ECB mode', cwe: 'CWE-327' },
|
|
663
|
+
];
|
|
664
|
+
// Check strings for weak algorithm references
|
|
665
|
+
for (const str of ir.strings) {
|
|
666
|
+
for (const { pattern, name, cwe } of weakAlgorithms) {
|
|
667
|
+
if (pattern.test(str.value)) {
|
|
668
|
+
findings.push({
|
|
669
|
+
id: `crypto-weak-${str.line}`,
|
|
670
|
+
type: 'weak-cryptography',
|
|
671
|
+
message: `Weak cryptographic algorithm "${name}" used at line ${str.line}.`,
|
|
672
|
+
severity: 'medium',
|
|
673
|
+
confidence: 0.85,
|
|
674
|
+
cwe,
|
|
675
|
+
owasp: 'A02:2021',
|
|
676
|
+
location: {
|
|
677
|
+
file: ir.filePath,
|
|
678
|
+
line: str.line,
|
|
679
|
+
},
|
|
680
|
+
remediation: `Replace ${name} with a stronger algorithm (e.g., SHA-256, AES-GCM).`,
|
|
681
|
+
});
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
// Check for insecure random
|
|
687
|
+
for (const call of ir.base.calls || []) {
|
|
688
|
+
if (call.receiver === 'Random' || call.method_name === 'Random') {
|
|
689
|
+
findings.push({
|
|
690
|
+
id: `crypto-random-${call.location.line}`,
|
|
691
|
+
type: 'insecure-random',
|
|
692
|
+
message: `java.util.Random used at line ${call.location.line}. Not cryptographically secure.`,
|
|
693
|
+
severity: 'medium',
|
|
694
|
+
confidence: 0.7,
|
|
695
|
+
cwe: 'CWE-330',
|
|
696
|
+
location: {
|
|
697
|
+
file: ir.filePath,
|
|
698
|
+
line: call.location.line,
|
|
699
|
+
},
|
|
700
|
+
remediation: 'Use SecureRandom for security-sensitive randomness.',
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
return {
|
|
705
|
+
agentId: insecureCryptoAgent.id,
|
|
706
|
+
agentName: insecureCryptoAgent.name,
|
|
707
|
+
category: 'security',
|
|
708
|
+
success: true,
|
|
709
|
+
findings,
|
|
710
|
+
processingTimeMs: Date.now() - startTime,
|
|
711
|
+
};
|
|
712
|
+
},
|
|
713
|
+
};
|
|
714
|
+
// ============================================================================
|
|
715
|
+
// Endpoint Security Agent
|
|
716
|
+
// ============================================================================
|
|
717
|
+
export const endpointSecurityAgent = {
|
|
718
|
+
id: 'security.endpoint',
|
|
719
|
+
name: 'Endpoint Security Analyzer',
|
|
720
|
+
description: 'Analyzes API endpoints for security issues',
|
|
721
|
+
category: 'security',
|
|
722
|
+
async analyze(ir, options) {
|
|
723
|
+
const findings = [];
|
|
724
|
+
const startTime = Date.now();
|
|
725
|
+
for (const endpoint of ir.endpoints) {
|
|
726
|
+
// Check for endpoints without authentication annotations
|
|
727
|
+
const handlerType = ir.base.types.find(t => t.name === endpoint.handlerClass);
|
|
728
|
+
if (handlerType) {
|
|
729
|
+
const method = handlerType.methods?.find(m => m.name === endpoint.handlerMethod);
|
|
730
|
+
const annotations = [...(handlerType.annotations || []), ...(method?.annotations || [])];
|
|
731
|
+
const hasAuthAnnotation = annotations.some(a => /PreAuthorize|Secured|RolesAllowed|RequiresAuthentication/.test(a));
|
|
732
|
+
if (!hasAuthAnnotation) {
|
|
733
|
+
findings.push({
|
|
734
|
+
id: `endpoint-noauth-${endpoint.line}`,
|
|
735
|
+
type: 'missing-authentication',
|
|
736
|
+
message: `Endpoint ${endpoint.method} ${endpoint.path} may lack authentication.`,
|
|
737
|
+
severity: 'medium',
|
|
738
|
+
confidence: 0.7,
|
|
739
|
+
cwe: 'CWE-306',
|
|
740
|
+
owasp: 'A07:2021',
|
|
741
|
+
location: {
|
|
742
|
+
file: ir.filePath,
|
|
743
|
+
line: endpoint.line,
|
|
744
|
+
},
|
|
745
|
+
metadata: {
|
|
746
|
+
endpoint: `${endpoint.method} ${endpoint.path}`,
|
|
747
|
+
handler: `${endpoint.handlerClass}.${endpoint.handlerMethod}`,
|
|
748
|
+
},
|
|
749
|
+
remediation: 'Add authentication annotation like @PreAuthorize or @Secured.',
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
// Check for endpoints accepting arbitrary input
|
|
754
|
+
const hasUnvalidatedInput = endpoint.params.some(p => !p.type.includes('Valid') && (p.type === 'String' || p.type === 'Object'));
|
|
755
|
+
if (hasUnvalidatedInput) {
|
|
756
|
+
findings.push({
|
|
757
|
+
id: `endpoint-validation-${endpoint.line}`,
|
|
758
|
+
type: 'missing-validation',
|
|
759
|
+
message: `Endpoint ${endpoint.method} ${endpoint.path} has unvalidated String/Object parameters.`,
|
|
760
|
+
severity: 'low',
|
|
761
|
+
confidence: 0.6,
|
|
762
|
+
cwe: 'CWE-20',
|
|
763
|
+
location: {
|
|
764
|
+
file: ir.filePath,
|
|
765
|
+
line: endpoint.line,
|
|
766
|
+
},
|
|
767
|
+
metadata: {
|
|
768
|
+
endpoint: `${endpoint.method} ${endpoint.path}`,
|
|
769
|
+
params: endpoint.params.map(p => p.name),
|
|
770
|
+
},
|
|
771
|
+
remediation: 'Add @Valid annotation and define validation constraints on DTOs.',
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
return {
|
|
776
|
+
agentId: endpointSecurityAgent.id,
|
|
777
|
+
agentName: endpointSecurityAgent.name,
|
|
778
|
+
category: 'security',
|
|
779
|
+
success: true,
|
|
780
|
+
findings,
|
|
781
|
+
processingTimeMs: Date.now() - startTime,
|
|
782
|
+
};
|
|
783
|
+
},
|
|
784
|
+
};
|
|
785
|
+
// ============================================================================
|
|
786
|
+
// Helper Functions
|
|
787
|
+
// ============================================================================
|
|
788
|
+
/**
|
|
789
|
+
* Find the method containing a given line.
|
|
790
|
+
*/
|
|
791
|
+
function findContainingMethod(lineNum, ir) {
|
|
792
|
+
for (const type of ir.base.types) {
|
|
793
|
+
for (const method of type.methods || []) {
|
|
794
|
+
if (lineNum >= method.start_line && lineNum <= method.end_line) {
|
|
795
|
+
return `${type.name}.${method.name}`;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
return undefined;
|
|
800
|
+
}
|
|
801
|
+
// ============================================================================
|
|
802
|
+
// Registration
|
|
803
|
+
// ============================================================================
|
|
804
|
+
/**
|
|
805
|
+
* All security agents.
|
|
806
|
+
*/
|
|
807
|
+
export const securityAgents = [
|
|
808
|
+
sqlInjectionAgent,
|
|
809
|
+
xssAgent,
|
|
810
|
+
commandInjectionAgent,
|
|
811
|
+
pathTraversalAgent,
|
|
812
|
+
deserializationAgent,
|
|
813
|
+
xxeAgent,
|
|
814
|
+
ldapInjectionAgent,
|
|
815
|
+
xpathInjectionAgent,
|
|
816
|
+
ssrfAgent,
|
|
817
|
+
codeInjectionAgent,
|
|
818
|
+
hardcodedSecretsAgent,
|
|
819
|
+
insecureCryptoAgent,
|
|
820
|
+
endpointSecurityAgent,
|
|
821
|
+
];
|
|
822
|
+
/**
|
|
823
|
+
* Register all security agents with the runner.
|
|
824
|
+
*/
|
|
825
|
+
export function registerSecurityAgents() {
|
|
826
|
+
for (const agent of securityAgents) {
|
|
827
|
+
registerAgent(agent);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
//# sourceMappingURL=security.js.map
|