aiptx 2.0.7__py3-none-any.whl

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.
Files changed (187) hide show
  1. aipt_v2/__init__.py +110 -0
  2. aipt_v2/__main__.py +24 -0
  3. aipt_v2/agents/AIPTxAgent/__init__.py +10 -0
  4. aipt_v2/agents/AIPTxAgent/aiptx_agent.py +211 -0
  5. aipt_v2/agents/__init__.py +46 -0
  6. aipt_v2/agents/base.py +520 -0
  7. aipt_v2/agents/exploit_agent.py +688 -0
  8. aipt_v2/agents/ptt.py +406 -0
  9. aipt_v2/agents/state.py +168 -0
  10. aipt_v2/app.py +957 -0
  11. aipt_v2/browser/__init__.py +31 -0
  12. aipt_v2/browser/automation.py +458 -0
  13. aipt_v2/browser/crawler.py +453 -0
  14. aipt_v2/cli.py +2933 -0
  15. aipt_v2/compliance/__init__.py +71 -0
  16. aipt_v2/compliance/compliance_report.py +449 -0
  17. aipt_v2/compliance/framework_mapper.py +424 -0
  18. aipt_v2/compliance/nist_mapping.py +345 -0
  19. aipt_v2/compliance/owasp_mapping.py +330 -0
  20. aipt_v2/compliance/pci_mapping.py +297 -0
  21. aipt_v2/config.py +341 -0
  22. aipt_v2/core/__init__.py +43 -0
  23. aipt_v2/core/agent.py +630 -0
  24. aipt_v2/core/llm.py +395 -0
  25. aipt_v2/core/memory.py +305 -0
  26. aipt_v2/core/ptt.py +329 -0
  27. aipt_v2/database/__init__.py +14 -0
  28. aipt_v2/database/models.py +232 -0
  29. aipt_v2/database/repository.py +384 -0
  30. aipt_v2/docker/__init__.py +23 -0
  31. aipt_v2/docker/builder.py +260 -0
  32. aipt_v2/docker/manager.py +222 -0
  33. aipt_v2/docker/sandbox.py +371 -0
  34. aipt_v2/evasion/__init__.py +58 -0
  35. aipt_v2/evasion/request_obfuscator.py +272 -0
  36. aipt_v2/evasion/tls_fingerprint.py +285 -0
  37. aipt_v2/evasion/ua_rotator.py +301 -0
  38. aipt_v2/evasion/waf_bypass.py +439 -0
  39. aipt_v2/execution/__init__.py +23 -0
  40. aipt_v2/execution/executor.py +302 -0
  41. aipt_v2/execution/parser.py +544 -0
  42. aipt_v2/execution/terminal.py +337 -0
  43. aipt_v2/health.py +437 -0
  44. aipt_v2/intelligence/__init__.py +194 -0
  45. aipt_v2/intelligence/adaptation.py +474 -0
  46. aipt_v2/intelligence/auth.py +520 -0
  47. aipt_v2/intelligence/chaining.py +775 -0
  48. aipt_v2/intelligence/correlation.py +536 -0
  49. aipt_v2/intelligence/cve_aipt.py +334 -0
  50. aipt_v2/intelligence/cve_info.py +1111 -0
  51. aipt_v2/intelligence/knowledge_graph.py +590 -0
  52. aipt_v2/intelligence/learning.py +626 -0
  53. aipt_v2/intelligence/llm_analyzer.py +502 -0
  54. aipt_v2/intelligence/llm_tool_selector.py +518 -0
  55. aipt_v2/intelligence/payload_generator.py +562 -0
  56. aipt_v2/intelligence/rag.py +239 -0
  57. aipt_v2/intelligence/scope.py +442 -0
  58. aipt_v2/intelligence/searchers/__init__.py +5 -0
  59. aipt_v2/intelligence/searchers/exploitdb_searcher.py +523 -0
  60. aipt_v2/intelligence/searchers/github_searcher.py +467 -0
  61. aipt_v2/intelligence/searchers/google_searcher.py +281 -0
  62. aipt_v2/intelligence/tools.json +443 -0
  63. aipt_v2/intelligence/triage.py +670 -0
  64. aipt_v2/interactive_shell.py +559 -0
  65. aipt_v2/interface/__init__.py +5 -0
  66. aipt_v2/interface/cli.py +230 -0
  67. aipt_v2/interface/main.py +501 -0
  68. aipt_v2/interface/tui.py +1276 -0
  69. aipt_v2/interface/utils.py +583 -0
  70. aipt_v2/llm/__init__.py +39 -0
  71. aipt_v2/llm/config.py +26 -0
  72. aipt_v2/llm/llm.py +514 -0
  73. aipt_v2/llm/memory.py +214 -0
  74. aipt_v2/llm/request_queue.py +89 -0
  75. aipt_v2/llm/utils.py +89 -0
  76. aipt_v2/local_tool_installer.py +1467 -0
  77. aipt_v2/models/__init__.py +15 -0
  78. aipt_v2/models/findings.py +295 -0
  79. aipt_v2/models/phase_result.py +224 -0
  80. aipt_v2/models/scan_config.py +207 -0
  81. aipt_v2/monitoring/grafana/dashboards/aipt-dashboard.json +355 -0
  82. aipt_v2/monitoring/grafana/dashboards/default.yml +17 -0
  83. aipt_v2/monitoring/grafana/datasources/prometheus.yml +17 -0
  84. aipt_v2/monitoring/prometheus.yml +60 -0
  85. aipt_v2/orchestration/__init__.py +52 -0
  86. aipt_v2/orchestration/pipeline.py +398 -0
  87. aipt_v2/orchestration/progress.py +300 -0
  88. aipt_v2/orchestration/scheduler.py +296 -0
  89. aipt_v2/orchestrator.py +2427 -0
  90. aipt_v2/payloads/__init__.py +27 -0
  91. aipt_v2/payloads/cmdi.py +150 -0
  92. aipt_v2/payloads/sqli.py +263 -0
  93. aipt_v2/payloads/ssrf.py +204 -0
  94. aipt_v2/payloads/templates.py +222 -0
  95. aipt_v2/payloads/traversal.py +166 -0
  96. aipt_v2/payloads/xss.py +204 -0
  97. aipt_v2/prompts/__init__.py +60 -0
  98. aipt_v2/proxy/__init__.py +29 -0
  99. aipt_v2/proxy/history.py +352 -0
  100. aipt_v2/proxy/interceptor.py +452 -0
  101. aipt_v2/recon/__init__.py +44 -0
  102. aipt_v2/recon/dns.py +241 -0
  103. aipt_v2/recon/osint.py +367 -0
  104. aipt_v2/recon/subdomain.py +372 -0
  105. aipt_v2/recon/tech_detect.py +311 -0
  106. aipt_v2/reports/__init__.py +17 -0
  107. aipt_v2/reports/generator.py +313 -0
  108. aipt_v2/reports/html_report.py +378 -0
  109. aipt_v2/runtime/__init__.py +53 -0
  110. aipt_v2/runtime/base.py +30 -0
  111. aipt_v2/runtime/docker.py +401 -0
  112. aipt_v2/runtime/local.py +346 -0
  113. aipt_v2/runtime/tool_server.py +205 -0
  114. aipt_v2/runtime/vps.py +830 -0
  115. aipt_v2/scanners/__init__.py +28 -0
  116. aipt_v2/scanners/base.py +273 -0
  117. aipt_v2/scanners/nikto.py +244 -0
  118. aipt_v2/scanners/nmap.py +402 -0
  119. aipt_v2/scanners/nuclei.py +273 -0
  120. aipt_v2/scanners/web.py +454 -0
  121. aipt_v2/scripts/security_audit.py +366 -0
  122. aipt_v2/setup_wizard.py +941 -0
  123. aipt_v2/skills/__init__.py +80 -0
  124. aipt_v2/skills/agents/__init__.py +14 -0
  125. aipt_v2/skills/agents/api_tester.py +706 -0
  126. aipt_v2/skills/agents/base.py +477 -0
  127. aipt_v2/skills/agents/code_review.py +459 -0
  128. aipt_v2/skills/agents/security_agent.py +336 -0
  129. aipt_v2/skills/agents/web_pentest.py +818 -0
  130. aipt_v2/skills/prompts/__init__.py +647 -0
  131. aipt_v2/system_detector.py +539 -0
  132. aipt_v2/telemetry/__init__.py +7 -0
  133. aipt_v2/telemetry/tracer.py +347 -0
  134. aipt_v2/terminal/__init__.py +28 -0
  135. aipt_v2/terminal/executor.py +400 -0
  136. aipt_v2/terminal/sandbox.py +350 -0
  137. aipt_v2/tools/__init__.py +44 -0
  138. aipt_v2/tools/active_directory/__init__.py +78 -0
  139. aipt_v2/tools/active_directory/ad_config.py +238 -0
  140. aipt_v2/tools/active_directory/bloodhound_wrapper.py +447 -0
  141. aipt_v2/tools/active_directory/kerberos_attacks.py +430 -0
  142. aipt_v2/tools/active_directory/ldap_enum.py +533 -0
  143. aipt_v2/tools/active_directory/smb_attacks.py +505 -0
  144. aipt_v2/tools/agents_graph/__init__.py +19 -0
  145. aipt_v2/tools/agents_graph/agents_graph_actions.py +69 -0
  146. aipt_v2/tools/api_security/__init__.py +76 -0
  147. aipt_v2/tools/api_security/api_discovery.py +608 -0
  148. aipt_v2/tools/api_security/graphql_scanner.py +622 -0
  149. aipt_v2/tools/api_security/jwt_analyzer.py +577 -0
  150. aipt_v2/tools/api_security/openapi_fuzzer.py +761 -0
  151. aipt_v2/tools/browser/__init__.py +5 -0
  152. aipt_v2/tools/browser/browser_actions.py +238 -0
  153. aipt_v2/tools/browser/browser_instance.py +535 -0
  154. aipt_v2/tools/browser/tab_manager.py +344 -0
  155. aipt_v2/tools/cloud/__init__.py +70 -0
  156. aipt_v2/tools/cloud/cloud_config.py +273 -0
  157. aipt_v2/tools/cloud/cloud_scanner.py +639 -0
  158. aipt_v2/tools/cloud/prowler_tool.py +571 -0
  159. aipt_v2/tools/cloud/scoutsuite_tool.py +359 -0
  160. aipt_v2/tools/executor.py +307 -0
  161. aipt_v2/tools/parser.py +408 -0
  162. aipt_v2/tools/proxy/__init__.py +5 -0
  163. aipt_v2/tools/proxy/proxy_actions.py +103 -0
  164. aipt_v2/tools/proxy/proxy_manager.py +789 -0
  165. aipt_v2/tools/registry.py +196 -0
  166. aipt_v2/tools/scanners/__init__.py +343 -0
  167. aipt_v2/tools/scanners/acunetix_tool.py +712 -0
  168. aipt_v2/tools/scanners/burp_tool.py +631 -0
  169. aipt_v2/tools/scanners/config.py +156 -0
  170. aipt_v2/tools/scanners/nessus_tool.py +588 -0
  171. aipt_v2/tools/scanners/zap_tool.py +612 -0
  172. aipt_v2/tools/terminal/__init__.py +5 -0
  173. aipt_v2/tools/terminal/terminal_actions.py +37 -0
  174. aipt_v2/tools/terminal/terminal_manager.py +153 -0
  175. aipt_v2/tools/terminal/terminal_session.py +449 -0
  176. aipt_v2/tools/tool_processing.py +108 -0
  177. aipt_v2/utils/__init__.py +17 -0
  178. aipt_v2/utils/logging.py +202 -0
  179. aipt_v2/utils/model_manager.py +187 -0
  180. aipt_v2/utils/searchers/__init__.py +269 -0
  181. aipt_v2/verify_install.py +793 -0
  182. aiptx-2.0.7.dist-info/METADATA +345 -0
  183. aiptx-2.0.7.dist-info/RECORD +187 -0
  184. aiptx-2.0.7.dist-info/WHEEL +5 -0
  185. aiptx-2.0.7.dist-info/entry_points.txt +7 -0
  186. aiptx-2.0.7.dist-info/licenses/LICENSE +21 -0
  187. aiptx-2.0.7.dist-info/top_level.txt +1 -0
@@ -0,0 +1,502 @@
1
+ """
2
+ AIPT LLM-Powered Vulnerability Analyzer
3
+
4
+ Uses LLM intelligence to perform deep analysis of findings:
5
+ - Discover novel attack chains beyond predefined rules
6
+ - Assess real-world exploitability with context
7
+ - Generate attack narratives for reports
8
+ - Identify implicit vulnerabilities from patterns
9
+
10
+ This enhances the rule-based chaining with intelligent reasoning.
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ import logging
16
+ import os
17
+ from dataclasses import dataclass, field
18
+ from datetime import datetime
19
+ from typing import Any, Optional
20
+
21
+ from aipt_v2.models.findings import Finding, Severity, VulnerabilityType
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ ANALYSIS_PROMPT = """You are an elite penetration tester analyzing vulnerability findings.
27
+
28
+ ## Findings to Analyze
29
+ ```json
30
+ {findings_json}
31
+ ```
32
+
33
+ ## Target Context
34
+ - **Target**: {target}
35
+ - **Technology Stack**: {tech_stack}
36
+ - **Business Type**: {business_context}
37
+
38
+ ## Your Analysis Tasks
39
+
40
+ ### 1. Attack Chain Discovery
41
+ Identify which vulnerabilities can be CHAINED together for greater impact.
42
+ Look for chains that go beyond obvious patterns:
43
+ - Can a low-severity finding enable a critical attack?
44
+ - Are there implicit trust relationships being exploited?
45
+ - Can multiple medium findings combine into a critical issue?
46
+
47
+ ### 2. Implicit Vulnerability Detection
48
+ Based on patterns in the findings, identify IMPLICIT vulnerabilities:
49
+ - If SQLi exists, input validation is likely weak everywhere
50
+ - If one IDOR exists, authorization logic may be flawed globally
51
+ - If secrets are exposed, key management is likely poor
52
+
53
+ ### 3. Real-World Exploitation Assessment
54
+ For each significant finding, assess:
55
+ - How easy would this be to exploit in practice?
56
+ - What would an attacker need (skills, tools, time)?
57
+ - What's the realistic business impact?
58
+
59
+ ### 4. Executive Risk Summary
60
+ Provide a business-focused summary suitable for executives.
61
+
62
+ ## Output Format (JSON)
63
+ ```json
64
+ {{
65
+ "attack_chains": [
66
+ {{
67
+ "name": "Descriptive chain name",
68
+ "steps": [
69
+ {{
70
+ "finding_title": "Name of finding",
71
+ "action": "What attacker does",
72
+ "outcome": "What attacker achieves"
73
+ }}
74
+ ],
75
+ "final_impact": "Ultimate impact if chain exploited",
76
+ "confidence": "high|medium|low",
77
+ "reasoning": "Why this chain works",
78
+ "cvss_amplification": 1.5
79
+ }}
80
+ ],
81
+ "implicit_vulnerabilities": [
82
+ {{
83
+ "type": "vulnerability_type",
84
+ "reasoning": "Why we suspect this exists",
85
+ "indicators": ["evidence1", "evidence2"],
86
+ "recommended_test": "How to verify"
87
+ }}
88
+ ],
89
+ "exploitation_assessments": [
90
+ {{
91
+ "finding_title": "Finding name",
92
+ "real_world_difficulty": "trivial|easy|moderate|difficult|theoretical",
93
+ "required_skills": "Description of needed skills",
94
+ "time_estimate": "Minutes/hours to exploit",
95
+ "impact_assessment": "Business impact description"
96
+ }}
97
+ ],
98
+ "executive_summary": "2-3 paragraph executive summary",
99
+ "top_risks": ["risk1", "risk2", "risk3"],
100
+ "immediate_actions": ["action1", "action2"]
101
+ }}
102
+ ```"""
103
+
104
+
105
+ @dataclass
106
+ class DiscoveredChain:
107
+ """An attack chain discovered by LLM analysis."""
108
+ name: str
109
+ steps: list[dict[str, str]]
110
+ final_impact: str
111
+ confidence: str
112
+ reasoning: str
113
+ cvss_amplification: float = 1.5
114
+
115
+ def to_dict(self) -> dict[str, Any]:
116
+ return {
117
+ "name": self.name,
118
+ "steps": self.steps,
119
+ "final_impact": self.final_impact,
120
+ "confidence": self.confidence,
121
+ "reasoning": self.reasoning,
122
+ "cvss_amplification": self.cvss_amplification,
123
+ }
124
+
125
+
126
+ @dataclass
127
+ class ImplicitVulnerability:
128
+ """A suspected vulnerability inferred from patterns."""
129
+ vuln_type: str
130
+ reasoning: str
131
+ indicators: list[str]
132
+ recommended_test: str
133
+
134
+ def to_dict(self) -> dict[str, Any]:
135
+ return {
136
+ "type": self.vuln_type,
137
+ "reasoning": self.reasoning,
138
+ "indicators": self.indicators,
139
+ "recommended_test": self.recommended_test,
140
+ }
141
+
142
+
143
+ @dataclass
144
+ class ExploitationAssessment:
145
+ """Real-world exploitation assessment for a finding."""
146
+ finding_title: str
147
+ real_world_difficulty: str
148
+ required_skills: str
149
+ time_estimate: str
150
+ impact_assessment: str
151
+
152
+ def to_dict(self) -> dict[str, Any]:
153
+ return {
154
+ "finding_title": self.finding_title,
155
+ "real_world_difficulty": self.real_world_difficulty,
156
+ "required_skills": self.required_skills,
157
+ "time_estimate": self.time_estimate,
158
+ "impact_assessment": self.impact_assessment,
159
+ }
160
+
161
+
162
+ @dataclass
163
+ class LLMAnalysisResult:
164
+ """Complete result of LLM vulnerability analysis."""
165
+ attack_chains: list[DiscoveredChain]
166
+ implicit_vulnerabilities: list[ImplicitVulnerability]
167
+ exploitation_assessments: list[ExploitationAssessment]
168
+ executive_summary: str
169
+ top_risks: list[str]
170
+ immediate_actions: list[str]
171
+ analyzed_at: datetime = field(default_factory=datetime.utcnow)
172
+ llm_model: str = ""
173
+
174
+ def to_dict(self) -> dict[str, Any]:
175
+ return {
176
+ "attack_chains": [c.to_dict() for c in self.attack_chains],
177
+ "implicit_vulnerabilities": [v.to_dict() for v in self.implicit_vulnerabilities],
178
+ "exploitation_assessments": [a.to_dict() for a in self.exploitation_assessments],
179
+ "executive_summary": self.executive_summary,
180
+ "top_risks": self.top_risks,
181
+ "immediate_actions": self.immediate_actions,
182
+ "analyzed_at": self.analyzed_at.isoformat(),
183
+ "llm_model": self.llm_model,
184
+ }
185
+
186
+ def get_high_confidence_chains(self) -> list[DiscoveredChain]:
187
+ """Get only high-confidence attack chains."""
188
+ return [c for c in self.attack_chains if c.confidence == "high"]
189
+
190
+ def get_critical_actions(self) -> list[str]:
191
+ """Get actions that require immediate attention."""
192
+ return self.immediate_actions[:5]
193
+
194
+
195
+ class LLMVulnerabilityAnalyzer:
196
+ """
197
+ LLM-powered deep vulnerability analysis.
198
+
199
+ Goes beyond rule-based chaining to discover novel attack paths
200
+ and assess real-world exploitability.
201
+
202
+ Example:
203
+ analyzer = LLMVulnerabilityAnalyzer()
204
+ result = await analyzer.analyze(
205
+ findings=findings,
206
+ target="https://example.com",
207
+ tech_stack=["WordPress", "PHP", "MySQL"],
208
+ business_context="E-commerce platform handling payments"
209
+ )
210
+
211
+ for chain in result.get_high_confidence_chains():
212
+ print(f"Attack Chain: {chain.name}")
213
+ print(f"Impact: {chain.final_impact}")
214
+ """
215
+
216
+ def __init__(
217
+ self,
218
+ llm_provider: str = "anthropic",
219
+ llm_model: str = "claude-3-5-sonnet-20241022",
220
+ ):
221
+ self.llm_provider = llm_provider
222
+ self.llm_model = llm_model
223
+ self._llm = None
224
+
225
+ async def _get_llm(self):
226
+ """Get or create LLM client."""
227
+ if self._llm is None:
228
+ try:
229
+ import litellm
230
+ self._llm = litellm
231
+ except ImportError:
232
+ logger.warning("litellm not installed")
233
+ return None
234
+ return self._llm
235
+
236
+ async def analyze(
237
+ self,
238
+ findings: list[Finding],
239
+ target: str = "",
240
+ tech_stack: list[str] = None,
241
+ business_context: str = "",
242
+ ) -> LLMAnalysisResult:
243
+ """
244
+ Perform deep LLM analysis of findings.
245
+
246
+ Args:
247
+ findings: List of vulnerability findings to analyze
248
+ target: Target URL or domain
249
+ tech_stack: Detected technologies
250
+ business_context: Business context for impact assessment
251
+
252
+ Returns:
253
+ LLMAnalysisResult with discovered chains and assessments
254
+ """
255
+ if not findings:
256
+ return self._empty_result()
257
+
258
+ llm = await self._get_llm()
259
+ if llm is None or not self._has_api_key():
260
+ logger.warning("LLM not available, returning basic analysis")
261
+ return self._basic_analysis(findings)
262
+
263
+ # Prepare findings for LLM (limit to top 30 to fit context)
264
+ sorted_findings = sorted(findings, key=lambda f: f.severity, reverse=True)
265
+ top_findings = sorted_findings[:30]
266
+
267
+ findings_json = json.dumps(
268
+ [f.to_dict() for f in top_findings],
269
+ indent=2,
270
+ default=str
271
+ )
272
+
273
+ prompt = ANALYSIS_PROMPT.format(
274
+ findings_json=findings_json,
275
+ target=target,
276
+ tech_stack=", ".join(tech_stack) if tech_stack else "Unknown",
277
+ business_context=business_context or "General web application",
278
+ )
279
+
280
+ try:
281
+ response = await self._call_llm(prompt)
282
+ result = self._parse_response(response)
283
+ result.llm_model = self.llm_model
284
+ return result
285
+ except Exception as e:
286
+ logger.error(f"LLM analysis failed: {e}")
287
+ return self._basic_analysis(findings)
288
+
289
+ async def analyze_single_finding(
290
+ self,
291
+ finding: Finding,
292
+ context: str = "",
293
+ ) -> ExploitationAssessment:
294
+ """
295
+ Analyze a single finding for real-world exploitability.
296
+
297
+ Args:
298
+ finding: The finding to analyze
299
+ context: Additional context about the target
300
+
301
+ Returns:
302
+ ExploitationAssessment for the finding
303
+ """
304
+ prompt = f"""Analyze this vulnerability for real-world exploitability:
305
+
306
+ Finding: {finding.title}
307
+ Type: {finding.vuln_type.value}
308
+ Severity: {finding.severity.value}
309
+ URL: {finding.url}
310
+ Evidence: {finding.evidence[:500] if finding.evidence else 'None'}
311
+ Context: {context}
312
+
313
+ Provide a JSON response:
314
+ {{
315
+ "real_world_difficulty": "trivial|easy|moderate|difficult|theoretical",
316
+ "required_skills": "Description",
317
+ "time_estimate": "Time to exploit",
318
+ "impact_assessment": "Business impact"
319
+ }}"""
320
+
321
+ try:
322
+ response = await self._call_llm(prompt)
323
+ data = self._extract_json(response)
324
+ return ExploitationAssessment(
325
+ finding_title=finding.title,
326
+ real_world_difficulty=data.get("real_world_difficulty", "moderate"),
327
+ required_skills=data.get("required_skills", "Security knowledge"),
328
+ time_estimate=data.get("time_estimate", "Unknown"),
329
+ impact_assessment=data.get("impact_assessment", finding.description),
330
+ )
331
+ except Exception as e:
332
+ logger.warning(f"Single finding analysis failed: {e}")
333
+ return self._default_assessment(finding)
334
+
335
+ async def discover_chains(
336
+ self,
337
+ findings: list[Finding],
338
+ ) -> list[DiscoveredChain]:
339
+ """
340
+ Focus specifically on discovering attack chains.
341
+
342
+ This is useful when you just want chain discovery without
343
+ full analysis.
344
+
345
+ Args:
346
+ findings: Findings to analyze for chains
347
+
348
+ Returns:
349
+ List of discovered attack chains
350
+ """
351
+ result = await self.analyze(findings)
352
+ return result.attack_chains
353
+
354
+ async def _call_llm(self, prompt: str) -> str:
355
+ """Call LLM and get response."""
356
+ llm = await self._get_llm()
357
+
358
+ model_str = f"{self.llm_provider}/{self.llm_model}"
359
+ if self.llm_provider == "anthropic" and not self.llm_model.startswith("anthropic/"):
360
+ model_str = f"anthropic/{self.llm_model}"
361
+ elif self.llm_provider == "openai" and not self.llm_model.startswith("openai/"):
362
+ model_str = f"openai/{self.llm_model}"
363
+
364
+ response = await llm.acompletion(
365
+ model=model_str,
366
+ messages=[{"role": "user", "content": prompt}],
367
+ max_tokens=4000,
368
+ temperature=0.3,
369
+ )
370
+
371
+ return response.choices[0].message.content
372
+
373
+ def _parse_response(self, response: str) -> LLMAnalysisResult:
374
+ """Parse LLM response into structured result."""
375
+ data = self._extract_json(response)
376
+
377
+ # Parse attack chains
378
+ chains = []
379
+ for chain_data in data.get("attack_chains", []):
380
+ chains.append(DiscoveredChain(
381
+ name=chain_data.get("name", "Unknown Chain"),
382
+ steps=chain_data.get("steps", []),
383
+ final_impact=chain_data.get("final_impact", ""),
384
+ confidence=chain_data.get("confidence", "medium"),
385
+ reasoning=chain_data.get("reasoning", ""),
386
+ cvss_amplification=chain_data.get("cvss_amplification", 1.5),
387
+ ))
388
+
389
+ # Parse implicit vulnerabilities
390
+ implicit = []
391
+ for vuln_data in data.get("implicit_vulnerabilities", []):
392
+ implicit.append(ImplicitVulnerability(
393
+ vuln_type=vuln_data.get("type", "unknown"),
394
+ reasoning=vuln_data.get("reasoning", ""),
395
+ indicators=vuln_data.get("indicators", []),
396
+ recommended_test=vuln_data.get("recommended_test", ""),
397
+ ))
398
+
399
+ # Parse exploitation assessments
400
+ assessments = []
401
+ for assess_data in data.get("exploitation_assessments", []):
402
+ assessments.append(ExploitationAssessment(
403
+ finding_title=assess_data.get("finding_title", ""),
404
+ real_world_difficulty=assess_data.get("real_world_difficulty", "moderate"),
405
+ required_skills=assess_data.get("required_skills", ""),
406
+ time_estimate=assess_data.get("time_estimate", ""),
407
+ impact_assessment=assess_data.get("impact_assessment", ""),
408
+ ))
409
+
410
+ return LLMAnalysisResult(
411
+ attack_chains=chains,
412
+ implicit_vulnerabilities=implicit,
413
+ exploitation_assessments=assessments,
414
+ executive_summary=data.get("executive_summary", "Analysis complete."),
415
+ top_risks=data.get("top_risks", []),
416
+ immediate_actions=data.get("immediate_actions", []),
417
+ )
418
+
419
+ def _extract_json(self, response: str) -> dict:
420
+ """Extract JSON from LLM response."""
421
+ # Try to find JSON block
422
+ json_start = response.find("{")
423
+ json_end = response.rfind("}") + 1
424
+
425
+ if json_start >= 0 and json_end > json_start:
426
+ json_str = response[json_start:json_end]
427
+ return json.loads(json_str)
428
+
429
+ # Try to find code block
430
+ if "```json" in response:
431
+ start = response.find("```json") + 7
432
+ end = response.find("```", start)
433
+ if end > start:
434
+ return json.loads(response[start:end].strip())
435
+
436
+ raise ValueError("No valid JSON found in response")
437
+
438
+ def _empty_result(self) -> LLMAnalysisResult:
439
+ """Return empty result for no findings."""
440
+ return LLMAnalysisResult(
441
+ attack_chains=[],
442
+ implicit_vulnerabilities=[],
443
+ exploitation_assessments=[],
444
+ executive_summary="No findings to analyze.",
445
+ top_risks=[],
446
+ immediate_actions=[],
447
+ )
448
+
449
+ def _basic_analysis(self, findings: list[Finding]) -> LLMAnalysisResult:
450
+ """Provide basic analysis without LLM."""
451
+ # Count by severity for summary
452
+ critical = sum(1 for f in findings if f.severity == Severity.CRITICAL)
453
+ high = sum(1 for f in findings if f.severity == Severity.HIGH)
454
+
455
+ summary = f"Analysis identified {len(findings)} findings: {critical} critical, {high} high severity."
456
+
457
+ # Basic risk identification
458
+ risks = []
459
+ if critical > 0:
460
+ risks.append(f"{critical} critical vulnerabilities require immediate remediation")
461
+ if high > 0:
462
+ risks.append(f"{high} high-severity issues pose significant risk")
463
+
464
+ # Basic actions
465
+ actions = []
466
+ for f in sorted(findings, key=lambda x: x.severity, reverse=True)[:3]:
467
+ actions.append(f"Address {f.vuln_type.value}: {f.title}")
468
+
469
+ return LLMAnalysisResult(
470
+ attack_chains=[],
471
+ implicit_vulnerabilities=[],
472
+ exploitation_assessments=[],
473
+ executive_summary=summary,
474
+ top_risks=risks[:5],
475
+ immediate_actions=actions[:5],
476
+ )
477
+
478
+ def _default_assessment(self, finding: Finding) -> ExploitationAssessment:
479
+ """Create default assessment for a finding."""
480
+ difficulty_map = {
481
+ Severity.CRITICAL: "easy",
482
+ Severity.HIGH: "moderate",
483
+ Severity.MEDIUM: "moderate",
484
+ Severity.LOW: "difficult",
485
+ Severity.INFO: "theoretical",
486
+ }
487
+
488
+ return ExploitationAssessment(
489
+ finding_title=finding.title,
490
+ real_world_difficulty=difficulty_map.get(finding.severity, "moderate"),
491
+ required_skills="Security testing knowledge",
492
+ time_estimate="Varies",
493
+ impact_assessment=finding.description or f"{finding.severity.value} impact",
494
+ )
495
+
496
+ def _has_api_key(self) -> bool:
497
+ """Check if API key is available."""
498
+ if self.llm_provider == "anthropic":
499
+ return bool(os.getenv("ANTHROPIC_API_KEY"))
500
+ if self.llm_provider == "openai":
501
+ return bool(os.getenv("OPENAI_API_KEY"))
502
+ return False